Leaked source code of windows server 2003
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.

488 lines
12 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name :
  4. wtblobj.c
  5. Abstract:
  6. Manage a list of waitable objects and associated callbacks.
  7. Author:
  8. TadB
  9. Revision History:
  10. --*/
  11. #ifdef TRC_FILE
  12. #undef TRC_FILE
  13. #endif
  14. #define TRC_FILE "_rdsutl"
  15. #include <RemoteDesktop.h>
  16. #include <RemoteDesktopDBG.h>
  17. #include "wtblobj.h"
  18. ////////////////////////////////////////////////////////
  19. //
  20. // Define
  21. //
  22. #define WTBLOBJMGR_MAGICNO 0x57575757
  23. ////////////////////////////////////////////////////////
  24. //
  25. // Local Typedefs
  26. //
  27. typedef struct tagWAITABLEOBJECTMGR
  28. {
  29. #if DBG
  30. DWORD magicNo;
  31. #endif
  32. WTBLOBJ_ClientFunc funcs[MAXIMUM_WAIT_OBJECTS];
  33. HANDLE objects[MAXIMUM_WAIT_OBJECTS];
  34. PVOID clientData[MAXIMUM_WAIT_OBJECTS];
  35. ULONG objectCount;
  36. } WAITABLEOBJECTMGR, *PWAITABLEOBJECTMGR;
  37. static BOOL g_WaitableObjectMgrCSCreated = FALSE;
  38. static CRITICAL_SECTION g_WaitableObjectMgrCS;
  39. static HANDLE g_WakeupPollThreadEvent = NULL;
  40. void
  41. WTBLOBJ_ObjectListChanged(
  42. HANDLE waitableObject,
  43. PVOID clientData
  44. )
  45. /*++
  46. Routine Description:
  47. This routine is called when waitable object list has changed via
  48. WTBLOBJ_DeleteWaitableObjectMgr() or WTBLOBJ_AddWaitableObject().
  49. Arguments:
  50. Refer to WTBLOBJ_ClientFunc.
  51. Return Value:
  52. None.
  53. --*/
  54. {
  55. DC_BEGIN_FN("WTBLOBJ_ObjectListChanged");
  56. ASSERT( waitableObject == g_WakeupPollThreadEvent );
  57. if( FALSE == g_WaitableObjectMgrCSCreated ||
  58. NULL == g_WakeupPollThreadEvent) {
  59. SetLastError( ERROR_INTERNAL_ERROR );
  60. return;
  61. }
  62. // Wait until WTBLOBJ_DeleteWaitableObjectMgr() or
  63. // WTBLOBJ_AddWaitableObject() complete.
  64. EnterCriticalSection( &g_WaitableObjectMgrCS );
  65. ResetEvent( g_WakeupPollThreadEvent );
  66. LeaveCriticalSection( &g_WaitableObjectMgrCS );
  67. DC_END_FN();
  68. return;
  69. }
  70. WTBLOBJMGR
  71. WTBLOBJ_CreateWaitableObjectMgr()
  72. /*++
  73. Routine Description:
  74. Create a new instance of the Waitable Object Manager.
  75. Arguments:
  76. Return Value:
  77. NULL on error. Otherwise, a new Waitable Object Manager is
  78. returned.
  79. --*/
  80. {
  81. PWAITABLEOBJECTMGR objMgr = NULL;
  82. DWORD status = ERROR_SUCCESS;
  83. DC_BEGIN_FN("WTBLOBJ_CreateWaitableObjectMgr");
  84. ASSERT( FALSE == g_WaitableObjectMgrCSCreated );
  85. ASSERT( NULL == g_WakeupPollThreadEvent );
  86. // non-signal, manual reset event to wake up pool thread.
  87. g_WakeupPollThreadEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
  88. if( NULL == g_WakeupPollThreadEvent ) {
  89. goto CLEANUPANDEXIT;
  90. }
  91. __try {
  92. InitializeCriticalSection( &g_WaitableObjectMgrCS );
  93. }
  94. __except( EXCEPTION_EXECUTE_HANDLER ) {
  95. status = GetExceptionCode();
  96. }
  97. if( ERROR_SUCCESS != status ) {
  98. SetLastError( status );
  99. goto CLEANUPANDEXIT;
  100. }
  101. g_WaitableObjectMgrCSCreated = TRUE;
  102. objMgr = ALLOCMEM(sizeof(WAITABLEOBJECTMGR));
  103. if (objMgr != NULL) {
  104. #if DBG
  105. objMgr->magicNo = WTBLOBJMGR_MAGICNO;
  106. #endif
  107. objMgr->objectCount = 0;
  108. memset(&objMgr->objects[0], 0, sizeof(objMgr->objects));
  109. memset(&objMgr->funcs[0], 0, sizeof(objMgr->funcs));
  110. memset(&objMgr->clientData[0], 0, sizeof(objMgr->clientData));
  111. }
  112. else {
  113. status = ERROR_OUTOFMEMORY;
  114. goto CLEANUPANDEXIT;
  115. }
  116. //
  117. // First one in list is our pool thread wakeup event.
  118. //
  119. status = WTBLOBJ_AddWaitableObject(
  120. objMgr,
  121. NULL,
  122. g_WakeupPollThreadEvent,
  123. WTBLOBJ_ObjectListChanged
  124. );
  125. if( ERROR_SUCCESS != status ) {
  126. ASSERT( ERROR_SUCCESS == status );
  127. WTBLOBJ_DeleteWaitableObjectMgr( objMgr );
  128. objMgr = NULL;
  129. SetLastError( status );
  130. }
  131. CLEANUPANDEXIT:
  132. if( status != ERROR_SUCCESS ) {
  133. if( TRUE == g_WaitableObjectMgrCSCreated ) {
  134. DeleteCriticalSection( &g_WaitableObjectMgrCS );
  135. g_WaitableObjectMgrCSCreated = FALSE;
  136. }
  137. if( NULL != g_WakeupPollThreadEvent ) {
  138. CloseHandle( g_WakeupPollThreadEvent );
  139. g_WakeupPollThreadEvent = NULL;
  140. }
  141. }
  142. DC_END_FN();
  143. return objMgr;
  144. }
  145. VOID
  146. WTBLOBJ_DeleteWaitableObjectMgr(
  147. IN WTBLOBJMGR mgr
  148. )
  149. /*++
  150. Routine Description:
  151. Release an instance of the Waitable Object Manager that was
  152. created via a call to WTBLOBJ_CreateWaitableObjectMgr.
  153. Arguments:
  154. mgr - Waitable object manager.
  155. Return Value:
  156. NULL on error. Otherwise, a new Waitable Object Manager is
  157. returned.
  158. --*/
  159. {
  160. PWAITABLEOBJECTMGR objMgr = (PWAITABLEOBJECTMGR)mgr;
  161. DC_BEGIN_FN("WTBLOBJ_DeleteWaitableObjectMgr");
  162. #if DBG
  163. objMgr->magicNo = 0xcccccccc;
  164. #endif
  165. if( NULL != g_WakeupPollThreadEvent ) {
  166. SetEvent( g_WakeupPollThreadEvent );
  167. }
  168. FREEMEM(objMgr);
  169. if( TRUE == g_WaitableObjectMgrCSCreated ) {
  170. DeleteCriticalSection( &g_WaitableObjectMgrCS );
  171. g_WaitableObjectMgrCSCreated = FALSE;
  172. }
  173. if( NULL != g_WakeupPollThreadEvent ) {
  174. CloseHandle( g_WakeupPollThreadEvent );
  175. g_WakeupPollThreadEvent = NULL;
  176. }
  177. DC_END_FN();
  178. }
  179. DWORD
  180. WTBLOBJ_AddWaitableObject(
  181. IN WTBLOBJMGR mgr,
  182. IN PVOID clientData,
  183. IN HANDLE waitableObject,
  184. IN WTBLOBJ_ClientFunc func
  185. )
  186. /*++
  187. Routine Description:
  188. Add a new waitable object to an existing Waitable Object Manager.
  189. Arguments:
  190. mgr - Waitable object manager.
  191. clientData - Associated client data.
  192. waitableObject - Associated waitable object.
  193. func - Completion callback function.
  194. Return Value:
  195. ERROR_SUCCESS on success. Otherwise, a Windows error code is
  196. returned.
  197. --*/
  198. {
  199. ULONG objectCount;
  200. DWORD retCode = ERROR_SUCCESS;
  201. PWAITABLEOBJECTMGR objMgr = (PWAITABLEOBJECTMGR)mgr;
  202. DC_BEGIN_FN("WTBLOBJ_AddWaitableObject");
  203. //
  204. // make sure WTBLOBJ_CreateWaitableObjectMgr() is
  205. // called.
  206. //
  207. ASSERT( TRUE == g_WaitableObjectMgrCSCreated );
  208. ASSERT( NULL != g_WakeupPollThreadEvent );
  209. if( FALSE == g_WaitableObjectMgrCSCreated ||
  210. NULL == g_WakeupPollThreadEvent) {
  211. return ERROR_INTERNAL_ERROR;
  212. }
  213. // wake up pool thread if it is in wait.
  214. SetEvent( g_WakeupPollThreadEvent );
  215. // Wait for ObjectMgr CS or Poll thread to exit
  216. EnterCriticalSection( &g_WaitableObjectMgrCS );
  217. // try/except so if anything goes wrong, we can release CS.
  218. __try {
  219. objectCount = objMgr->objectCount;
  220. //
  221. // Make sure we don't run out of waitable objects. This version
  222. // only supports MAXIMUM_WAIT_OBJECTS waitable objects.
  223. //
  224. if (objectCount < MAXIMUM_WAIT_OBJECTS) {
  225. objMgr->funcs[objectCount] = func;
  226. objMgr->objects[objectCount] = waitableObject;
  227. objMgr->clientData[objectCount] = clientData;
  228. objMgr->objectCount++;
  229. }
  230. else {
  231. retCode = ERROR_INSUFFICIENT_BUFFER;
  232. }
  233. }
  234. __except( EXCEPTION_EXECUTE_HANDLER ) {
  235. retCode = GetExceptionCode();
  236. }
  237. LeaveCriticalSection( &g_WaitableObjectMgrCS );
  238. DC_END_FN();
  239. return retCode;
  240. }
  241. VOID
  242. WTBLOBJ_RemoveWaitableObject(
  243. IN WTBLOBJMGR mgr,
  244. IN HANDLE waitableObject
  245. )
  246. /*++
  247. Routine Description:
  248. Remove a waitable object via a call to WTBLOBJ_AddWaitableObject.
  249. Arguments:
  250. mgr - Waitable object manager.
  251. waitableObject - Associated waitable object.
  252. Return Value:
  253. NA
  254. --*/
  255. {
  256. ULONG offset;
  257. DWORD retCode;
  258. PWAITABLEOBJECTMGR objMgr = (PWAITABLEOBJECTMGR)mgr;
  259. DC_BEGIN_FN("WTBLOBJ_RemoveWaitableObject");
  260. //
  261. // make sure WTBLOBJ_CreateWaitableObjectMgr() is
  262. // called.
  263. //
  264. ASSERT( TRUE == g_WaitableObjectMgrCSCreated );
  265. ASSERT( NULL != g_WakeupPollThreadEvent );
  266. if( FALSE == g_WaitableObjectMgrCSCreated ||
  267. NULL == g_WakeupPollThreadEvent) {
  268. SetLastError( ERROR_INTERNAL_ERROR );
  269. return;
  270. }
  271. // wake up pool thread if it is in wait.
  272. SetEvent( g_WakeupPollThreadEvent );
  273. // Wait for ObjectMgr CS or Poll thread to exit
  274. EnterCriticalSection( &g_WaitableObjectMgrCS );
  275. __try {
  276. //
  277. // Find the waitable object in the list, using a linear search.
  278. //
  279. for (offset=0; offset<objMgr->objectCount; offset++) {
  280. if (objMgr->objects[offset] == waitableObject) {
  281. break;
  282. }
  283. }
  284. if (offset < objMgr->objectCount) {
  285. //
  286. // Move the last items to the now vacant spot and decrement the count.
  287. //
  288. objMgr->objects[offset] = objMgr->objects[objMgr->objectCount - 1];
  289. objMgr->funcs[offset] = objMgr->funcs[objMgr->objectCount - 1];
  290. objMgr->clientData[offset] = objMgr->clientData[objMgr->objectCount - 1];
  291. //
  292. // Clear the unused spot.
  293. //
  294. objMgr->objects[objMgr->objectCount - 1] = NULL;
  295. objMgr->funcs[objMgr->objectCount - 1] = NULL;
  296. objMgr->clientData[objMgr->objectCount - 1] = NULL;
  297. objMgr->objectCount--;
  298. }
  299. }
  300. __except( EXCEPTION_EXECUTE_HANDLER ) {
  301. retCode = GetExceptionCode();
  302. SetLastError( retCode );
  303. }
  304. LeaveCriticalSection( &g_WaitableObjectMgrCS );
  305. DC_END_FN();
  306. }
  307. DWORD
  308. WTBLOBJ_PollWaitableObjects(
  309. WTBLOBJMGR mgr
  310. )
  311. /*++
  312. Routine Description:
  313. Poll the list of waitable objects associated with a
  314. Waitable Object manager, until the next waitable object
  315. is signaled.
  316. Arguments:
  317. waitableObject - Associated waitable object.
  318. Return Value:
  319. ERROR_SUCCESS on success. Otherwise, a Windows error status
  320. is returned.
  321. --*/
  322. {
  323. DWORD waitResult, objectOffset;
  324. DWORD ret = ERROR_SUCCESS;
  325. HANDLE obj;
  326. WTBLOBJ_ClientFunc func;
  327. PVOID clientData;
  328. PWAITABLEOBJECTMGR objMgr = (PWAITABLEOBJECTMGR)mgr;
  329. DC_BEGIN_FN("WTBLOBJ_PollWaitableObjects");
  330. ASSERT( TRUE == g_WaitableObjectMgrCSCreated );
  331. ASSERT( NULL != g_WakeupPollThreadEvent );
  332. if( FALSE == g_WaitableObjectMgrCSCreated ||
  333. NULL == g_WakeupPollThreadEvent ) {
  334. return ERROR_INTERNAL_ERROR;
  335. }
  336. EnterCriticalSection( &g_WaitableObjectMgrCS );
  337. __try {
  338. //
  339. // Wait for all the waitable objects.
  340. //
  341. waitResult = WaitForMultipleObjectsEx(
  342. objMgr->objectCount,
  343. objMgr->objects,
  344. FALSE,
  345. INFINITE,
  346. FALSE
  347. );
  348. // WAIT_OBJECT_0 us defined as 0, compiler will complain '>=' : expression is always true
  349. if ( /* waitResult >= WAIT_OBJECT_0 && */ waitResult < objMgr->objectCount + WAIT_OBJECT_0 ) {
  350. objectOffset = waitResult - WAIT_OBJECT_0;
  351. //
  352. // Call the associated callback.
  353. //
  354. clientData = objMgr->clientData[objectOffset];
  355. func = objMgr->funcs[objectOffset];
  356. obj = objMgr->objects[objectOffset];
  357. func(obj, clientData);
  358. }
  359. else {
  360. ret = GetLastError();
  361. }
  362. }
  363. __except( EXCEPTION_EXECUTE_HANDLER ) {
  364. ret = GetExceptionCode();
  365. }
  366. LeaveCriticalSection( &g_WaitableObjectMgrCS );
  367. DC_END_FN();
  368. return ret;
  369. }