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.

654 lines
15 KiB

  1. //============================================================================
  2. // Copyright (c) 1995, Microsoft Corporation
  3. //
  4. // File: sync.c
  5. //
  6. // History:
  7. // V Raman July-11-1997 Created.
  8. //
  9. // Basic locking operations. Borrowed from RIP implementation by abolade
  10. //============================================================================
  11. #include "pchmgm.h"
  12. #pragma hdrstop
  13. //----------------------------------------------------------------------------
  14. // Function: QueueMgmWorker
  15. //
  16. // This function is called to queue a MGM function in a safe fashion;
  17. // if cleanup is in progress or if MGM has stopped, this function
  18. // discards the work-item.
  19. //----------------------------------------------------------------------------
  20. DWORD
  21. QueueMgmWorker(
  22. WORKERFUNCTION pFunction,
  23. PVOID pContext
  24. ) {
  25. DWORD dwErr;
  26. ENTER_GLOBAL_SECTION();
  27. if (ig.imscStatus != IPMGM_STATUS_RUNNING) {
  28. //
  29. // cannot queue a work function when MGM has quit or is quitting
  30. //
  31. dwErr = ERROR_CAN_NOT_COMPLETE;
  32. }
  33. else {
  34. ++ig.lActivityCount;
  35. dwErr = RtlQueueWorkItem(pFunction, pContext, 0);
  36. if (dwErr != STATUS_SUCCESS) { --ig.lActivityCount; }
  37. }
  38. LEAVE_GLOBAL_SECTION();
  39. return dwErr;
  40. }
  41. //----------------------------------------------------------------------------
  42. // Function: EnterMgmAPI
  43. //
  44. // This function is called to when entering a MGM api, as well as
  45. // when entering the input thread and timer thread.
  46. // It checks to see if MGM has stopped, and if so it quits; otherwise
  47. // it increments the count of active threads.
  48. //----------------------------------------------------------------------------
  49. BOOL
  50. EnterMgmAPI(
  51. ) {
  52. BOOL bEntered;
  53. ENTER_GLOBAL_SECTION();
  54. if (ig.imscStatus == IPMGM_STATUS_RUNNING) {
  55. //
  56. // MGM is running, so the API may continue
  57. //
  58. ++ig.lActivityCount;
  59. bEntered = TRUE;
  60. }
  61. else {
  62. //
  63. // MGM is not running, so the API exits quietly
  64. //
  65. bEntered = FALSE;
  66. }
  67. LEAVE_GLOBAL_SECTION();
  68. return bEntered;
  69. }
  70. //----------------------------------------------------------------------------
  71. // Function: EnterMgmWorker
  72. //
  73. // This function is called when entering a MGM worker-function.
  74. // Since there is a lapse between the time a worker-function is queued
  75. // and the time the function is actually invoked by a worker thread,
  76. // this function must check to see if MGM has stopped or is stopping;
  77. // if this is the case, then it decrements the activity count,
  78. // releases the activity semaphore, and quits.
  79. //----------------------------------------------------------------------------
  80. BOOL
  81. EnterMgmWorker(
  82. ) {
  83. BOOL bEntered;
  84. ENTER_GLOBAL_SECTION();
  85. if (ig.imscStatus == IPMGM_STATUS_RUNNING) {
  86. //
  87. // MGM is running, so the function may continue
  88. //
  89. bEntered = TRUE;
  90. }
  91. else
  92. if (ig.imscStatus == IPMGM_STATUS_STOPPING) {
  93. //
  94. // MGM is not running, but it was, so the function must stop.
  95. //
  96. --ig.lActivityCount;
  97. ReleaseSemaphore(ig.hActivitySemaphore, 1, NULL);
  98. bEntered = FALSE;
  99. }
  100. else {
  101. //
  102. // MGM probably never started. quit quietly
  103. //
  104. bEntered = FALSE;
  105. }
  106. LEAVE_GLOBAL_SECTION();
  107. return bEntered;
  108. }
  109. //----------------------------------------------------------------------------
  110. // Function: LeaveMgmWorker
  111. //
  112. // This function is called when leaving a MGM API or worker function.
  113. // It decrements the activity count, and if it detects that MGM has stopped
  114. // or is stopping, it releases the activity semaphore.
  115. //----------------------------------------------------------------------------
  116. VOID
  117. LeaveMgmWorker(
  118. ) {
  119. ENTER_GLOBAL_SECTION();
  120. --ig.lActivityCount;
  121. if (ig.imscStatus == IPMGM_STATUS_STOPPING) {
  122. ReleaseSemaphore(ig.hActivitySemaphore, 1, NULL);
  123. }
  124. LEAVE_GLOBAL_SECTION();
  125. }
  126. //----------------------------------------------------------------------------
  127. // CreateReadWriteLock
  128. //
  129. // This function is called to create and initialize a new read-write lock
  130. // structure. It is invoked by AcquireXLock ( X = { Read | Write } )
  131. //----------------------------------------------------------------------------
  132. DWORD
  133. CreateReadWriteLock(
  134. IN OUT PMGM_READ_WRITE_LOCK * ppmrwl
  135. )
  136. {
  137. DWORD dwErr;
  138. PMGM_READ_WRITE_LOCK pmrwl;
  139. TRACELOCK1( "ENTERED CreateReadWriteLock : %x", ppmrwl );
  140. do
  141. {
  142. *ppmrwl = NULL;
  143. //
  144. // Allocate a lock structure
  145. //
  146. pmrwl = MGM_ALLOC( sizeof( MGM_READ_WRITE_LOCK ) );
  147. if ( pmrwl == NULL )
  148. {
  149. dwErr = GetLastError();
  150. TRACE1(
  151. ANY, "CreateReadWriteLock failed to allocate lock : %x", dwErr
  152. );
  153. break;
  154. }
  155. //
  156. // Init. critcal section
  157. //
  158. try
  159. {
  160. InitializeCriticalSection( &pmrwl-> csReaderWriterBlock );
  161. }
  162. except ( EXCEPTION_EXECUTE_HANDLER )
  163. {
  164. dwErr = GetLastError();
  165. MGM_FREE( pmrwl );
  166. TRACE1(
  167. ANY,
  168. "CreateReadWriteLock failed to initialize critical section : %x",
  169. dwErr
  170. );
  171. break;
  172. }
  173. //
  174. // create reader done event.
  175. //
  176. pmrwl-> hReaderDoneEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  177. if ( pmrwl-> hReaderDoneEvent == NULL )
  178. {
  179. dwErr = GetLastError();
  180. MGM_FREE( pmrwl );
  181. TRACE1(
  182. ANY,
  183. "CreateReadWriteLock failed to create event : %x",
  184. dwErr
  185. );
  186. break;
  187. }
  188. //
  189. // initialize count fields
  190. //
  191. pmrwl-> lUseCount = 0;
  192. pmrwl-> lReaderCount = 0;
  193. pmrwl-> sleLockList.Next = NULL;
  194. *ppmrwl = pmrwl;
  195. dwErr = NO_ERROR;
  196. } while ( FALSE );
  197. TRACELOCK1( "LEAVING CreateReadWriteLock : %x", dwErr );
  198. return dwErr;
  199. }
  200. //----------------------------------------------------------------------------
  201. // DeleteReadWriteLock
  202. //
  203. // This functions destroys a read-write lock. It is invoked when MGM is
  204. // being stopped. During normal operation when a read-write lock is no longer
  205. // required it pushed onto a global stack of locks for reuse as needed.
  206. //----------------------------------------------------------------------------
  207. VOID
  208. DeleteReadWriteLock(
  209. IN PMGM_READ_WRITE_LOCK pmrwl
  210. )
  211. {
  212. DeleteCriticalSection( &pmrwl-> csReaderWriterBlock );
  213. CloseHandle( pmrwl-> hReaderDoneEvent );
  214. MGM_FREE( pmrwl );
  215. }
  216. //----------------------------------------------------------------------------
  217. // DeleteLockList
  218. //
  219. // This function deletes the entire list of locks present in the stack of
  220. // read write locks. Assumes stack of locks is locked.
  221. //----------------------------------------------------------------------------
  222. VOID
  223. DeleteLockList(
  224. )
  225. {
  226. PSINGLE_LIST_ENTRY psle = NULL;
  227. PMGM_READ_WRITE_LOCK pmrwl = NULL;
  228. TRACELOCK0( "ENTERED DeleteLockList" );
  229. ENTER_GLOBAL_LOCK_LIST_SECTION();
  230. psle = PopEntryList( &ig.llStackOfLocks.sleHead );
  231. while ( psle != NULL )
  232. {
  233. pmrwl = CONTAINING_RECORD( psle, MGM_READ_WRITE_LOCK, sleLockList );
  234. DeleteReadWriteLock( pmrwl );
  235. psle = PopEntryList( &ig.llStackOfLocks.sleHead );
  236. }
  237. LEAVE_GLOBAL_LOCK_LIST_SECTION();
  238. TRACELOCK0( "LEAVING DeleteLockList");
  239. }
  240. //----------------------------------------------------------------------------
  241. // AcquireReadLock
  242. //
  243. // This function provides read access to a protected resource. If needed
  244. // it will reuse a lock from the stack of locks if available or allocate a
  245. // new read-write lock.
  246. //----------------------------------------------------------------------------
  247. DWORD
  248. AcquireReadLock(
  249. IN OUT PMGM_READ_WRITE_LOCK * ppmrwl
  250. )
  251. {
  252. DWORD dwErr = NO_ERROR;
  253. PSINGLE_LIST_ENTRY psle = NULL;
  254. //
  255. // determine if a lock needs to be allocated first.
  256. // Perform this check with in a critical section so
  257. // that two locks are not concurrently
  258. // assigned to a single resource.
  259. //
  260. ENTER_GLOBAL_LOCK_LIST_SECTION();
  261. if ( *ppmrwl == NULL )
  262. {
  263. //
  264. // get a lock from the stack of locks
  265. //
  266. psle = PopEntryList( &ig.llStackOfLocks.sleHead );
  267. if ( psle != NULL )
  268. {
  269. *ppmrwl = CONTAINING_RECORD(
  270. psle, MGM_READ_WRITE_LOCK, sleLockList
  271. );
  272. }
  273. else
  274. {
  275. //
  276. // Stack of locks was empty. Create a new lock
  277. //
  278. dwErr = CreateReadWriteLock( ppmrwl );
  279. if ( dwErr != NO_ERROR )
  280. {
  281. //
  282. // failed to create a lock. Possibly ran out of resources
  283. //
  284. LEAVE_GLOBAL_LOCK_LIST_SECTION();
  285. TRACE2(
  286. ANY, "LEAVING AcquireReadLock, lock %x, error %x",
  287. ppmrwl, dwErr
  288. );
  289. return dwErr;
  290. }
  291. }
  292. }
  293. //
  294. // *ppmrwl points to a valid lock structure.
  295. //
  296. InterlockedIncrement( &( (*ppmrwl)-> lUseCount ) );
  297. TRACECOUNT1( "AcquireReadLock, Users %d", (*ppmrwl)-> lUseCount );
  298. LEAVE_GLOBAL_LOCK_LIST_SECTION();
  299. //
  300. // Increment reader count
  301. //
  302. EnterCriticalSection( &( (*ppmrwl)-> csReaderWriterBlock ) );
  303. InterlockedIncrement( &( (*ppmrwl)-> lReaderCount ) );
  304. TRACECOUNT1( "Readers %d", (*ppmrwl)-> lReaderCount );
  305. LeaveCriticalSection( &( (*ppmrwl)-> csReaderWriterBlock ) );
  306. return NO_ERROR;
  307. }
  308. //----------------------------------------------------------------------------
  309. // ReleaseReadLock
  310. //
  311. // This function is invoked to release read access to a protected resource.
  312. // If there are no more reader/writers waiting on this lock, the read-write
  313. // lock is released to the global stack of locks for later reuse.
  314. //----------------------------------------------------------------------------
  315. VOID
  316. ReleaseReadLock(
  317. IN OUT PMGM_READ_WRITE_LOCK * ppmrwl
  318. )
  319. {
  320. //
  321. // Decrement reader count, and signal any waiting writer
  322. //
  323. if ( InterlockedDecrement( &( (*ppmrwl)-> lReaderCount ) ) < 0 )
  324. {
  325. SetEvent( (*ppmrwl)-> hReaderDoneEvent );
  326. }
  327. //
  328. // determine if the lock is being used. If not the lock should be
  329. // released to the stack of locks.
  330. //
  331. ENTER_GLOBAL_LOCK_LIST_SECTION();
  332. if ( InterlockedDecrement( &( (*ppmrwl)-> lUseCount ) ) == 0 )
  333. {
  334. PushEntryList( &ig.llStackOfLocks.sleHead, &( (*ppmrwl)-> sleLockList ) );
  335. *ppmrwl = NULL;
  336. TRACECOUNT0( "ReleaseReadLock no more users" );
  337. }
  338. else
  339. {
  340. TRACECOUNT2(
  341. "ReleaseReadLock, Readers %x, users %x",
  342. (*ppmrwl)-> lReaderCount, (*ppmrwl)-> lUseCount
  343. );
  344. }
  345. LEAVE_GLOBAL_LOCK_LIST_SECTION();
  346. }
  347. //----------------------------------------------------------------------------
  348. // AcquireWriteLock
  349. //
  350. // This function provides write access to a protected resource. If needed
  351. // it will reuse a lock from the stack of locks if available or allocate a
  352. // new read-write lock.
  353. //----------------------------------------------------------------------------
  354. DWORD
  355. AcquireWriteLock(
  356. IN OUT PMGM_READ_WRITE_LOCK * ppmrwl
  357. )
  358. {
  359. DWORD dwErr = NO_ERROR;
  360. PSINGLE_LIST_ENTRY psle = NULL;
  361. //
  362. // determine is the you need to allocate a lock first. If needed
  363. // do so under mutual exclusive so that two locks are not
  364. // concurrently assigned for the same resources.
  365. //
  366. ENTER_GLOBAL_LOCK_LIST_SECTION();
  367. if ( *ppmrwl == NULL )
  368. {
  369. //
  370. // get a lock from the stack of locks
  371. //
  372. psle = PopEntryList( &ig.llStackOfLocks.sleHead );
  373. if ( psle != NULL )
  374. {
  375. *ppmrwl = CONTAINING_RECORD(
  376. psle,
  377. MGM_READ_WRITE_LOCK,
  378. sleLockList
  379. );
  380. }
  381. else
  382. {
  383. //
  384. // Stack of locks was empty. Create a new lock
  385. //
  386. dwErr = CreateReadWriteLock( ppmrwl );
  387. if ( dwErr != NO_ERROR )
  388. {
  389. LEAVE_GLOBAL_LOCK_LIST_SECTION();
  390. return dwErr;
  391. }
  392. }
  393. }
  394. //
  395. // *ppmrwl points to a valid lock structure.
  396. //
  397. InterlockedIncrement( &( (*ppmrwl)-> lUseCount ) );
  398. TRACECOUNT1( "AcquireWriteLock, Users %d", (*ppmrwl)-> lUseCount );
  399. LEAVE_GLOBAL_LOCK_LIST_SECTION();
  400. //
  401. // acquire write lock.
  402. //
  403. EnterCriticalSection( &( (*ppmrwl)-> csReaderWriterBlock ) );
  404. if ( InterlockedDecrement( &( (*ppmrwl)-> lReaderCount ) ) >= 0 )
  405. {
  406. //
  407. // other readers present. Wait for them to finish
  408. //
  409. TRACECOUNT1( "AcquireWriteLock, Readers %d", (*ppmrwl)-> lReaderCount );
  410. WaitForSingleObject( (*ppmrwl)-> hReaderDoneEvent, INFINITE );
  411. }
  412. return dwErr;
  413. }
  414. //----------------------------------------------------------------------------
  415. // ReleaseWriteLock
  416. //
  417. // This function is invoked to release write access to a protected resource.
  418. // If there are no more reader/writers waiting on this lock, the read-write
  419. // lock is released to the global stack of locks for later reuse.
  420. //----------------------------------------------------------------------------
  421. VOID
  422. ReleaseWriteLock(
  423. IN OUT PMGM_READ_WRITE_LOCK * ppmrwl
  424. )
  425. {
  426. //
  427. // release the write lock
  428. //
  429. (*ppmrwl)-> lReaderCount = 0;
  430. LeaveCriticalSection( &( (*ppmrwl)-> csReaderWriterBlock ) );
  431. //
  432. // determine if the lock is being used by anyone else.
  433. // if not we need to release the lock back to the stack.
  434. //
  435. ENTER_GLOBAL_LOCK_LIST_SECTION();
  436. if ( InterlockedDecrement( &( (*ppmrwl)-> lUseCount ) ) == 0 )
  437. {
  438. PushEntryList( &ig.llStackOfLocks.sleHead, &( (*ppmrwl)-> sleLockList ) );
  439. *ppmrwl = NULL;
  440. TRACECOUNT0( "ReleaseWriteLock no more users" );
  441. }
  442. else
  443. {
  444. TRACECOUNT2(
  445. "ReleaseWriteLock, Readers %x, users %x",
  446. (*ppmrwl)-> lReaderCount, (*ppmrwl)-> lUseCount
  447. );
  448. }
  449. LEAVE_GLOBAL_LOCK_LIST_SECTION();
  450. }