Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1433 lines
53 KiB

  1. #include "wt.h"
  2. #include "wtproto.h"
  3. #include "workerinc.h"
  4. //----------------------------------------------------------------------------------//
  5. // WorkerFunction_ProcessClientNotifyWTEvent //
  6. // the client has locks on wte_CS, so that no one can add or delete //
  7. // if you need to add timers, you have to take lock on wte_CSTimer //
  8. //----------------------------------------------------------------------------------//
  9. VOID
  10. WorkerFunction_ProcessClientNotifyWTEvent (
  11. IN PVOID pContext
  12. )
  13. {
  14. PWAIT_THREAD_ENTRY pwte;
  15. BOOL bLockTimer;
  16. pwte = (PWAIT_THREAD_ENTRY) pContext;
  17. TRACE0(ENTER, "Entering WorkerFunction_ProcessClientNotifyWTEvent:");
  18. switch (pwte->wte_ChangeType) {
  19. case CHANGE_TYPE_ADD :
  20. RegisterClientEventsTimers(pwte);
  21. break;
  22. case CHANGE_TYPE_DELETE :
  23. DeRegisterClientEventsTimers(pwte);
  24. break;
  25. case CHANGE_TYPE_BIND_FUNCTION_ADD :
  26. RegisterClientEventBinding(pwte);
  27. break;
  28. case CHANGE_TYPE_BIND_FUNCTION_DELETE :
  29. DeRegisterClientEventBinding(pwte);
  30. break;
  31. }
  32. SET_EVENT(pwte->wte_WTNotifyClientEvent, "wte_WTNotifyClientEvent",
  33. "WorkerFunction_ProcessClientNotifyWTEvent");
  34. TRACE0(LEAVE, "Leaving WorkerFunction_ProcessClientNotifyWTEvent:");
  35. return;
  36. } //end WorkerFunction_ProcessClientNotifyWTEvent
  37. //----------------------------------------------------------------------------------//
  38. // WorkerFunction_ProcessWorkQueueTimer //
  39. //----------------------------------------------------------------------------------//
  40. VOID
  41. WorkerFunction_ProcessWorkQueueTimer (
  42. IN PVOID pContext
  43. )
  44. {
  45. TRACE0(ENTER, "Entering WorkerFunction_ProcessWorkQueueTimer:");
  46. // Work queue has not been served within specified
  47. // timeout
  48. while (1) {
  49. // Make a local copy of the count
  50. LONG count = ThreadCount;
  51. // Make sure we havn't exceded the limit
  52. if (count>=MAX_WORKER_THREADS)
  53. break;
  54. else {
  55. // Try to increment the value
  56. // use another local variable
  57. // because of MIPS optimizer bug
  58. LONG newCount = count+1;
  59. if (InterlockedCompareExchange (&ThreadCount,
  60. newCount, count)==count) {
  61. HANDLE hThread;
  62. DWORD tid;
  63. // Create new thread if increment succeded
  64. hThread = CreateThread (NULL, 0, WorkerThread, NULL, 0, &tid);
  65. if (hThread!=NULL) {
  66. CloseHandle (hThread);
  67. }
  68. else // Restore the value if thread creation
  69. // failed
  70. InterlockedDecrement (&ThreadCount);
  71. break;
  72. }
  73. // else repeat the loop if ThreadCount was modified
  74. // while we were checking
  75. }
  76. }
  77. TRACE0(LEAVE, "Leaving WorkerFunction_ProcessWorkQueueTimer:");
  78. return;
  79. } //end WorkerFunction_ProcessWorkQueueTimer
  80. //----------------------------------------------------------------------------------//
  81. // WorkerFunction_ProcessAlertableThreadSemaphore //
  82. //----------------------------------------------------------------------------------//
  83. VOID
  84. WorkerFunction_ProcessAlertableThreadSemaphore (
  85. IN PVOID pContext
  86. )
  87. {
  88. WorkItem *workitem;
  89. TRACE0(ENTER, "Entering WorkerFunction_ProcessAlertableThreadSemaphore:");
  90. EnterCriticalSection(&AlertableWorkQueueLock);
  91. ASSERT (!IsListEmpty (&AlertableWorkQueue));
  92. workitem = (WorkItem *) RemoveHeadList (&AlertableWorkQueue) ;
  93. LeaveCriticalSection(&AlertableWorkQueueLock);
  94. (workitem->WI_Function) (workitem->WI_Context);
  95. HeapFree (AlertableWorkerHeap, 0, workitem);
  96. TRACE0(LEAVE, "Leaving WorkerFunction_ProcessAlertableThreadSemaphore:");
  97. return;
  98. }
  99. //++-------------------------------------------------------------------------------*//
  100. // WorkerFunction_ProcessWaitableTimer //
  101. // Process event: waitable timer fired //
  102. // takes lock on wte_CSTimer and releases it in the end //
  103. //----------------------------------------------------------------------------------//
  104. VOID
  105. WorkerFunction_ProcessWaitableTimer(
  106. IN PVOID pContext
  107. )
  108. {
  109. PWAIT_THREAD_ENTRY pwte;
  110. LONGLONG liCurrentTime;
  111. PLIST_ENTRY ple, pHead, pleCurrent;
  112. PWT_TIMER_ENTRY pte;
  113. BOOL bActiveTimers;
  114. TRACE0(ENTER, "Entering WorkerFunction_ProcessWaitableTimer:");
  115. pwte = (PWAIT_THREAD_ENTRY) pContext;
  116. // get lock on server threads timer
  117. ENTER_CRITICAL_SECTION(&pwte->wte_CSTimer, "wte_CSTimer", "WorkerFunction_ProcessWaitableTimer");
  118. NtQuerySystemTime((LARGE_INTEGER*) &liCurrentTime);
  119. // ordered in increasing time, with inactive timers at the end
  120. pHead = &pwte->wteL_ClientTimerEntries;
  121. for (ple=pHead->Flink; ple!=pHead; ) {
  122. pte = CONTAINING_RECORD(ple, WT_TIMER_ENTRY, te_ServerLinks);
  123. if (pte->te_Status == TIMER_INACTIVE) // inactive timers at end of list
  124. break;
  125. if (IS_TIMER_INFINITE(pte->te_Timeout)) { //should have been inactive
  126. ple = ple->Flink;
  127. continue;
  128. }
  129. if (pte->te_Timeout<=liCurrentTime) {
  130. //
  131. // set timer status to inactive and insert at end of timer queue
  132. //
  133. pte->te_Status = TIMER_INACTIVE;
  134. SET_TIMER_INFINITE(pte->te_Timeout);
  135. pleCurrent = ple;
  136. ple = ple->Flink;
  137. RemoveEntryList(pleCurrent);
  138. InsertTailList(pHead, pleCurrent);
  139. // run the function in current thread or dispatch to worker thread
  140. //
  141. if (pte->te_RunInServer) {
  142. (pte->te_Function)(pte->te_Context);
  143. }
  144. else {
  145. QueueWorkItem( pte->te_Function, pte->te_Context, FALSE ); // do not run in alertable thread
  146. }
  147. }
  148. else {
  149. break;
  150. }
  151. }
  152. //
  153. // search for active timers with timeout which is not infinite
  154. //
  155. if (IsListEmpty(pHead))
  156. bActiveTimers = FALSE;
  157. else {
  158. ple = pHead->Flink;
  159. pte = CONTAINING_RECORD(ple, WT_TIMER_ENTRY, te_ServerLinks);
  160. bActiveTimers = (pte->te_Status==TIMER_INACTIVE) ? FALSE : TRUE;
  161. }
  162. //
  163. // if active timers present, then set waitableTimer
  164. //
  165. if (bActiveTimers) {
  166. // set next timeout value for the wait server
  167. pwte->wte_Timeout = pte->te_Timeout;
  168. TRACE2(TIMER, "SetWaitableTimer set to <%lu:%lu> after being fired",
  169. TIMER_HIGH(pte->te_Timeout), TIMER_LOW(pte->te_Timeout));
  170. SetWaitableTimer(pwte->wte_Timer, (LARGE_INTEGER*)&pte->te_Timeout, 0, NULL, NULL, FALSE);
  171. }
  172. // no active timer in queue. do not set the waitable timer
  173. else {
  174. SET_TIMER_INFINITE(pwte->wte_Timeout);
  175. }
  176. #if DBG2
  177. DebugPrintWaitWorkerThreads(DEBUGPRINT_FILTER_EVENTS);
  178. #endif
  179. LEAVE_CRITICAL_SECTION(&pwte->wte_CSTimer, "wte_CSTimer", "WorkerFunction_ProcessWaitableTimer");
  180. TRACE0(LEAVE, "Leaving WorkerFunction_ProcessWaitableTimer:");
  181. return;
  182. } //end WorkerFunction_ProcessWaitableTimer
  183. //---------------------------------------------------------------------------------*//
  184. // CreateServerEventsAndTimer //
  185. // Create the events for a server and the timer(called by server only) //
  186. // assumes lock on server and server timer structure //
  187. // THIS FUNCTION SHOULD NOT HAVE ANY CALLS TO API FUNCTIONS //
  188. //----------------------------------------------------------------------------------//
  189. DWORD
  190. CreateServerEventsAndTimer (
  191. IN PWAIT_THREAD_ENTRY pwte
  192. )
  193. {
  194. PWT_EVENT_ENTRY peeWaitableTimer, peeClientNotifyWTEvent,
  195. peeAlertableThreadSemaphore, peeWorkQueueTimer;
  196. // waitable timer (set to infinity time)
  197. peeWaitableTimer = CreateWaitEvent(
  198. pwte->wte_Timer,
  199. NULL, FALSE, FALSE, NULL,
  200. TRUE, // highPriority
  201. (WORKERFUNCTION) WorkerFunction_ProcessWaitableTimer,
  202. (PVOID)pwte, // context
  203. 0, // context size=0, as just a pointer value is being passed
  204. TRUE // run in server context
  205. );
  206. if (!peeWaitableTimer)
  207. return ERROR_NOT_ENOUGH_MEMORY;
  208. peeWaitableTimer->ee_EventId = 1;
  209. RegisterClientEventLocal(peeWaitableTimer, pwte);
  210. // ClientNotifyWTEvent
  211. peeClientNotifyWTEvent = CreateWaitEvent(
  212. pwte->wte_ClientNotifyWTEvent,
  213. NULL, FALSE, FALSE, NULL,
  214. TRUE, // highPriority
  215. (WORKERFUNCTION) WorkerFunction_ProcessClientNotifyWTEvent,
  216. (PVOID)pwte, // context
  217. 0, // context size=0, as just a pointer value is being passed
  218. TRUE // run in server context
  219. );
  220. if (!peeClientNotifyWTEvent )
  221. return ERROR_NOT_ENOUGH_MEMORY;
  222. peeClientNotifyWTEvent->ee_EventId = 2;
  223. RegisterClientEventLocal(peeClientNotifyWTEvent, pwte);
  224. // AlertableThreadSemaphore
  225. peeAlertableThreadSemaphore = CreateWaitEvent(
  226. AlertableThreadSemaphore,
  227. NULL, FALSE, FALSE, NULL,
  228. FALSE, // Priority=low
  229. (WORKERFUNCTION) WorkerFunction_ProcessAlertableThreadSemaphore,
  230. NULL, // context
  231. 0, // context size=0, as just a pointer value is being passed
  232. TRUE // run in server context
  233. );
  234. peeAlertableThreadSemaphore->ee_EventId = 3;
  235. RegisterClientEventLocal(peeAlertableThreadSemaphore, pwte);
  236. // WorkQueueTimer
  237. peeWorkQueueTimer = CreateWaitEvent(
  238. WorkQueueTimer,
  239. NULL, FALSE, FALSE, NULL,
  240. FALSE, // Priority=low
  241. (WORKERFUNCTION) WorkerFunction_ProcessWorkQueueTimer,
  242. NULL, // context
  243. 0, // context size=0, as just a pointer value is being passed
  244. TRUE // run in server context
  245. );
  246. peeWorkQueueTimer->ee_EventId = 4;
  247. RegisterClientEventLocal(peeWorkQueueTimer, pwte);
  248. return NO_ERROR;
  249. } //end CreateServerEventsAndTimer
  250. //---------------------------------------------------------------------------------*//
  251. // InitializeWaitGlobal //
  252. // initialize the global data structure for all wait threads //
  253. //----------------------------------------------------------------------------------//
  254. DWORD
  255. InitializeWaitGlobal(
  256. )
  257. {
  258. BOOL bErr;
  259. DWORD dwErr = NO_ERROR;
  260. ZeroMemory(&WTG, sizeof(WTG));
  261. WTG.g_Initialized = 0x12345678;
  262. //
  263. // initialize tracing and logging
  264. //
  265. WTG.g_TraceId = TraceRegister("WAIT_THREAD");
  266. //todo:set the logging level
  267. WTG.g_LogLevel = WT_LOGGING_ERROR;
  268. WTG.g_LogHandle = RouterLogRegister("WAIT_THREAD");
  269. TRACE0(ENTER, "Entering InitializeWaitGlobal()");
  270. //
  271. // initialize global structure
  272. //
  273. bErr = FALSE;
  274. do { // error breakout loop
  275. //
  276. // create a private heap for Wait-Thread
  277. //
  278. WTG.g_Heap = AlertableWorkerHeap; // created in worker.c
  279. if (WTG.g_Heap==NULL)
  280. WTG.g_Heap = HeapCreate(0, 0, 0);
  281. if (WTG.g_Heap == NULL) {
  282. dwErr = GetLastError();
  283. TRACE1(
  284. ANY, "error %d creating Wait-Thread global heap", dwErr
  285. );
  286. LOGERR0(HEAP_CREATE_FAILED, dwErr);
  287. bErr = FALSE;
  288. break;
  289. }
  290. // initialize list for wait thread entries
  291. //
  292. InitializeListHead(&WTG.gL_WaitThreadEntries);
  293. // initialize critical section
  294. //
  295. try {
  296. InitializeCriticalSection(&WTG.g_CS);
  297. }
  298. except (EXCEPTION_EXECUTE_HANDLER) {
  299. dwErr = GetExceptionCode();
  300. TRACE1(
  301. ANY, "exception %d initializing global critical section",
  302. dwErr
  303. );
  304. LOGERR0(INIT_CRITSEC_FAILED, dwErr);
  305. bErr = TRUE;
  306. break;
  307. }
  308. } while (FALSE);
  309. TRACE1(LEAVE, "leaving InitializeWaitGlobal: %d", dwErr);
  310. if (bErr)
  311. return dwErr;
  312. else
  313. return NO_ERROR;
  314. } //end InitializeWaitGlobal
  315. //---------------------------------------------------------------------------------*//
  316. // DeInitializeWaitGlobal //
  317. //deinitializes the global structure for wait-thread //
  318. //todo: free the server entries and the event/timers etc associated with them //
  319. //----------------------------------------------------------------------------------//
  320. DWORD
  321. DeInitializeWaitGlobal(
  322. )
  323. {
  324. PLIST_ENTRY ple, pHead;
  325. PWAIT_THREAD_ENTRY pwte;
  326. ENTER_CRITICAL_SECTION(&WTG.g_CS, "g_CS", "DeInitializeWaitGlobal");
  327. if (WTG.g_Initialized==0) {
  328. LEAVE_CRITICAL_SECTION(&WTG.g_CS, "g_CS", "DeInitializeWaitGlobal");
  329. TRACE0(LEAVE, "leaving DeInitializeWaitGlobal:Pending");
  330. return ERROR_CAN_NOT_COMPLETE;
  331. }
  332. else
  333. WTG.g_Initialized = 0;
  334. //
  335. // if waitThreadEntries exist, then for each server entry mark each event/binding
  336. // as deleted and return pending
  337. //
  338. if (!IsListEmpty(&WTG.gL_WaitThreadEntries)) {
  339. pHead = &WTG.gL_WaitThreadEntries;
  340. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  341. pwte = CONTAINING_RECORD(ple, WAIT_THREAD_ENTRY, wte_Links);
  342. ENTER_CRITICAL_SECTION(&pwte->wte_CS, "deleting wte_CS", "DeInitializeWaitGlobal");
  343. pwte->wte_Status = WT_STATUS_DELETED;
  344. }
  345. //todo should I also mark each event and timer as deleted
  346. TRACE0(LEAVE, "leaving DeInitializeWaitGlobal:Pending");
  347. return ERROR_CAN_NOT_COMPLETE;
  348. }
  349. DeInitializeWaitGlobalComplete();
  350. return NO_ERROR;
  351. } //end DeInitializeWaitGlobal
  352. //----------------------DeInitializeWaitGlobalComplete-----------------------------//
  353. DWORD
  354. DeInitializeWaitGlobalComplete (
  355. )
  356. {
  357. TRACE0(LEAVE, "leaving DeInitializeWaitGlobal");
  358. // for each server entry mark each event/binding as deleted
  359. // and return pending
  360. TraceDeregister(WTG.g_TraceId);
  361. RouterLogDeregister(WTG.g_LogHandle);
  362. // delete critical section
  363. try{
  364. DeleteCriticalSection(&WTG.g_CS);
  365. }
  366. except (EXCEPTION_EXECUTE_HANDLER) {
  367. }
  368. // destroy heap
  369. /*if (WTG.g_Heap != NULL) {
  370. HeapDestroy(WTG.g_Heap);
  371. }*/
  372. return NO_ERROR;
  373. } //end DeInitializeWaitGlobal
  374. //++-------------------------------------------------------------------------------*//
  375. // InsertWaitThreadEntry //
  376. // insert the new wait server thread into a list of increasing ServerIds //
  377. // initializes the serverId //
  378. // assumes: it has lock on WTG.g_cs, and pwte->wte_CS, and pwte->wte_CSTimer //
  379. // NO CALLS TO APIS SHOULD BE MADE HERE //
  380. //----------------------------------------------------------------------------------//
  381. DWORD
  382. InsertWaitThreadEntry (
  383. IN PWAIT_THREAD_ENTRY pwteInsert
  384. )
  385. {
  386. PLIST_ENTRY ple, pHead;
  387. PWAIT_THREAD_ENTRY pwte;
  388. DWORD dwServerId;
  389. //
  390. // find the lowest unallocated SeverId and insert the new server in the ordered list
  391. //
  392. dwServerId = 1;
  393. pHead = &WTG.gL_WaitThreadEntries;
  394. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink,dwServerId++) {
  395. pwte = CONTAINING_RECORD(ple, WAIT_THREAD_ENTRY, wte_Links);
  396. if (dwServerId==pwte->wte_ServerId) {
  397. continue;
  398. }
  399. else
  400. break;
  401. }
  402. // insert in list
  403. if (dwServerId==1) { // not required. but kept for easy understanding
  404. InsertHeadList(&WTG.gL_WaitThreadEntries, &pwteInsert->wte_Links);
  405. }
  406. else {
  407. InsertTailList(ple, &pwteInsert->wte_Links);
  408. }
  409. // set serverId
  410. pwteInsert->wte_ServerId = dwServerId;
  411. pwteInsert->wte_Status = WT_STATUS_REGISTERED;
  412. return NO_ERROR;
  413. } //end InsertWaitThreadEntry
  414. //---------------------------------------------------------------------------------*//
  415. // RemoveWaitThreadEntry //
  416. // removes a wait server thread from the list of servers //
  417. // assumes: it has lock on WTG.g_cs and wte_CS //
  418. //----------------------------------------------------------------------------------//
  419. DWORD
  420. DeleteWaitThreadEntry (
  421. IN PWAIT_THREAD_ENTRY pwte
  422. )
  423. {
  424. // set status to deleted
  425. pwte->wte_Status = WT_STATUS_DELETED;
  426. // if RefCount == 0, then remove it from the list and free it
  427. if (pwte->wte_RefCount==0) {
  428. // free the wait thread entry
  429. RemoveEntryList(&pwte->wte_Links);
  430. FreeWaitThreadEntry(pwte);
  431. // deinitialize global structure if it is also marked for delete and its
  432. // WaitThreadEntry list is empty
  433. if ((WTG.g_Initialized==WT_STATUS_DELETED)
  434. &&(IsListEmpty(&WTG.gL_WaitThreadEntries)))
  435. {
  436. DeInitializeWaitGlobalComplete();
  437. }
  438. }
  439. return NO_ERROR;
  440. }
  441. //---------------------------------------------------------------------------------*//
  442. // CreateWaitThreadEntry //
  443. // creates a wait thread entry and initializes it //
  444. // no locks required //
  445. //----------------------------------------------------------------------------------//
  446. DWORD
  447. CreateWaitThreadEntry (
  448. IN DWORD dwThreadId,
  449. OUT PWAIT_THREAD_ENTRY *ppwte
  450. )
  451. {
  452. PWAIT_THREAD_ENTRY pwte;
  453. DWORD dwErr = NO_ERROR;
  454. BOOL bErr = TRUE;
  455. TRACE0(ENTER, "Entering CreateWaitThreadEntry");
  456. //
  457. // allocate wait-thread-entry entry
  458. //
  459. *ppwte = pwte = WT_MALLOC(sizeof(WAIT_THREAD_ENTRY));
  460. if (pwte == NULL) {
  461. dwErr = GetLastError();
  462. TRACE2(
  463. ANY, "error %d allocating %d bytes for wait-thread-entry",
  464. dwErr, sizeof(WAIT_THREAD_ENTRY)
  465. );
  466. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  467. return dwErr;
  468. }
  469. ZeroMemory(pwte, sizeof(WAIT_THREAD_ENTRY));
  470. //
  471. // initialize global structure
  472. //
  473. do { // error breakout loop
  474. // critical section
  475. try {
  476. InitializeCriticalSection(&pwte->wte_CS);
  477. }
  478. except (EXCEPTION_EXECUTE_HANDLER) {
  479. dwErr = GetExceptionCode();
  480. TRACE1(
  481. ANY, "exception %d initializing global critical section",
  482. dwErr
  483. );
  484. LOGERR0(INIT_CRITSEC_FAILED, dwErr);
  485. break;
  486. }
  487. // current clients
  488. //server id is set when it is inserted into global list
  489. pwte->wte_ThreadId = dwThreadId; //ServerId is assigned during insertion of wte
  490. pwte->wte_NumClients = 0;
  491. // list for events/timers
  492. InitializeListHead(&pwte->wteL_ClientEventEntries);
  493. InitializeListHead(&pwte->wteL_ClientTimerEntries);
  494. // create waitable timer
  495. pwte->wte_Timer = CreateWaitableTimer(NULL, FALSE, NULL);
  496. if (pwte->wte_Timer == NULL) {
  497. dwErr = GetLastError();
  498. TRACE1(
  499. ANY, "error creating waitable timer",
  500. dwErr
  501. );
  502. LOGERR0(CREATE_WAITABLE_TIMER_FAILED, dwErr);
  503. break;
  504. }
  505. SET_TIMER_INFINITE(pwte->wte_Timeout); //set timeout to infinity
  506. // critical section for timers
  507. try {
  508. InitializeCriticalSection(&pwte->wte_CSTimer);
  509. }
  510. except (EXCEPTION_EXECUTE_HANDLER) {
  511. dwErr = GetExceptionCode();
  512. TRACE1(
  513. ANY, "exception %d initializing critical section for timer",
  514. dwErr
  515. );
  516. LOGERR0(INIT_CRITSEC_FAILED, dwErr);
  517. break;
  518. }
  519. // array for WaitForMultipleObjects
  520. pwte->wte_LowIndex = 0;
  521. pwte->wte_NumTotalEvents = 0;
  522. pwte->wte_NumActiveEvents = 0;
  523. pwte->wte_NumHighPriorityEvents = 0;
  524. pwte->wte_NumActiveHighPriorityEvents = 0;
  525. //
  526. // adding/deleting events/timers
  527. //
  528. // create event: Client notifies WT: wake up WT to add/delete events/timers
  529. pwte->wte_ClientNotifyWTEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  530. if (pwte->wte_ClientNotifyWTEvent == NULL) {
  531. dwErr = GetLastError();
  532. TRACE1(START, "error %d creating event Client-notify-WT", dwErr);
  533. LOGERR0(CREATE_EVENT_FAILED, dwErr);
  534. break;
  535. }
  536. // create event: WT notifies Client: the work requested has been done
  537. pwte->wte_WTNotifyClientEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  538. if (pwte->wte_WTNotifyClientEvent == NULL) {
  539. dwErr = GetLastError();
  540. TRACE1(START, "error:%d creating event WT-notify-Client", dwErr);
  541. LOGERR0(CREATE_EVENT_FAILED, dwErr);
  542. break;
  543. }
  544. // variables used to add/delete events/timers
  545. pwte->wte_ChangeType = CHANGE_TYPE_NONE;
  546. pwte->wte_Status = 0;
  547. pwte->wte_RefCount = 0;
  548. pwte->wtePL_EventsToChange = NULL;
  549. pwte->wtePL_TimersToChange = NULL;
  550. bErr = FALSE;
  551. } while (FALSE);
  552. TRACE1(LEAVE, "Leaving CreateWaitThreadEntry: %d", dwErr);
  553. if (bErr) {
  554. FreeWaitThreadEntry(pwte);
  555. return dwErr;
  556. }
  557. else
  558. return NO_ERROR;
  559. }//end CreateWaitThreadEntry
  560. //---------------------------------------------------------------------------------*//
  561. // FreeWaitThreadEntry //
  562. //----------------------------------------------------------------------------------//
  563. DWORD
  564. FreeWaitThreadEntry (
  565. IN PWAIT_THREAD_ENTRY pwte
  566. )
  567. {
  568. DWORD dwErr = NO_ERROR;
  569. TRACE0(ENTER, "Entering FreeWaitThreadEntry");
  570. DeleteCriticalSection(&pwte->wte_CS);
  571. // delete waitable timer
  572. if (pwte->wte_Timer!=NULL)
  573. CloseHandle(pwte->wte_Timer);
  574. DeleteCriticalSection(&pwte->wte_CSTimer);
  575. // delete event: Client notifies WT
  576. if (pwte->wte_ClientNotifyWTEvent!=NULL)
  577. CloseHandle(&pwte->wte_ClientNotifyWTEvent);
  578. // delete event: WT notifies Client
  579. if (pwte->wte_WTNotifyClientEvent!=NULL)
  580. CloseHandle(pwte->wte_WTNotifyClientEvent);
  581. //
  582. // free wait-thread-entry record
  583. //
  584. WT_FREE(pwte);
  585. // deinitialize global structure if it is also marked for delete and its
  586. // WaitThreadEntry list is empty
  587. if ((WTG.g_Initialized==WT_STATUS_DELETED)
  588. &&(IsListEmpty(&WTG.gL_WaitThreadEntries)))
  589. {
  590. DeInitializeWaitGlobalComplete();
  591. }
  592. TRACE1(LEAVE, "Leaving FreeWaitThreadEntry: %d", dwErr);
  593. return NO_ERROR;
  594. } //end FreeWaitThreadEntry
  595. //----------------------------------------------------------------------------------//
  596. // GetWaitThread //
  597. // returns a wait thread which has the required number of free events //
  598. // assumes lock on g_CS. //
  599. // if NumTotalEvents is low enough, do interlocked increment. //
  600. //----------------------------------------------------------------------------------//
  601. PWAIT_THREAD_ENTRY
  602. GetWaitThread (
  603. IN DWORD dwNumEventsToAdd, //==0, if only timers are being added
  604. IN DWORD dwNumTimersToadd
  605. )
  606. {
  607. PLIST_ENTRY ple, pHead;
  608. PWAIT_THREAD_ENTRY pwte;
  609. BOOL bFound;
  610. DWORD dwIncrRefCount = dwNumEventsToAdd + dwNumTimersToadd;
  611. pHead = &WTG.gL_WaitThreadEntries;
  612. //
  613. // Locate a wait-thread with required events free.
  614. //
  615. bFound = FALSE;
  616. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  617. pwte = CONTAINING_RECORD(ple, WAIT_THREAD_ENTRY, wte_Links);
  618. // cannot allocate this server because it is not active
  619. if ((pwte->wte_Status != WT_STATUS_REGISTERED)
  620. && (pwte->wte_Status != WT_STATUS_ACTIVE)
  621. )
  622. {
  623. ETRACE0("could not allocate this wte as it is not registered");
  624. continue;
  625. }
  626. if (NUM_CLIENT_EVENTS_FREE(pwte) >= dwNumEventsToAdd) {
  627. // increment RefCount so that it cannot be deleted
  628. // interlocked operation as it can be decremented outside g_CS and inside only wte_CS
  629. InterlockedExchangeAdd((PLONG)&pwte->wte_RefCount, dwIncrRefCount);
  630. InterlockedExchangeAdd((PLONG)&pwte->wte_NumTotalEvents,
  631. (LONG)dwNumEventsToAdd);
  632. bFound = TRUE;
  633. break;
  634. }
  635. }
  636. if (bFound) {
  637. //shift the wte to the end so that all server threads are balanced
  638. RemoveEntryList(ple);
  639. InsertTailList(pHead, ple);
  640. return pwte;
  641. }
  642. else {
  643. return NULL;
  644. }
  645. }
  646. //----------------------------------------------------------------------------------//
  647. // RegisterClientEventLocal //
  648. // Register the wait event locally //
  649. // event being registered by the server itself: //
  650. // assumes lock on server //
  651. // somewhat similar to AddClientEvent //
  652. //----------------------------------------------------------------------------------//
  653. DWORD
  654. RegisterClientEventLocal (
  655. IN PWT_EVENT_ENTRY pee,
  656. IN PWAIT_THREAD_ENTRY pwte
  657. )
  658. {
  659. // insert wait event in list of event entries //dont have to do interlocked here
  660. pwte->wte_RefCount ++;
  661. pwte->wte_NumTotalEvents ++;
  662. InsertInEventsList(pee, pwte);
  663. // insert wait event in array of event entries
  664. if (pee->ee_bInitialState == FALSE) {
  665. InsertInEventsArray(pee, pwte);
  666. }
  667. else {
  668. pee->ee_Status = WT_STATUS_INACTIVE + WT_STATUS_FIRED; // but arrayIndex ==-1
  669. }
  670. return NO_ERROR;
  671. }
  672. //----------------------------------------------------------------------------------//
  673. // InsertInEventsList //
  674. // assumes lock on server //
  675. // Insert the event in the list and increment the counters //
  676. // NumTotalEvents has been increased during allocation of the server //
  677. //----------------------------------------------------------------------------------//
  678. VOID
  679. InsertInEventsList (
  680. IN PWT_EVENT_ENTRY pee,
  681. IN PWAIT_THREAD_ENTRY pwte
  682. )
  683. {
  684. InsertHeadList(&pwte->wteL_ClientEventEntries, &pee->ee_ServerLinks);
  685. //
  686. // set fields of event entry
  687. //
  688. pee->ee_ServerId = pwte->wte_ServerId;
  689. pee->eeP_wte = pwte;
  690. pee->ee_Status = WT_STATUS_REGISTERED;
  691. //
  692. // change fields of wait thread entry
  693. //
  694. //pwte->wte_RefCount++; //RefCount incremented during allocation
  695. //pwte->wte_NumTotalEvents ++; //incremented during allocation
  696. if (pee->ee_bHighPriority) {
  697. pwte->wte_NumHighPriorityEvents ++;
  698. }
  699. return;
  700. }
  701. //----------------------------------------------------------------------------------//
  702. // DeleteFromEventsList //
  703. // NumTotalEvents/Refcount is interlockedDecremented //
  704. //----------------------------------------------------------------------------------//
  705. VOID
  706. DeleteFromEventsList (
  707. IN PWT_EVENT_ENTRY pee,
  708. IN PWAIT_THREAD_ENTRY pwte
  709. )
  710. {
  711. // remove entry from list
  712. RemoveEntryList(&pee->ee_ServerLinks);
  713. //
  714. // set fields of event entry
  715. //
  716. pee->ee_Status = WT_STATUS_DELETED;
  717. //
  718. // change fields of wait thread entry
  719. //
  720. // pwte->wte_NumTotalEvents ++; interlocked incremented during allocation
  721. if (pee->ee_bHighPriority) {
  722. pwte->wte_NumHighPriorityEvents --;
  723. }
  724. InterlockedDecrement(&pwte->wte_NumTotalEvents);
  725. // decremented in DeleteClientEventComplete if ee_RefCount is 0
  726. //InterlockedDecrement(&pwte->wte_RefCount);
  727. return;
  728. }
  729. //----------------------------------------------------------------------------------//
  730. // DeleteFromEventsArray //
  731. // pee: status is not set to inactive, but array pointer is set to -1 //
  732. // pwte: decrement active counters //
  733. //----------------------------------------------------------------------------------//
  734. VOID
  735. DeleteFromEventsArray (
  736. IN PWT_EVENT_ENTRY pee,
  737. IN PWAIT_THREAD_ENTRY pwte
  738. )
  739. {
  740. INT iIndex;
  741. DWORD dwCount;
  742. iIndex = pee->ee_ArrayIndex;
  743. dwCount = pwte->wte_NumActiveEvents + pwte->wte_LowIndex - iIndex - 1;
  744. // shift right part towards left if its size is smaller
  745. if (dwCount <= pwte->wte_NumActiveEvents/2) {
  746. EventsArray_MoveOverlap (
  747. pwte,
  748. iIndex, //dstn
  749. iIndex+1, //src
  750. dwCount //count
  751. );
  752. }
  753. // shift left part towards right
  754. else {
  755. EventsArray_MoveOverlap (
  756. pwte,
  757. pwte->wte_LowIndex+1, //dstn
  758. pwte->wte_LowIndex, //src
  759. pwte->wte_NumActiveEvents - dwCount -1 //count
  760. );
  761. pwte->wte_LowIndex ++;
  762. }
  763. // set fields of event entry
  764. //
  765. pee->ee_ArrayIndex = -1;
  766. // change fields of wait thread entry
  767. //
  768. pwte->wte_NumActiveEvents --;
  769. if (pee->ee_bHighPriority) {
  770. pwte->wte_NumActiveHighPriorityEvents--;
  771. }
  772. }//end DeleteFromEventsArray
  773. //----------------------------------------------------------------------------------//
  774. // InsertInEventsArray //
  775. // assumes lock on server:wte_CS :todo is the lock required //
  776. // Insert the event in the events array and the map array (no checks are performed)//
  777. // pee: status set to active, set index to array position //
  778. // pwte: increment active counters //
  779. //----------------------------------------------------------------------------------//
  780. VOID
  781. InsertInEventsArray (
  782. IN PWT_EVENT_ENTRY pee,
  783. IN PWAIT_THREAD_ENTRY pwte
  784. )
  785. {
  786. INT iIndex;
  787. // if the array is filled to the extreme right, then shift all events to the left end
  788. if (EA_OVERFLOW(pwte, 1))
  789. EventsArray_CopyLeftEnd(pwte);
  790. //
  791. // get index where it has to be inserted
  792. //
  793. if (pee->ee_bHighPriority) {
  794. // the highPriority event has to be moved to the place right of the righmost HighPriority event
  795. iIndex = EA_INDEX_LOW_LOW_PRIORITY_EVENT(pwte);
  796. //copy the 1st low priority event to end+1;
  797. if (EA_EXISTS_LOW_PRIORITY_EVENT(pwte)) {
  798. EventsArray_Move(pwte,
  799. EA_INDEX_HIGH_LOW_PRIORITY_EVENT(pwte)+1, //dstn
  800. iIndex, //src
  801. 1 //count
  802. );
  803. }
  804. }
  805. else { // low priority event: insert in the end
  806. iIndex = EA_INDEX_HIGH_LOW_PRIORITY_EVENT(pwte)+1;
  807. }
  808. // insert the event
  809. EventsArray_InsertEvent(pee, pwte, iIndex);
  810. // set fields of event entry
  811. //
  812. pee->ee_Status = WT_STATUS_ACTIVE;
  813. pee->ee_ArrayIndex = iIndex;
  814. // change fields of wait thread entry
  815. //
  816. pwte->wte_NumActiveEvents ++;
  817. if (pee->ee_bHighPriority) {
  818. pwte->wte_NumActiveHighPriorityEvents++;
  819. }
  820. }//end InsertInEventsArray
  821. //----------------------------------------------------------------------------------//
  822. // InactivateEvent //
  823. // Remove the event from the arrays and set the inactive flag // //
  824. // Used with bManual reset //
  825. //----------------------------------------------------------------------------------//
  826. VOID
  827. InactivateEvent (
  828. IN PWT_EVENT_ENTRY pee
  829. )
  830. {
  831. DWORD dwIndex;
  832. PWAIT_THREAD_ENTRY pwte;
  833. dwIndex = pee->ee_ArrayIndex;
  834. pwte = pee->eeP_wte;
  835. // if event is not at the right end of the array, then events on its right have to be shifted
  836. if (dwIndex != EA_INDEX_HIGH_LOW_PRIORITY_EVENT(pwte)) {
  837. EventsArray_MoveOverlap(pwte, dwIndex, dwIndex+1,
  838. (pwte->wte_NumActiveEvents + pwte->wte_LowIndex - dwIndex -1)
  839. );
  840. }
  841. //
  842. // change fields in event entry to make it inactive
  843. //
  844. pee->ee_ArrayIndex = -1;
  845. pee->ee_Status = (pee->ee_Status&WT_STATUS_FIRED) + WT_STATUS_INACTIVE;
  846. //
  847. // change fields in wait thread entry
  848. //
  849. pwte->wte_NumActiveEvents --;
  850. if (pee->ee_bHighPriority) {
  851. pwte->wte_NumActiveHighPriorityEvents --;
  852. }
  853. return;
  854. }
  855. //----------------------------------------------------------------------------------//
  856. // EventsArray_CopyLeftEnd //
  857. // copy all the events to the left end of the array //
  858. // sets the wte_LowIndex value //
  859. //----------------------------------------------------------------------------------//
  860. VOID
  861. EventsArray_CopyLeftEnd (
  862. IN PWAIT_THREAD_ENTRY pwte
  863. )
  864. {
  865. EventsArray_Move(pwte,
  866. 0, //dstn
  867. pwte->wte_LowIndex, //src
  868. pwte->wte_NumActiveEvents //count
  869. );
  870. //
  871. // change fields of wait thread entry
  872. //
  873. pwte->wte_LowIndex = 0;
  874. return;
  875. }
  876. //----------------------------------------------------------------------------------//
  877. // EventsArray_Move //
  878. // copy dwCount events from the srcIndex to dstnIndex (no overlap) //
  879. //----------------------------------------------------------------------------------//
  880. VOID
  881. EventsArray_Move (
  882. IN PWAIT_THREAD_ENTRY pwte,
  883. IN DWORD dwDstnIndex,
  884. IN DWORD dwSrcIndex,
  885. IN DWORD dwCount
  886. )
  887. {
  888. PWT_EVENT_ENTRY pee;
  889. DWORD i;
  890. if (dwCount==0)
  891. return;
  892. CopyMemory( &pwte->wteA_Events[dwDstnIndex],
  893. &pwte->wteA_Events[dwSrcIndex],
  894. sizeof(HANDLE) * dwCount
  895. );
  896. CopyMemory( &pwte->wteA_EventMapper[dwDstnIndex],
  897. &pwte->wteA_EventMapper[dwSrcIndex],
  898. sizeof(PWT_EVENT_ENTRY) * dwCount
  899. );
  900. for (i=0; i<dwCount; i++) {
  901. pee = pwte->wteA_EventMapper[dwDstnIndex + i];
  902. pee->ee_ArrayIndex = dwDstnIndex + i;
  903. }
  904. return;
  905. }
  906. //----------------------------------------------------------------------------------//
  907. // EventsArray_MoveOverlap //
  908. // copy dwCount events from the srcIndex to dstnIndex (with overlap) //
  909. //----------------------------------------------------------------------------------//
  910. VOID
  911. EventsArray_MoveOverlap (
  912. IN PWAIT_THREAD_ENTRY pwte,
  913. IN DWORD dwDstnIndex,
  914. IN DWORD dwSrcIndex,
  915. IN DWORD dwCount
  916. )
  917. {
  918. PWT_EVENT_ENTRY pee;
  919. DWORD i;
  920. if (dwCount==0)
  921. return;
  922. MoveMemory( &pwte->wteA_Events[dwDstnIndex],
  923. &pwte->wteA_Events[dwSrcIndex],
  924. sizeof(HANDLE) * dwCount
  925. );
  926. MoveMemory( &pwte->wteA_EventMapper[dwDstnIndex],
  927. &pwte->wteA_EventMapper[dwSrcIndex],
  928. sizeof(PWT_EVENT_ENTRY) * dwCount
  929. );
  930. for (i=0; i<dwCount; i++) {
  931. pee = pwte->wteA_EventMapper[dwDstnIndex + i];
  932. pee->ee_ArrayIndex = dwDstnIndex + i;
  933. }
  934. return;
  935. }
  936. //----------------------------------------------------------------------------------//
  937. // EventsArray_InsertEvent //
  938. // Insert the event in the events array and the map array //
  939. //----------------------------------------------------------------------------------//
  940. VOID
  941. EventsArray_InsertEvent (
  942. IN PWT_EVENT_ENTRY pee,
  943. IN PWAIT_THREAD_ENTRY pwte,
  944. IN INT iIndex
  945. )
  946. {
  947. // insert event in events array
  948. pwte->wteA_Events[iIndex] = pee->ee_Event;
  949. // insert pointer in map array
  950. pwte->wteA_EventMapper[iIndex] = pee;
  951. return;
  952. }
  953. //---------------------------------------------------------------------------------*//
  954. // GetListLength //
  955. // returns the length of the list //
  956. // returns 0 if the list contains the header only //
  957. //----------------------------------------------------------------------------------//
  958. INT
  959. GetListLength (
  960. IN PLIST_ENTRY pHead
  961. )
  962. {
  963. PLIST_ENTRY ple;
  964. DWORD dwCount=0;
  965. if (pHead==NULL)
  966. return -1;
  967. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  968. dwCount++;
  969. }
  970. return dwCount;
  971. }
  972. VOID
  973. PrintEvent (
  974. PWT_EVENT_ENTRY pee,
  975. DWORD level
  976. )
  977. {
  978. PLIST_ENTRY pHead, ple;
  979. PWT_WORK_ITEM pwi;
  980. if (pee->ee_Event==NULL)
  981. printf(" Event is NULL\n");
  982. printf("-- -------------------------------------------------------------------------\n");
  983. printf("-- <%2d><ee_bManualReset:%2d> <ee_bInitialState:%2d> <ee_Status:%2d> <ee_bHighPriority:%2d>\n",
  984. pee->ee_EventId, pee->ee_bManualReset, pee->ee_bInitialState, pee->ee_Status,
  985. pee->ee_bHighPriority);
  986. printf("-- <ee_bSignalSingle:%2d> <ee_bOwnerSelf:%2d> <ee_ArrayIndex:%2d> <ee_ServerId:4%d>\n",
  987. pee->ee_bSignalSingle, pee->ee_bOwnerSelf, pee->ee_ArrayIndex, pee->ee_ServerId);
  988. printf("-- <ee_RefCount:%d\n", pee->ee_RefCount);
  989. pHead = &pee->eeL_wi;
  990. printf("-- LIST OF EVENT BINDINGS\n");
  991. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  992. pwi = CONTAINING_RECORD(ple, WT_WORK_ITEM, wi_ServerLinks);
  993. printf("-- <wi_ContextSz:%lu> <wi_RunInServer:%d> <wiP_ee:%lu>\n",
  994. pwi->wi_ContextSz, pwi->wi_RunInServer, (UINT_PTR)(PVOID)pwi->wiP_ee);
  995. }
  996. return;
  997. }
  998. VOID
  999. PrintTimer (
  1000. PWT_TIMER_ENTRY pte,
  1001. DWORD level
  1002. )
  1003. {
  1004. LARGE_INTEGER li;
  1005. TRACE0(WAIT_TIMER,"__ ________________________________________________________________________");
  1006. TRACE4(WAIT_TIMER, "__ <TimerId:%2d><Timeout:%lu:%lu> <te_ContextSz:%lu>",
  1007. pte->te_TimerId, TIMER_HIGH(pte->te_Timeout), TIMER_LOW(pte->te_Timeout), pte->te_ContextSz);
  1008. TRACE3(WAIT_TIMER, "__ <te_RunInServer:%1d> <te_Status:%1d> <te_ServerId:%d>",
  1009. pte->te_RunInServer, pte->te_Status, pte->te_ServerId);
  1010. return;
  1011. }
  1012. //----------------------------------------------------------------------------------//
  1013. // PrintWaitThreadEntry //
  1014. // Prints the events and timers registered with this server. //
  1015. //----------------------------------------------------------------------------------//
  1016. VOID
  1017. PrintWaitThreadEntry (
  1018. PWAIT_THREAD_ENTRY pwte,
  1019. DWORD level
  1020. )
  1021. {
  1022. PLIST_ENTRY ple, pHead;
  1023. PWT_EVENT_ENTRY pee;
  1024. PWT_TIMER_ENTRY pte;
  1025. DWORD dwHigh, dwLow;
  1026. LARGE_INTEGER li;
  1027. BOOL bPrint;
  1028. DWORD i;
  1029. TRACE0(WAIT_TIMER, "\n");
  1030. TRACE0(WAIT_TIMER, "=================================================================================");
  1031. TRACE3(WAIT_TIMER, "== <wte_ServerId:%2lu> <wte_ThreadId:%2lu> <wte_NumClients:%2lu>",
  1032. pwte->wte_ServerId, pwte->wte_ThreadId, pwte->wte_NumClients);
  1033. TRACE2(WAIT_TIMER, "== <wte_Status:%2lu> <wte_RefCount:%2lu>", pwte->wte_Status, pwte->wte_RefCount);
  1034. //
  1035. // print list of events registered
  1036. //
  1037. if (!(level&DEBUGPRINT_FILTER_EVENTS)) {
  1038. TRACE0(WAIT_TIMER, "-- ");
  1039. TRACE0(WAIT_TIMER, "---------------------------------------------------------------------------------");
  1040. TRACE2(WAIT_TIMER,"-- <wte_LowIndex:%2lu> <wte_NumTotalEvents:%2lu>",
  1041. pwte->wte_LowIndex, pwte->wte_NumTotalEvents);
  1042. TRACE2(WAIT_TIMER, "-- <wte_NumActiveEvents:%2lu> <wte_NumHighPriorityEvents:%2lu>",
  1043. pwte->wte_NumActiveEvents, pwte->wte_NumHighPriorityEvents);
  1044. TRACE1(WAIT_TIMER, "-- <wte_NumActiveHighPriorityEvents:%2lu>", pwte->wte_NumActiveHighPriorityEvents);
  1045. if (level&0x2) {//dont print the initial 4 reserved events
  1046. bPrint = FALSE;
  1047. i = 0;
  1048. }
  1049. else
  1050. bPrint = TRUE;
  1051. TRACE0(WAIT_TIMER, "--");
  1052. pHead = &pwte->wteL_ClientEventEntries;
  1053. for (ple=pHead->Blink; ple!=pHead; ple=ple->Blink) {
  1054. if (!bPrint) {
  1055. if (++i==4)
  1056. bPrint=TRUE;
  1057. continue;
  1058. }
  1059. pee = CONTAINING_RECORD(ple, WT_EVENT_ENTRY, ee_ServerLinks);
  1060. PrintEvent(pee, level);
  1061. }
  1062. for (i=0; i<=10; i++) {
  1063. if (pwte->wteA_EventMapper[i]==NULL)
  1064. TRACE0(WAIT_TIMER, "--");
  1065. else
  1066. TRACE2(WAIT_TIMER, "<%d:%d>", (pwte->wteA_EventMapper[i])->ee_EventId,
  1067. (pwte->wteA_EventMapper[i])->ee_ArrayIndex);
  1068. }
  1069. }
  1070. //
  1071. // print list of timers registered
  1072. //
  1073. if (!(level&DEBUGPRINT_FILTER_TIMERS)) {
  1074. li = *(LARGE_INTEGER*)(PVOID)&pwte->wte_Timeout;
  1075. dwHigh = li.HighPart;
  1076. dwLow = li.LowPart;
  1077. TRACE0(WAIT_TIMER, "--");
  1078. TRACE0(WAIT_TIMER,"_________________________________________________________________________________");
  1079. TRACE2(WAIT_TIMER, "__ <wte_Timeout.high:%lu> <wte_Timeout.low:%lu>", dwHigh, dwLow);
  1080. pHead = &pwte->wteL_ClientTimerEntries;
  1081. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  1082. pte = CONTAINING_RECORD(ple, WT_TIMER_ENTRY, te_ServerLinks);
  1083. PrintTimer(pte, level);
  1084. }
  1085. }
  1086. return;
  1087. } //PrintWaitThreadEntry