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.

1825 lines
55 KiB

  1. #include "wt.h"
  2. #include "wtproto.h"
  3. #include "workerinc.h"
  4. //////////////////////////////////////////////////////////////////////////////////
  5. //
  6. // create event and register client are separated so that all events/timers can be
  7. // registered as one atomic operation.
  8. // assumption: you should always register.
  9. //
  10. // Locks: the server does not need to take lock when changing the arrays/lists
  11. // arrays and lists can be changed by the wait server thread only after it has
  12. // been signalled
  13. // g_CS, wte_CS, wte_CSTimer -->> order of taking locks
  14. // -- wte_CS always taken by client on behalf of the server:
  15. // used to lock the list of changes till the changes have completed
  16. // (RefCount can decrease now)
  17. // server locks it only when it is initializing itself
  18. // -- wte_CSTimer taken by client when it wants to change a timer which already
  19. // exists or by server when it wants to go throught the timer list after
  20. // the timer is fired.
  21. // note: if wte_CS is taken by server then it may lead to deadlock
  22. // lock taken by client which wakes up server. server wakes up on
  23. // some other event which needs that lock
  24. // note: wte_CSTimer lock is taken by clients and server independently and not
  25. // on behalf of the other. So no possibility of deadlock
  26. // -- g_CS : locked by client for finding which server to use (wte->wte_NumTotalEvents)
  27. // -- g_CS : locked by server to delete itself.
  28. // wte_NumTotalEvents read under g_CS or wte_CS, incremented under g_CS,
  29. // decremented under wte_CS
  30. // so use interlocked operation. you might not have been able to allocate
  31. // a server which just then frees events, but this "inconsistency" is fine
  32. // RULES: never free a shared event when other bindings exist
  33. // //todo: when last event/timer is deleted, delete the wte if deleted flag is set
  34. // 3. all events that have been created have to be registered before deleting them
  35. // //todo: remove above requirement
  36. // you can call deregister functions from within server thread
  37. // YOU CANNOT CALL FUNCTIONS LIKE DEREGISTER//REGISTER from within a server thread.
  38. // Be careful when you queue to alertable thread. an alertable thread cannot be
  39. // client/server at same time.
  40. //
  41. //////////////////////////////////////////////////////////////////////////////////
  42. VOID
  43. APIENTRY
  44. WTFreeEvent (
  45. IN PWT_EVENT_ENTRY peeEvent
  46. )
  47. {
  48. if (peeEvent==NULL)
  49. return;
  50. FreeWaitEvent(peeEvent);
  51. return;
  52. }
  53. VOID
  54. APIENTRY
  55. WTFreeTimer (
  56. IN PWT_TIMER_ENTRY pteTimer
  57. )
  58. {
  59. if (pteTimer==NULL)
  60. return;
  61. FreeWaitTimer(pteTimer);
  62. return;
  63. }
  64. VOID
  65. APIENTRY
  66. WTFree (
  67. PVOID ptr
  68. )
  69. {
  70. WT_FREE(ptr);
  71. return;
  72. }
  73. //------------------------------------------------------------------------------//
  74. // DebugPrintWaitWorkerThreads //
  75. //THE LATEST STATE MAY NOT BE THE ONE YOU EXPECT, eg if you set event and //
  76. //immediately do debugprint, the alertableThread might not have processed it by //
  77. //the time the enumeration is done //
  78. //------------------------------------------------------------------------------//
  79. VOID
  80. APIENTRY
  81. DebugPrintWaitWorkerThreads (
  82. DWORD dwDebugLevel
  83. )
  84. {
  85. PLIST_ENTRY ple, pHead;
  86. PWAIT_THREAD_ENTRY pwte;
  87. DWORD dwErr;
  88. // initialize worker threads if not yet done
  89. if (!ENTER_WAIT_API()) {
  90. dwErr = GetLastError();
  91. return;
  92. }
  93. TRACE_ENTER("Entering DebugPrintWaitWorkerThreads");
  94. ENTER_CRITICAL_SECTION(&WTG.g_CS, "g_CS", "DebugPrintWaitWorkerThreads");
  95. pHead = &WTG.gL_WaitThreadEntries;
  96. for (ple=pHead->Flink; ple!=pHead; ple=ple->Flink) {
  97. pwte = CONTAINING_RECORD(ple, WAIT_THREAD_ENTRY, wte_Links);
  98. ENTER_CRITICAL_SECTION(&pwte->wte_CS, "wte_CS",
  99. "DebugPrintWaitWorkerThreads");
  100. ENTER_CRITICAL_SECTION(&pwte->wte_CSTimer, "wte_CSTimer",
  101. "DebugPrintWaitWorkerThreads");
  102. PrintWaitThreadEntry(pwte, dwDebugLevel);
  103. LEAVE_CRITICAL_SECTION(&pwte->wte_CSTimer,
  104. "wte_CSTimer", "DebugPrintWaitWorkerThreads");
  105. LEAVE_CRITICAL_SECTION(&pwte->wte_CS, "wte_CS",
  106. "DebugPrintWaitWorkerThreads");
  107. }
  108. LEAVE_CRITICAL_SECTION(&WTG.g_CS, "g_CS", "DebugPrintWaitWorkerThreads");
  109. TRACE_LEAVE("Leaving DebugPrintWaitWorkerThreads");
  110. return;
  111. }
  112. //++----------------------------------------------------------------------------//
  113. // AlertableWaitWorkerThread //
  114. //------------------------------------------------------------------------------//
  115. DWORD
  116. APIENTRY
  117. AlertableWaitWorkerThread (
  118. IN LPVOID param
  119. )
  120. {
  121. PWAIT_THREAD_ENTRY pwte;
  122. DWORD dwErr = NO_ERROR;
  123. DWORD dwThreadId = GetCurrentThreadId();
  124. DWORD dwRetVal, dwIndex;
  125. BOOL bBreakout = FALSE;
  126. //DWORD dwFirstThread;
  127. //TRACE0(ENTER, "Entering AlertableWaitWorkerThread: ");
  128. //dwFirstThread = (DWORD) param;
  129. //
  130. // create the structures and add this thread as one of the aletertable
  131. // wait threads.
  132. //
  133. // create and initialize wait thread entry
  134. dwErr = CreateWaitThreadEntry(dwThreadId, &pwte);
  135. // exit if thread could not be initialized
  136. if (dwErr!=NO_ERROR) {
  137. return dwErr;
  138. }
  139. //
  140. // get global lock and insert wait-thread-entry into the list of entries
  141. //
  142. EnterCriticalSection(&WTG.g_CS);
  143. // acquire lock on server thread and timer section before inserting
  144. // into global list
  145. EnterCriticalSection(&pwte->wte_CS);
  146. EnterCriticalSection(&pwte->wte_CSTimer);
  147. InsertWaitThreadEntry(pwte);
  148. //THERE SHOULD BE NO CALLS TO RTUTILS APIS IN THIS FUNCTION TILL HERE WHEN
  149. //INITIALIZING THE FIRST ALERTABLE THREAD
  150. // set event so that rest of rtutils initialization can proceed
  151. /*if (dwFirstThread==0) {
  152. TRACE0(CS, "Initialization of 1st worker thread done");
  153. SetEvent(WTG.g_InitializedEvent);
  154. }
  155. */
  156. //
  157. // create the initial events and waitable timer
  158. //
  159. dwErr = CreateServerEventsAndTimer(pwte);
  160. LeaveCriticalSection(&WTG.g_CS);
  161. // initialization done: release lock on server thread
  162. LeaveCriticalSection(&pwte->wte_CSTimer);
  163. LeaveCriticalSection(&pwte->wte_CS);
  164. //
  165. // wait for servicing events
  166. //
  167. do {
  168. // locks not required as pwteEvents(array,list) can be changed by server
  169. // thread only
  170. TRACE0(CS, "AlertableThread waiting for events:%d");
  171. dwRetVal = WaitForMultipleObjectsEx(pwte->wte_NumActiveEvents,
  172. &pwte->wteA_Events[pwte->wte_LowIndex],
  173. FALSE, INFINITE, TRUE);
  174. TRACE0(CS, "AlertableThread woken by signalled event");
  175. switch (dwRetVal) {
  176. case WAIT_IO_COMPLETION:
  177. {
  178. // Handled IO completion
  179. break;
  180. }
  181. case 0xFFFFFFFF:
  182. {
  183. // Error, we must have closed the semaphore handle
  184. bBreakout = TRUE;
  185. break;
  186. }
  187. default:
  188. {
  189. PLIST_ENTRY ple, pHead;
  190. PWT_WORK_ITEM pwi;
  191. PWT_EVENT_ENTRY pee;
  192. DWORD dwCount;
  193. //
  194. // wait returned an error
  195. //
  196. if (dwRetVal > (WAIT_OBJECT_0+pwte->wte_NumActiveEvents-1))
  197. {
  198. bBreakout = TRUE;
  199. break;
  200. }
  201. //
  202. // service the different events
  203. //
  204. // get pointer to event entry
  205. dwIndex = dwRetVal - WAIT_OBJECT_0 + pwte->wte_LowIndex;
  206. pee = pwte->wteA_EventMapper[dwIndex];
  207. // move event to end of array, and shift the left part rightwards, or
  208. // the right part leftwards (only if the event is not a high priority event)
  209. if (!pee->ee_bHighPriority) {
  210. if (EA_OVERFLOW(pwte, 1)) {
  211. EventsArray_CopyLeftEnd(pwte);
  212. dwIndex = dwRetVal - WAIT_OBJECT_0 + pwte->wte_LowIndex;
  213. }
  214. //if righmost entry, then dont have to shift
  215. if (!(dwIndex==EA_INDEX_HIGH_LOW_PRIORITY_EVENT(pwte))) {
  216. // move the signalled event to the right end
  217. EventsArray_Move(pwte,
  218. EA_INDEX_HIGH_LOW_PRIORITY_EVENT(pwte)+1, //dstn
  219. dwIndex, //src
  220. 1 //count
  221. );
  222. dwCount = pwte->wte_NumActiveEvents + pwte->wte_LowIndex
  223. - dwIndex - 1;
  224. // shift right part towards left if its size is smaller
  225. if (dwCount <= pwte->wte_NumActiveEvents/2) {
  226. EventsArray_MoveOverlap (
  227. pwte,
  228. dwIndex, //dstn
  229. dwIndex+1, //src
  230. dwCount+1 //count:
  231. //+1 as the entry has been moved to the right end
  232. );
  233. }
  234. // shift left part towards right
  235. else {
  236. EventsArray_MoveOverlap (
  237. pwte,
  238. pwte->wte_LowIndex+1, //dstn
  239. pwte->wte_LowIndex, //src
  240. pwte->wte_NumActiveEvents - dwCount -1 //count
  241. );
  242. pwte->wte_LowIndex ++;
  243. }
  244. }
  245. }
  246. // for each work item allocate context if not run in server context
  247. // so all functions can be run only in server or worker context.
  248. // else there will be errors.
  249. pHead = &pee->eeL_wi;
  250. for (ple=pHead->Flink; ple!=pHead; ) {
  251. pwi = CONTAINING_RECORD(ple, WT_WORK_ITEM, wi_ServerLinks);
  252. if (pwi->wi_Function==NULL) {
  253. continue;
  254. }
  255. ple = ple->Flink; // this allows deregistering of current binding
  256. // Run the work item in the present context or queue it to worker thread
  257. DispatchWorkItem(pwi);
  258. }
  259. //
  260. // if it is manual reset then remove from array, and shift it from
  261. // active to inactive
  262. //
  263. if (pee->ee_bManualReset) {
  264. pee->ee_Status = WT_STATUS_FIRED;
  265. InactivateEvent(pee);
  266. }
  267. break;
  268. } //end case:default
  269. } //end switch
  270. } while ((WorkersInitialized==WORKERS_INITIALIZED) &&(bBreakout!=TRUE));
  271. TRACE0(LEAVE, "Leaving AlertableWaitWorkerThread:");
  272. return 0;
  273. } //end AlertableWaitWorkerThread
  274. //------------------------------------------------------------------------------//
  275. // UpdateWaitTimer //
  276. // a timer can be inactivated by setting the update timeout to 0 //
  277. // relative time can be sent by sending the complement: time = -time //
  278. //------------------------------------------------------------------------------//
  279. DWORD
  280. APIENTRY
  281. UpdateWaitTimer (
  282. IN PWT_TIMER_ENTRY pte,
  283. IN LONGLONG *pTime
  284. )
  285. {
  286. PWAIT_THREAD_ENTRY pwte;
  287. PLIST_ENTRY ple, pHead;
  288. PWT_TIMER_ENTRY pteCur;
  289. BOOL bDecrease;
  290. LONGLONG newTime = *pTime;
  291. LONGLONG oldTime;
  292. LONGLONG currentTime;
  293. // get the waitThreadEntry
  294. pwte = pte->teP_wte;
  295. oldTime = pte->te_Timeout;
  296. pte->te_Timeout = newTime;
  297. //convert relative time to absolute time
  298. if (newTime<0) {
  299. newTime = -newTime;
  300. NtQuerySystemTime((LARGE_INTEGER*) &currentTime);
  301. newTime += currentTime;
  302. }
  303. // if wait thread is set to deleted, then return error
  304. if (pwte->wte_Status == WT_STATUS_DELETED) {
  305. return ERROR_CAN_NOT_COMPLETE;
  306. }
  307. ENTER_CRITICAL_SECTION(&pwte->wte_CSTimer, "wte_CSTimer", "UpdateWaitTimer");
  308. // the timer should have been deleted
  309. if (pte->te_Status==WT_STATUS_DELETED) {
  310. TRACE0(TIMER, "cannot update timer whose status is set to deleted");
  311. LEAVE_CRITICAL_SECTION(&pwte->wte_CSTimer, "wte_CSTimer", "UpdateWaitTimer");
  312. return ERROR_CAN_NOT_COMPLETE;
  313. }
  314. // the timer is to be disabled and inserted at end of timers list
  315. if (IS_TIMER_INFINITE(newTime)) {
  316. TRACE0(TIMER, "Called UpdateWaitTimer to disable a timer");
  317. SET_TIMER_INFINITE(pte->te_Timeout);
  318. pte->te_Status = TIMER_INACTIVE;
  319. RemoveEntryList(&pte->te_ServerLinks);
  320. InsertTailList(&pwte->wteL_ClientTimerEntries, &pte->te_ServerLinks);
  321. }
  322. else {
  323. TRACE4(TIMER, "Called UpdateWaitTimer to update timer from <%lu:%lu> to <%lu:%lu>",
  324. TIMER_HIGH(oldTime), TIMER_LOW(oldTime),
  325. TIMER_HIGH(newTime), TIMER_LOW(newTime));
  326. bDecrease = (newTime<oldTime) || (IS_TIMER_INFINITE(oldTime));
  327. pte->te_Status = TIMER_ACTIVE;
  328. pHead = &pwte->wteL_ClientTimerEntries;
  329. ple = bDecrease? (pte->te_ServerLinks).Blink: (pte->te_ServerLinks).Flink;
  330. RemoveEntryList(&pte->te_ServerLinks);
  331. if (bDecrease) {
  332. for ( ; ple!=pHead; ple=ple->Blink) {
  333. pteCur = CONTAINING_RECORD(ple, WT_TIMER_ENTRY, te_ServerLinks);
  334. if (pteCur->te_Status==TIMER_INACTIVE)
  335. continue;
  336. if (pteCur->te_Timeout>newTime)
  337. continue;
  338. else
  339. break;
  340. }
  341. InsertHeadList(ple, &pte->te_ServerLinks);
  342. }
  343. else {
  344. for ( ; ple!=pHead; ple=ple->Flink) {
  345. pteCur = CONTAINING_RECORD(ple, WT_TIMER_ENTRY, te_ServerLinks);
  346. if (IS_TIMER_INFINITE(pteCur->te_Timeout)
  347. || (pteCur->te_Status==TIMER_INACTIVE)
  348. || (pteCur->te_Timeout>newTime))
  349. {
  350. break;
  351. }
  352. }
  353. InsertTailList(ple, &pte->te_ServerLinks);
  354. }
  355. }
  356. //
  357. // see if the WaitableTimer timeout has to be changed
  358. //
  359. pteCur = CONTAINING_RECORD(pwte->wteL_ClientTimerEntries.Flink, WT_TIMER_ENTRY, te_ServerLinks);
  360. if (pteCur->te_Status == TIMER_INACTIVE) {
  361. TRACE0(TIMER, "CancelWaitableTimer called");
  362. SET_TIMER_INFINITE(pwte->wte_Timeout);
  363. CancelWaitableTimer(pwte->wte_Timer);
  364. }
  365. else if (pteCur->te_Timeout!=pwte->wte_Timeout) {
  366. TRACE2(TIMER, "SetWaitableTimer called <%lu:%lu>",
  367. TIMER_HIGH(pteCur->te_Timeout), TIMER_LOW(pteCur->te_Timeout));
  368. pwte->wte_Timeout = pteCur->te_Timeout;
  369. SetWaitableTimer(pwte->wte_Timer, (LARGE_INTEGER*)&pwte->wte_Timeout, 0, NULL, NULL, FALSE);
  370. }
  371. LEAVE_CRITICAL_SECTION(&pwte->wte_CSTimer, "wte_CSTimer", "UpdateWaitTimer");
  372. return NO_ERROR;
  373. }
  374. //++--------------------------------------------------------------------------------//
  375. // DispatchWorkItem //
  376. //----------------------------------------------------------------------------------//
  377. DWORD
  378. DispatchWorkItem (
  379. IN PWT_WORK_ITEM pwi
  380. )
  381. {
  382. PVOID pContext;
  383. DWORD dwErr = NO_ERROR;
  384. // if it has to run in server context
  385. if (pwi->wi_RunInServer) {
  386. (pwi->wi_Function)(pwi->wi_Context);
  387. }
  388. // else queue to worker thread
  389. else {
  390. QueueWorkItem(pwi->wi_Function, pwi->wi_Context, FALSE);
  391. }
  392. return NO_ERROR;
  393. }
  394. //++----------------------------------------------------------------------------//
  395. // RegisterWaitEventsTimers //
  396. // Register the client with the wait thread //
  397. // The client acquires lock on wte_CS on behalf of the server. If timers have to//
  398. // change then the server has to lock the timers in RegisterClientEventTimers//
  399. //------------------------------------------------------------------------------//
  400. DWORD
  401. APIENTRY
  402. RegisterWaitEventsTimers (
  403. IN PLIST_ENTRY pLEventsToAdd,
  404. IN PLIST_ENTRY pLTimersToAdd
  405. )
  406. {
  407. PWAIT_THREAD_ENTRY pwte;
  408. INT iNumEventsToAdd, iNumTimersToAdd;
  409. DWORD dwErr;
  410. //ChangeClientEventsTimersAux(1, pwte); // add
  411. // you cannot register without creating it first!!
  412. // initialize worker threads if not yet done
  413. if (!ENTER_WAIT_API()) {
  414. dwErr = GetLastError();
  415. return (dwErr == NO_ERROR ? ERROR_CAN_NOT_COMPLETE : dwErr);
  416. }
  417. TRACE0(ENTER, "Entering : RegisterWaitEventsTimers");
  418. // get global lock: g_CS
  419. ENTER_CRITICAL_SECTION(&WTG.g_CS, "g_CS", "RegisterWaitEventsTimers");
  420. //
  421. // locate the wait thread server with iNumEventsToAdd free events
  422. //
  423. // if iNumEventsToAdd ptr !=0 but list length is 1, means no list header
  424. iNumEventsToAdd = GetListLength(pLEventsToAdd);
  425. if (iNumEventsToAdd<0)
  426. iNumEventsToAdd = 0;
  427. if ((pLEventsToAdd!=NULL) && (iNumEventsToAdd==0))
  428. iNumEventsToAdd = 1;
  429. iNumTimersToAdd = GetListLength(pLTimersToAdd);
  430. if (iNumTimersToAdd<0)
  431. iNumTimersToAdd = 0;
  432. if ((pLTimersToAdd!=NULL) && (iNumTimersToAdd==0))
  433. iNumTimersToAdd = 1;
  434. // iNumEventsToAdd may be 0, if timers only have to be added
  435. // getWaiThread increments the refCount of the server so that it cannot be deleted
  436. // wte_NumTotalEvents so that space is reserved
  437. pwte = GetWaitThread(iNumEventsToAdd, iNumTimersToAdd);
  438. if (pwte==NULL) {
  439. TRACE0(WT, "could not allocate wait thread");
  440. LEAVE_CRITICAL_SECTION(&WTG.g_CS, "g_CS", "RegisterWaitEventsTimers");
  441. return ERROR_WAIT_THREAD_UNAVAILABLE;
  442. }
  443. // lock server: wte_CS
  444. ENTER_CRITICAL_SECTION(&pwte->wte_CS, "wte_CS", "RegisterWaitEventsTimers");
  445. // release global lock: g_CS
  446. LEAVE_CRITICAL_SECTION(&WTG.g_CS, "g_CS", "RegisterWaitEventsTimers");
  447. //
  448. // events/timers to be added
  449. //
  450. pwte->wte_ChangeType = CHANGE_TYPE_ADD;
  451. pwte->wtePL_EventsToChange = pLEventsToAdd;
  452. pwte->wtePL_TimersToChange = pLTimersToAdd;
  453. //
  454. // Wake up the server so that it can enter the events and timers of the client
  455. //
  456. SET_EVENT(pwte->wte_ClientNotifyWTEvent, "wte_ClientNotifyWTEvent", "RegisterWaitEventsTimers");
  457. // Wait till wait server notifies on completion
  458. //
  459. WAIT_FOR_SINGLE_OBJECT(pwte->wte_WTNotifyClientEvent, INFINITE,
  460. "wte_WTNotifyClientEvent", "RegisterWaitEventsTimers");
  461. //release server lock: wte_CS
  462. LEAVE_CRITICAL_SECTION(&pwte->wte_CS, "wte_CS", "RegisterWaitEventsTimers");
  463. TRACE0(LEAVE, "Leaving: RegisterWaitEventsTimers");
  464. return NO_ERROR;
  465. } //end RegisterWaitEventsTimers
  466. //++----------------------------------------------------------------------------//
  467. // RegisterClientEventsTimers:aux //
  468. // Add the client events and timers //
  469. // The client has the lock on the server and has already increased the refCount //
  470. //------------------------------------------------------------------------------//
  471. DWORD
  472. RegisterClientEventsTimers (
  473. IN PWAIT_THREAD_ENTRY pwte
  474. )
  475. {
  476. ChangeClientEventsTimersAux(1, pwte, pwte->wtePL_EventsToChange,
  477. pwte->wtePL_TimersToChange); // add
  478. return NO_ERROR;
  479. }
  480. //++----------------------------------------------------------------------------//
  481. // ChangeClientEventsTimersAux:aux //
  482. // Add/delete the client events and timers //
  483. // The client has the lock on the server and has already increased the refCount //
  484. // (add) //
  485. //------------------------------------------------------------------------------//
  486. DWORD
  487. ChangeClientEventsTimersAux (
  488. IN BOOL bChangeTypeAdd,
  489. IN PWAIT_THREAD_ENTRY pwte,
  490. IN PLIST_ENTRY pLEvents,
  491. IN PLIST_ENTRY pLTimers
  492. )
  493. {
  494. PLIST_ENTRY ple;
  495. PWT_EVENT_ENTRY pee;
  496. PWT_TIMER_ENTRY pte;
  497. //
  498. // process each event to be changed(added/deleted)
  499. //
  500. if (pLEvents != NULL) {
  501. //
  502. // list of events
  503. //
  504. if (!IsListEmpty(pLEvents)) {
  505. for (ple=pLEvents->Flink; ple!=pLEvents; ) {
  506. pee = CONTAINING_RECORD(ple, WT_EVENT_ENTRY, ee_Links);
  507. ple = ple->Flink;
  508. if (bChangeTypeAdd)
  509. AddClientEvent(pee, pwte);
  510. else
  511. DeleteClientEvent(pee, pwte);
  512. }
  513. }
  514. //
  515. // single event
  516. else { // list empty but not null, so pointer to only one event
  517. pee = CONTAINING_RECORD(pLEvents, WT_EVENT_ENTRY, ee_Links);
  518. if (bChangeTypeAdd)
  519. AddClientEvent(pee, pwte);
  520. else
  521. DeleteClientEvent(pee, pwte);
  522. }
  523. }
  524. //
  525. // process each timer to be added/deleted
  526. //
  527. if (pLTimers != NULL) {
  528. ENTER_CRITICAL_SECTION(&pwte->wte_CSTimer, "wte_CSTimer",
  529. "ChangeClientEventsTimersAux");
  530. //
  531. // list of timers
  532. //
  533. if (!IsListEmpty(pLTimers)) {
  534. for (ple=pLTimers->Flink; ple!=pLTimers;) {
  535. pte = CONTAINING_RECORD(ple, WT_TIMER_ENTRY, te_Links);
  536. ple = ple->Flink;
  537. if (bChangeTypeAdd)
  538. AddClientTimer(pte, pwte);
  539. else
  540. DeleteClientTimer(pte, pwte);
  541. }
  542. }
  543. //
  544. //single timer
  545. else { // list empty but not null, so pointer to only one timer
  546. pte = CONTAINING_RECORD(pLTimers, WT_TIMER_ENTRY, te_Links);
  547. if (bChangeTypeAdd)
  548. AddClientTimer(pte, pwte);
  549. else
  550. DeleteClientTimer(pte, pwte);
  551. }
  552. LEAVE_CRITICAL_SECTION(&pwte->wte_CSTimer, "wte_CSTimer",
  553. "ChangeClientEventsTimersAux");
  554. }
  555. return NO_ERROR;
  556. }
  557. //++----------------------------------------------------------------------------//
  558. // AddClientEvent //
  559. // calling client has locked the server wte_CS: and increased refCount with server //
  560. // somewhat similar to RegisterClientEventLocal //
  561. //------------------------------------------------------------------------------//
  562. DWORD
  563. AddClientEvent (
  564. IN PWT_EVENT_ENTRY pee,
  565. IN PWAIT_THREAD_ENTRY pwte
  566. )
  567. {
  568. // the event might have been deleted by some other thread (such things should
  569. // never happen)
  570. if (pee->ee_Status==WT_STATUS_DELETED) {
  571. //todo check above
  572. // delete the event if RefCount is 0
  573. if (pee->ee_RefCount==0) {
  574. FreeWaitEvent(pee);
  575. }
  576. // decrement refcount as it was increased by client adding the events
  577. InterlockedDecrement(&pwte->wte_NumTotalEvents);
  578. InterlockedDecrement(&pwte->wte_RefCount);
  579. return ERROR_WT_EVENT_ALREADY_DELETED;
  580. }
  581. // insert the client event into the list of client events
  582. InsertInEventsList(pee, pwte);
  583. // insert the client into the MapArray and EventsArray
  584. if (pee->ee_bInitialState == FALSE) {
  585. InsertInEventsArray(pee, pwte);
  586. }
  587. //fired so not inserted in array
  588. else {
  589. pee->ee_Status = WT_STATUS_INACTIVE + WT_STATUS_FIRED;
  590. }
  591. return NO_ERROR;
  592. }
  593. //++----------------------------------------------------------------------------//
  594. // AddClientTimer //
  595. // The client has the lock on the server //
  596. // refcount has already been changed during registration //
  597. //------------------------------------------------------------------------------//
  598. DWORD
  599. AddClientTimer (
  600. PWT_TIMER_ENTRY pte,
  601. PWAIT_THREAD_ENTRY pwte
  602. )
  603. {
  604. // change fields of timerEntry
  605. pte->te_Status = TIMER_INACTIVE;
  606. pte->te_ServerId = pwte->wte_ServerId;
  607. pte->teP_wte = pwte;
  608. //insert inactive timers at end of list
  609. InsertTailList(&pwte->wteL_ClientTimerEntries, &pte->te_ServerLinks);
  610. return NO_ERROR;
  611. }
  612. //++----------------------------------------------------------------------------//
  613. // DeleteClientTimer //
  614. // The client has the lock on the server //
  615. //------------------------------------------------------------------------------//
  616. DWORD
  617. DeleteClientTimer (
  618. PWT_TIMER_ENTRY pte,
  619. PWAIT_THREAD_ENTRY pwte
  620. )
  621. {
  622. // change fields of waitThreadEntry
  623. InterlockedDecrement(&pwte->wte_RefCount);
  624. // if deleted flag set and refcount is 0, delete the wait entry
  625. if ((pwte->wte_Status == WT_STATUS_DELETED)
  626. && (pwte->wte_RefCount==0)
  627. )
  628. {
  629. FreeWaitThreadEntry(pwte);
  630. }
  631. //remove the timer from timer list
  632. RemoveEntryList(&pte->te_ServerLinks);
  633. FreeWaitTimer(pte);
  634. //
  635. // see if the WaitableTimer timeout has to be changed
  636. //
  637. // if list is empty then cancel the timer
  638. if (IsListEmpty(&pwte->wteL_ClientTimerEntries)) {
  639. if (!IS_TIMER_INFINITE(pwte->wte_Timeout))
  640. CancelWaitableTimer(pwte->wte_Timer);
  641. SET_TIMER_INFINITE(pwte->wte_Timeout);
  642. }
  643. else {
  644. PWT_TIMER_ENTRY pteCur;
  645. pteCur = CONTAINING_RECORD(pwte->wteL_ClientTimerEntries.Flink,
  646. WT_TIMER_ENTRY, te_ServerLinks);
  647. if (pteCur->te_Status == TIMER_INACTIVE) {
  648. TRACE0(TIMER, "CancelWaitableTimer called in DeleteClientTimer");
  649. if (!IS_TIMER_INFINITE(pwte->wte_Timeout))
  650. CancelWaitableTimer(pwte->wte_Timer);
  651. SET_TIMER_INFINITE(pwte->wte_Timeout);
  652. }
  653. else if (pteCur->te_Timeout!=pwte->wte_Timeout) {
  654. TRACE2(TIMER, "SetWaitableTimer called in DeleteClientTimer<%lu:%lu>",
  655. TIMER_HIGH(pteCur->te_Timeout),
  656. TIMER_LOW(pteCur->te_Timeout));
  657. pwte->wte_Timeout = pteCur->te_Timeout;
  658. SetWaitableTimer(pwte->wte_Timer, (LARGE_INTEGER*)&pwte->wte_Timeout,
  659. 0, NULL, NULL, FALSE);
  660. }
  661. }
  662. return NO_ERROR;
  663. }
  664. //++---------------------------------------------------------------------------*//
  665. // CreateWaitEventBinding //
  666. // creates, initializes and returns a work_item for waitEvent //
  667. // note WT_EVENT_BINDING==WT_WORK_ITEM //
  668. // increments refCount for the EventEntry so that it cannot be deleted //
  669. //------------------------------------------------------------------------------//
  670. PWT_EVENT_BINDING
  671. APIENTRY
  672. CreateWaitEventBinding (
  673. IN PWT_EVENT_ENTRY pee,
  674. IN WORKERFUNCTION pFunction,
  675. IN PVOID pContext,
  676. IN DWORD dwContextSz,
  677. IN BOOL bRunInServerContext
  678. )
  679. {
  680. DWORD dwErr = NO_ERROR;
  681. PWT_WORK_ITEM pWorkItem;
  682. PWAIT_THREAD_ENTRY pwte;
  683. BOOL bErr = TRUE;
  684. // initialize worker threads if not yet done
  685. if (!ENTER_WAIT_API()) {
  686. dwErr = GetLastError();
  687. return NULL;
  688. }
  689. TRACE0(ENTER, "CreateWaitEventBinding:");
  690. do { //breakout loop
  691. //
  692. // allocate work item
  693. //
  694. pWorkItem = WT_MALLOC(sizeof(WT_WORK_ITEM));
  695. if (pWorkItem==NULL) {
  696. dwErr = GetLastError();
  697. TRACE2(
  698. ANY, "error %d allocating %d bytes for work item",
  699. dwErr, sizeof(WT_WORK_ITEM)
  700. );
  701. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  702. break;
  703. }
  704. //
  705. // initialize work item
  706. //
  707. pWorkItem->wi_Function = pFunction;
  708. pWorkItem->wi_Context = pContext;
  709. pWorkItem->wi_ContextSz = dwContextSz;
  710. pWorkItem->wi_RunInServer = bRunInServerContext;
  711. pWorkItem->wiP_ee = pee;
  712. InitializeListHead(&pWorkItem->wi_ServerLinks);
  713. InitializeListHead(&pWorkItem->wi_Links);
  714. pwte = pee->eeP_wte;
  715. if ((pee->ee_Status==0) || (pee->ee_Status==WT_STATUS_DELETED)) {
  716. break;
  717. }
  718. ENTER_CRITICAL_SECTION(&pwte->wte_CS, "wte_CS", "CreateWaitEventBinding");
  719. if ((pee->ee_Status==0) || (pee->ee_Status==WT_STATUS_DELETED)) {
  720. LEAVE_CRITICAL_SECTION(&pwte->wte_CS, "wte_CS",
  721. "CreateWaitEventBinding");
  722. break;
  723. }
  724. LEAVE_CRITICAL_SECTION(&pwte->wte_CS, "wte_CS", "CreateWaitEventBinding");
  725. bErr = FALSE;
  726. } while (FALSE); //breakout loop
  727. if (bErr) {
  728. TRACE1(LEAVE, "Could not CreateWaitEventBinding: %d", dwErr);
  729. FreeWaitEventBinding(pWorkItem);
  730. return NULL;
  731. }
  732. else {
  733. TRACE1(LEAVE, "Leaving CreateWaitEventBinding: %d", NO_ERROR);
  734. return pWorkItem;
  735. }
  736. } //end CreateWaitEventBinding
  737. //++----------------------------------------------------------------------------//
  738. // FreeWaitEventBinding //
  739. // Called by DeleteWaitEventBinding //
  740. // Free an eventBinding entry which has been deregistered(deleted) //
  741. //------------------------------------------------------------------------------//
  742. VOID
  743. FreeWaitEventBinding (
  744. IN PWT_WORK_ITEM pwiWorkItem
  745. )
  746. {
  747. DWORD dwErr;
  748. TRACE0(ENTER, "Entering FreeWaitEventBinding: ");
  749. if (pwiWorkItem==NULL)
  750. return ;
  751. // free context
  752. /*if (pwiWorkItem->wi_ContextSz>0)
  753. WT_FREE_NOT_NULL(pwiWorkItem->wi_Context);*/
  754. // free wt_eventBinding structure
  755. WT_FREE(pwiWorkItem);
  756. TRACE0(LEAVE, "Leaving FreeWaitEventBinding:");
  757. return;
  758. }
  759. //++--------------------------------------------------------------------------------//
  760. // ChangeWaitEventBindingAux //
  761. // called by (De)RegisterWaitEventBinding API //
  762. //----------------------------------------------------------------------------------//
  763. DWORD
  764. ChangeWaitEventBindingAux (
  765. IN BOOL bChangeTypeAdd,
  766. IN PWT_EVENT_BINDING pwiWorkItem
  767. )
  768. {
  769. DWORD dwErr = NO_ERROR;
  770. PWAIT_THREAD_ENTRY pwte;
  771. PWT_EVENT_ENTRY pee;
  772. // get pointer to event entry
  773. pee = pwiWorkItem->wiP_ee;
  774. if (pee==NULL) {
  775. return ERROR_CAN_NOT_COMPLETE; //this error should not occur
  776. }
  777. // get pointer to wait-thread-entry
  778. pwte = pee->eeP_wte;
  779. if (pwte==NULL) { //this error should not occur
  780. return ERROR_CAN_NOT_COMPLETE;
  781. }
  782. //
  783. // lock wait server: insert the binding into change list and wake up server
  784. //
  785. ENTER_CRITICAL_SECTION(&pwte->wte_CS, "wte_CS", "ChangeWaitEventBindingAux");
  786. if (bChangeTypeAdd) {
  787. if ((pee->ee_Status==0) || (pee->ee_Status==WT_STATUS_DELETED)) {
  788. LEAVE_CRITICAL_SECTION(&pwte->wte_CS, "wte_CS",
  789. "CreateWaitEventBindingAux");
  790. return ERROR_CAN_NOT_COMPLETE;
  791. }
  792. pwte->wte_ChangeType = CHANGE_TYPE_BIND_FUNCTION_ADD;
  793. }
  794. else {
  795. pwte->wte_ChangeType = CHANGE_TYPE_BIND_FUNCTION_DELETE;
  796. }
  797. //insert in wte list of wait server thread
  798. pwte->wteP_BindingToChange = pwiWorkItem;
  799. //
  800. // Wake up the server so that it can enter the events and timers of the client
  801. //
  802. SET_EVENT(pwte->wte_ClientNotifyWTEvent, "wte_ClientNotifyWTEvent",
  803. "ChangeWaitEventBindingAux");
  804. // Wait till wait server notifies on completion
  805. //
  806. WAIT_FOR_SINGLE_OBJECT(pwte->wte_WTNotifyClientEvent, INFINITE, "wte_WTNotifyClientEvent", "ChangeWaitEventBindingAux");
  807. //release server lock: wte_CS
  808. LEAVE_CRITICAL_SECTION(&pwte->wte_CS, "wte_CS", "ChangeWaitEventBindingAux");
  809. return NO_ERROR;
  810. } //end ChangeWaitEventBindingAux
  811. //++-----------------------------------------------------------------------------//
  812. // RegisterClientEventBinding:aux //
  813. // Server adds the event binding to the event //
  814. //-------------------------------------------------------------------------------//
  815. DWORD
  816. RegisterClientEventBinding (
  817. IN PWAIT_THREAD_ENTRY pwte
  818. )
  819. {
  820. return ChangeClientEventBindingAux(1, pwte, pwte->wteP_BindingToChange); //server add event binding
  821. }
  822. //++----------------------------------------------------------------------------//
  823. // DeRegisterClientEventBinding:aux //
  824. // Server adds the event binding to the event //
  825. //------------------------------------------------------------------------------//
  826. DWORD
  827. DeRegisterClientEventBinding (
  828. IN PWAIT_THREAD_ENTRY pwte
  829. )
  830. {
  831. return ChangeClientEventBindingAux(0, pwte, pwte->wteP_BindingToChange); //server delete event binding
  832. }
  833. //++----------------------------------------------------------------------------//
  834. // ChangeClientEventBindingAux //
  835. // client has lock on the server. RefCount of event increased when binding created//
  836. //------------------------------------------------------------------------------//
  837. DWORD
  838. ChangeClientEventBindingAux (
  839. IN BOOL bChangeTypeAdd,
  840. IN PWAIT_THREAD_ENTRY pwte,
  841. IN PWT_WORK_ITEM pwi
  842. )
  843. {
  844. PWT_EVENT_ENTRY pee;
  845. // client has verified that the event entry has not been deleted
  846. if (pwi==NULL) // binding cannot be null
  847. return ERROR_CAN_NOT_COMPLETE;
  848. pee = pwi->wiP_ee;
  849. if (bChangeTypeAdd) {
  850. pee->ee_RefCount++;
  851. InsertHeadList(&pee->eeL_wi, &pwi->wi_ServerLinks);
  852. // if count==0 and initial state is active and
  853. if (pee->ee_Status & WT_STATUS_FIRED) {
  854. // queue the work item
  855. DispatchWorkItem(pwi);
  856. }
  857. }
  858. // deleting eventBinding
  859. else {
  860. pee->ee_RefCount --;
  861. RemoveEntryList(&pwi->wi_ServerLinks);
  862. FreeWaitEventBinding(pwi);
  863. // if ee has deleted flag set and RefCount is 0, then complete its deletion
  864. if ( (pee->ee_RefCount==0) && (pee->ee_Status==WT_STATUS_DELETED) ) {
  865. DeleteClientEventComplete(pee, pwte);
  866. }
  867. }
  868. return NO_ERROR;
  869. }
  870. //++----------------------------------------------------------------------------//
  871. // RegisterWaitEventBinding //
  872. //------------------------------------------------------------------------------//
  873. DWORD
  874. APIENTRY
  875. RegisterWaitEventBinding (
  876. IN PWT_EVENT_BINDING pwiWorkItem
  877. )
  878. {
  879. DWORD dwErr = NO_ERROR;
  880. // initialize worker threads if not yet done
  881. if (!ENTER_WAIT_API()) {
  882. dwErr = GetLastError();
  883. return (dwErr == NO_ERROR ? ERROR_CAN_NOT_COMPLETE : dwErr);
  884. }
  885. TRACE0(ENTER, "Entering RegisterWaitEventFunction:");
  886. // call the auxiliary function to add the entry into the server structure and wake it
  887. // the aux function checks if it is running in server context
  888. ChangeWaitEventBindingAux(1,//add
  889. pwiWorkItem
  890. );
  891. TRACE1(LEAVE, "Leaving BindFunctionToWaitEvent: %d", NO_ERROR);
  892. return NO_ERROR;
  893. } //end RegisterWaitEventBinding
  894. //++----------------------------------------------------------------------------//
  895. // DeRegisterWaitEventBindingSelf //
  896. //------------------------------------------------------------------------------//
  897. DWORD
  898. APIENTRY
  899. DeRegisterWaitEventBindingSelf (
  900. IN PWT_EVENT_BINDING pwiWorkItem
  901. )
  902. {
  903. PWAIT_THREAD_ENTRY pwte;
  904. DWORD dwError = NO_ERROR;
  905. PWT_EVENT_ENTRY pee;
  906. TRACE0(ENTER, "Entering DeRegisterWaitEventBindingSelf:");
  907. if (pwiWorkItem==NULL)
  908. return NO_ERROR;
  909. // get pointer to event entry
  910. pee = pwiWorkItem->wiP_ee;
  911. if (pee==NULL) {
  912. return ERROR_CAN_NOT_COMPLETE; //this error should not occur
  913. }
  914. // get pointer to wait-thread-entry
  915. pwte = pee->eeP_wte;
  916. if (pwte==NULL) { //this error should not occur
  917. return ERROR_CAN_NOT_COMPLETE;
  918. }
  919. dwError = ChangeClientEventBindingAux(0, pwte, pwiWorkItem);
  920. TRACE1(LEAVE, "Leaving DeRegisterWaitEventBindingSelf: %d", dwError);
  921. return dwError;
  922. }
  923. //++----------------------------------------------------------------------------//
  924. // DeRegisterWaitEventBinding //
  925. //------------------------------------------------------------------------------//
  926. DWORD
  927. APIENTRY
  928. DeRegisterWaitEventBinding (
  929. IN PWT_EVENT_BINDING pwiWorkItem
  930. )
  931. {
  932. DWORD dwErr = NO_ERROR;
  933. TRACE0(ENTER, "Entering DeRegisterWaitEventBinding:");
  934. // call the auxiliary function to add the entry into the server structure and wake it
  935. dwErr = ChangeWaitEventBindingAux(0,//Delete
  936. pwiWorkItem
  937. );
  938. TRACE1(LEAVE, "Leaving DeRegisterWaitEventBinding: %d", NO_ERROR);
  939. return dwErr;
  940. } //end DeRegisterWaitEventBinding
  941. //++---------------------------------------------------------------------------*//
  942. // CreateWaitTimer //
  943. // creates, initializes and returns a wait timer //
  944. //------------------------------------------------------------------------------//
  945. PWT_TIMER_ENTRY
  946. APIENTRY
  947. CreateWaitTimer (
  948. IN WORKERFUNCTION pFunction,
  949. IN PVOID pContext,
  950. IN DWORD dwContextSz,
  951. IN BOOL bRunInServerContext
  952. )
  953. {
  954. PWT_TIMER_ENTRY pte;
  955. DWORD dwErr;
  956. DWORD bErr = TRUE;
  957. // initialize worker threads if not yet done
  958. if (!ENTER_WAIT_API()) {
  959. dwErr = GetLastError();
  960. return (NULL);
  961. }
  962. TRACE0(ENTER, "Entering CreateWaitTimer: ");
  963. do { // breakout loop
  964. //
  965. // allocate wait-timer structure
  966. //
  967. pte = WT_MALLOC(sizeof(WT_TIMER_ENTRY));
  968. if (pte==NULL) {
  969. dwErr = GetLastError();
  970. TRACE2(
  971. ANY, "error %d allocating %d bytes for wait-timer structure",
  972. dwErr, sizeof(WT_TIMER_ENTRY)
  973. );
  974. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  975. break;
  976. }
  977. //
  978. // initialize fields of the waitTimer
  979. //
  980. SET_TIMER_INFINITE(pte->te_Timeout);
  981. pte->te_Function = pFunction;
  982. pte->te_Context = pContext;
  983. pte->te_ContextSz = dwContextSz;
  984. pte->te_RunInServer = bRunInServerContext;
  985. pte->te_Status = 0;
  986. //serverId, teP_wte and ServerLinks are set when it is registered
  987. InitializeListHead(&pte->te_ServerLinks);
  988. InitializeListHead(&pte->te_Links);
  989. pte->te_Flag = FALSE;
  990. bErr = FALSE;
  991. } while (FALSE); //end breakout loop
  992. if (bErr) {
  993. FreeWaitTimer(pte);
  994. TRACE0(LEAVE, "Leaving CreateWaitTimer: Not Created");
  995. return NULL;
  996. }
  997. else {
  998. TRACE0(LEAVE, "Leaving CreateWaitTimer: Created");
  999. return pte;
  1000. }
  1001. } //end createWaitTimer
  1002. //++---------------------------------------------------------------------------*//
  1003. // FreeWaitTimer //
  1004. // frees memory/handles associated with the waitTimer //
  1005. //------------------------------------------------------------------------------//
  1006. VOID
  1007. FreeWaitTimer (
  1008. IN PWT_TIMER_ENTRY pte
  1009. )
  1010. {
  1011. TRACE0(ENTER, "Entering FreeWaitTimer: ");
  1012. if (pte==NULL)
  1013. return;
  1014. //free context
  1015. //WT_FREE_NOT_NULL(pte->te_Context);
  1016. //free timer structure
  1017. WT_FREE(pte);
  1018. TRACE0(LEAVE, "Leaving FreeWaitTimer:");
  1019. return;
  1020. } //end FreeWaitTimer
  1021. //++---------------------------------------------------------------------------*//
  1022. // CreateWaitEvent //
  1023. // no locks required //
  1024. // creates, initializes and returns a wait event //
  1025. //------------------------------------------------------------------------------//
  1026. PWT_EVENT_ENTRY
  1027. APIENTRY
  1028. CreateWaitEvent (
  1029. IN HANDLE pEvent, // handle to event if already created
  1030. IN LPSECURITY_ATTRIBUTES lpEventAttributes, // pointer to security attributes
  1031. IN BOOL bManualReset,
  1032. IN BOOL bInitialState,
  1033. IN LPCTSTR lpName, // pointer to event-object name
  1034. IN BOOL bHighPriority, // create high priority event
  1035. IN WORKERFUNCTION pFunction, // if null, means will be set by other clients
  1036. IN PVOID pContext, // can be null
  1037. IN DWORD dwContextSz, // size of context: used for allocating context to functions
  1038. // context size can be 0, without context being null
  1039. IN BOOL bRunInServerContext // run in server thread or get dispatched to worker thread
  1040. )
  1041. {
  1042. PWT_EVENT_ENTRY peeEvent;
  1043. PWT_WORK_ITEM pWorkItem;
  1044. DWORD dwErr;
  1045. BOOL bErr = TRUE;
  1046. // initialize worker threads if not yet done
  1047. if (!ENTER_WAIT_API()) {
  1048. dwErr = GetLastError();
  1049. return (NULL);
  1050. }
  1051. TRACE0(ENTER, "Entering CreateWaitEvent: ");
  1052. do { // breakout loop
  1053. //
  1054. // allocate wt_event structure
  1055. //
  1056. peeEvent = WT_MALLOC(sizeof(WT_EVENT_ENTRY));
  1057. if (peeEvent==NULL) {
  1058. dwErr = GetLastError();
  1059. TRACE2(
  1060. ANY, "error %d allocating %d bytes for wait-thread-entry",
  1061. dwErr, sizeof(WT_EVENT_ENTRY)
  1062. );
  1063. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  1064. break;
  1065. }
  1066. //
  1067. // create event
  1068. //
  1069. if (pEvent!=NULL) {
  1070. peeEvent->ee_Event = pEvent;
  1071. peeEvent->ee_bDeleteEvent = FALSE;
  1072. }
  1073. else {
  1074. peeEvent->ee_bDeleteEvent = TRUE;
  1075. peeEvent->ee_Event = CreateEvent(lpEventAttributes, bManualReset,
  1076. bInitialState, lpName);
  1077. if (peeEvent->ee_Event==NULL) {
  1078. WT_FREE(peeEvent);
  1079. peeEvent = NULL;
  1080. dwErr = GetLastError();
  1081. TRACE1(
  1082. ANY, "error %d creating event",
  1083. dwErr
  1084. );
  1085. LOGERR0(CREATE_EVENT_FAILED, dwErr);
  1086. break;
  1087. }
  1088. }
  1089. //
  1090. // initialize fields of wt_event entry
  1091. //
  1092. peeEvent->ee_bManualReset = bManualReset;
  1093. peeEvent->ee_bInitialState = bInitialState;
  1094. peeEvent->ee_Status = 0; // created but not registered
  1095. peeEvent->ee_bHighPriority = bHighPriority;
  1096. // initialize list of work items
  1097. InitializeListHead(&peeEvent->eeL_wi);
  1098. // create work item
  1099. //
  1100. if (pFunction==NULL) {
  1101. // no work item set by this client
  1102. }
  1103. else {
  1104. pWorkItem = WT_MALLOC(sizeof(WT_WORK_ITEM));
  1105. if (pWorkItem==NULL) {
  1106. dwErr = GetLastError();
  1107. TRACE2(
  1108. ANY, "error %d allocating %d bytes for work item",
  1109. dwErr, sizeof(WT_WORK_ITEM)
  1110. );
  1111. LOGERR0(HEAP_ALLOC_FAILED, dwErr);
  1112. break;
  1113. }
  1114. pWorkItem->wi_Function = pFunction;
  1115. pWorkItem->wi_Context = pContext;
  1116. pWorkItem->wi_ContextSz = dwContextSz;
  1117. pWorkItem->wi_RunInServer = bRunInServerContext;
  1118. pWorkItem->wiP_ee = peeEvent; //not required to be set in this case
  1119. InitializeListHead(&pWorkItem->wi_ServerLinks);
  1120. InsertHeadList(&peeEvent->eeL_wi, &pWorkItem->wi_ServerLinks);
  1121. InitializeListHead(&pWorkItem->wi_Links);
  1122. }
  1123. peeEvent->ee_bSignalSingle = FALSE; // signal everyone
  1124. if (pFunction!=NULL)
  1125. peeEvent->ee_bOwnerSelf = TRUE; // currently all events can be shared
  1126. else
  1127. peeEvent->ee_bOwnerSelf = FALSE;
  1128. peeEvent->ee_ArrayIndex = -1; // points to index in events array, when event is active
  1129. //peeEvent->ee_ServerId = 0; // server id is set when it is inserted into wait server
  1130. peeEvent->eeP_wte = NULL;
  1131. InitializeListHead(&peeEvent->ee_ServerLinks);
  1132. InitializeListHead(&peeEvent->ee_Links);
  1133. peeEvent->ee_RefCount = 0; // note: refcount can be 0 and still there can be 1 workItem
  1134. peeEvent->ee_bFlag = FALSE;
  1135. bErr = FALSE;
  1136. } while (FALSE); //end breakout loop
  1137. if (bErr) {
  1138. FreeWaitEvent(peeEvent);
  1139. TRACE0(LEAVE, "Leaving CreateWaitEvent: Not Created");
  1140. return NULL;
  1141. }
  1142. else {
  1143. TRACE0(LEAVE, "Leaving CreateWaitEvent: Created");
  1144. return peeEvent;
  1145. }
  1146. } //end createWaitEvent
  1147. //++----------------------------------------------------------------------------//
  1148. // DeleteClientEvent //
  1149. // Free an event entry which has been deregistered(deleted) //
  1150. // frees all fields of the wait event without touching others //
  1151. // interlockedDecrement(pwte->wte_NumTotalEvents) //
  1152. //------------------------------------------------------------------------------//
  1153. DWORD
  1154. DeleteClientEvent (
  1155. IN PWT_EVENT_ENTRY pee,
  1156. IN PWAIT_THREAD_ENTRY pwte
  1157. )
  1158. {
  1159. DWORD dwErr;
  1160. // can be called when the event has to be deleted or when the last binding is
  1161. // being deleted and the delete flag is set.
  1162. // if event is active Delete from events array
  1163. if ((pee->ee_Status==WT_STATUS_ACTIVE)&&(pee->ee_ArrayIndex!=-1)) {
  1164. DeleteFromEventsArray(pee, pwte);
  1165. pee->ee_Status = WT_STATUS_INACTIVE; // not req
  1166. }
  1167. // does interlocked decrement and sets status to deleted
  1168. DeleteFromEventsList(pee, pwte);
  1169. // decrement the RefCount with the waitThreadEntry
  1170. // free memory and handles assocaited with the wait event entry
  1171. if (pee->ee_RefCount==0) {
  1172. DeleteClientEventComplete(pee, pwte);
  1173. }
  1174. // else DeleteClientEventComplete will be called when last binding is deleted
  1175. return NO_ERROR;
  1176. } //end DeleteWaitEvent
  1177. // complete the deletion of the client eventEntry which could not be completed
  1178. // due to existing bindings
  1179. VOID
  1180. DeleteClientEventComplete (
  1181. IN PWT_EVENT_ENTRY pee,
  1182. IN PWAIT_THREAD_ENTRY pwte
  1183. )
  1184. {
  1185. pwte->wte_RefCount--;
  1186. //todo: do i have to check if wte_refcount==0 and set to deleted
  1187. FreeWaitEvent(pee);
  1188. return;
  1189. }
  1190. //++--------------------------------------------------------------------------------//
  1191. // FreeWaitEvent //
  1192. // Called by DeleteWaitEvent //
  1193. // Free an event entry which has been deregistered(deleted) //
  1194. //----------------------------------------------------------------------------------//
  1195. VOID
  1196. FreeWaitEvent (
  1197. IN PWT_EVENT_ENTRY peeEvent
  1198. )
  1199. {
  1200. PLIST_ENTRY pHead, ple;
  1201. PWT_WORK_ITEM pwi;
  1202. DWORD dwErr;
  1203. DWORD dwNumWorkItems=0;
  1204. TRACE0(ENTER, "Entering FreeWaitEvent: ");
  1205. if (peeEvent==NULL)
  1206. return;
  1207. if (peeEvent->ee_bDeleteEvent)
  1208. CloseHandle(peeEvent->ee_Event);
  1209. // there should be no work items or should have been created as part of this entry
  1210. dwNumWorkItems = GetListLength(&peeEvent->eeL_wi);
  1211. ASSERT((peeEvent->ee_RefCount==0)
  1212. && ((dwNumWorkItems==0)
  1213. || ((dwNumWorkItems==1)&&(peeEvent->ee_bOwnerSelf))
  1214. )
  1215. );
  1216. // free all work items and their context
  1217. // actually there cannot be more than 1 such item at most
  1218. pHead = &peeEvent->eeL_wi;
  1219. for (ple=pHead->Flink; ple!=pHead; ) {
  1220. pwi = CONTAINING_RECORD(ple, WT_WORK_ITEM, wi_ServerLinks);
  1221. if ((pwi->wi_Context!=NULL) && (pwi->wi_ContextSz>0))
  1222. ;
  1223. //WT_FREE(pwi->wi_Context);
  1224. ple = ple->Flink;
  1225. WT_FREE(pwi);
  1226. }
  1227. // free wt_event structure
  1228. WT_FREE(peeEvent);
  1229. TRACE0(LEAVE, "Leaving FreeWaitEvent:");
  1230. return;
  1231. }
  1232. //++--------------------------------------------------------------------------------//
  1233. // DeRegisterClientsEventsTimers //
  1234. // Server DeRegister the client with the wait thread //
  1235. //----------------------------------------------------------------------------------//
  1236. DWORD
  1237. DeRegisterClientEventsTimers (
  1238. IN PWAIT_THREAD_ENTRY pwte
  1239. )
  1240. {
  1241. DWORD dwErr;
  1242. dwErr = ChangeClientEventsTimersAux(0, pwte, pwte->wtePL_EventsToChange,
  1243. pwte->wtePL_TimersToChange); //delete event
  1244. return dwErr;
  1245. }
  1246. //++--------------------------------------------------------------------------------//
  1247. // DeRegisterWaitEventsTimersSelf //
  1248. // DeRegister the client from within its server //
  1249. // Either send in NULL, a proper list, of a single node. dont send a empty header!! //
  1250. //----------------------------------------------------------------------------------//
  1251. DWORD
  1252. APIENTRY
  1253. DeRegisterWaitEventsTimersSelf (
  1254. IN PLIST_ENTRY pLEvents,
  1255. IN PLIST_ENTRY pLTimers
  1256. )
  1257. {
  1258. PWAIT_THREAD_ENTRY pwte;
  1259. DWORD dwError;
  1260. if ((pLEvents==NULL)&&(pLTimers==NULL))
  1261. return NO_ERROR;
  1262. TRACE_ENTER("DeRegisterWaitEventsTimersSelf");
  1263. // get pwte
  1264. if (pLEvents!=NULL) {
  1265. PWT_EVENT_ENTRY pee;
  1266. // the below will work even if there is only one record
  1267. pee = CONTAINING_RECORD(pLEvents->Flink, WT_EVENT_ENTRY, ee_Links);
  1268. pwte = pee->eeP_wte;
  1269. }
  1270. else {
  1271. PWT_TIMER_ENTRY pte;
  1272. if (pLTimers==NULL)
  1273. return NO_ERROR;
  1274. pte = CONTAINING_RECORD(pLTimers->Flink, WT_TIMER_ENTRY, te_Links);
  1275. pwte = pte->teP_wte;
  1276. }
  1277. dwError = ChangeClientEventsTimersAux ( 0, //delete
  1278. pwte, pLEvents, pLTimers);
  1279. TRACE_LEAVE("DeRegisterWaitEventsTimersSelf");
  1280. return dwError;
  1281. }
  1282. //++--------------------------------------------------------------------------------//
  1283. // DeRegisterWaitEventsTimers //
  1284. // DeRegister the client with the wait thread //
  1285. // Either send in NULL, a proper list, of a single node. dont send a empty header!! //
  1286. //----------------------------------------------------------------------------------//
  1287. DWORD
  1288. APIENTRY
  1289. DeRegisterWaitEventsTimers (
  1290. IN PLIST_ENTRY pLEvents,
  1291. IN PLIST_ENTRY pLTimers
  1292. )
  1293. {
  1294. PWAIT_THREAD_ENTRY pwte;
  1295. DWORD dwErr = NO_ERROR;
  1296. if ((pLEvents==NULL)&&(pLTimers==NULL))
  1297. return NO_ERROR;
  1298. TRACE0(ENTER, "Entering : DeRegisterWaitEventsTimers");
  1299. // get pwte
  1300. if (pLEvents!=NULL) {
  1301. PWT_EVENT_ENTRY pee;
  1302. // the below will work even if there is only one record
  1303. pee = CONTAINING_RECORD(pLEvents->Flink, WT_EVENT_ENTRY, ee_Links);
  1304. pwte = pee->eeP_wte;
  1305. }
  1306. else {
  1307. PWT_TIMER_ENTRY pte;
  1308. if (pLTimers==NULL)
  1309. return NO_ERROR;
  1310. pte = CONTAINING_RECORD(pLTimers->Flink, WT_TIMER_ENTRY, te_Links);
  1311. pwte = pte->teP_wte;
  1312. }
  1313. // lock server: wte_CS
  1314. ENTER_CRITICAL_SECTION(&pwte->wte_CS, "wte_CS", "DeRegisterWaitEventsTimers");
  1315. //
  1316. // events/timers to be deleted
  1317. //
  1318. pwte->wte_ChangeType = CHANGE_TYPE_DELETE;
  1319. pwte->wtePL_EventsToChange = pLEvents;
  1320. pwte->wtePL_TimersToChange = pLTimers;
  1321. // Wake up the server so that it can delete the events and timers of the client
  1322. SET_EVENT(pwte->wte_ClientNotifyWTEvent, "wte_ClientNotifyWTEvent", "DeRegisterWaitEventsTimers");
  1323. WAIT_FOR_SINGLE_OBJECT(pwte->wte_WTNotifyClientEvent, INFINITE, "wte_WTNotifyClientEvent", "DeRegisterWaitEventsTimers");
  1324. LEAVE_CRITICAL_SECTION(&pwte->wte_CS, "wte_CS", "DeRegisterWaitEventsTimers");
  1325. TRACE0(LEAVE, "Leaving: DeRegisterWaitEventsTimers");
  1326. return NO_ERROR;
  1327. } //end DeRegisterWaitEventsTimers
  1328. #pragma hdrstop