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.

379 lines
9.6 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. swmr.c
  5. Abstract:
  6. This module contains the single-writer, multi-reader semaphore routines
  7. and the lock-list-count routines.
  8. Author:
  9. Jameel Hyder (microsoft!jameelh)
  10. Revision History:
  11. 25 Apr 1992 Initial Version
  12. Notes: Tab stop: 4
  13. --*/
  14. #define FILENUM FILE_SWMR
  15. #include <afp.h>
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text( PAGE, AfpSwmrInitSwmr)
  18. #endif
  19. /*** AfpSwmrInitSwmr
  20. *
  21. * Initialize the access data structure. Involves initialization of the spin
  22. * lock and the shared and exclusive semaphores. All counts are zeroed.
  23. */
  24. VOID FASTCALL FASTCALL
  25. AfpSwmrInitSwmr(
  26. IN OUT PSWMR pSwmr
  27. )
  28. {
  29. #if DBG
  30. pSwmr->Signature = SWMR_SIGNATURE;
  31. #endif
  32. pSwmr->swmr_cOwnedExclusive = 0;
  33. pSwmr->swmr_cExclWaiting = 0;
  34. pSwmr->swmr_cSharedOwners = 0;
  35. pSwmr->swmr_cSharedWaiting = 0;
  36. pSwmr->swmr_ExclusiveOwner = NULL;
  37. KeInitializeSemaphore(&pSwmr->swmr_SharedSem, 0, MAXLONG);
  38. KeInitializeSemaphore(&pSwmr->swmr_ExclSem, 0, MAXLONG);
  39. }
  40. /*** AfpSwmrAcquireShared
  41. *
  42. * Take the semaphore for shared access.
  43. */
  44. VOID FASTCALL
  45. AfpSwmrAcquireShared(
  46. IN PSWMR pSwmr
  47. )
  48. {
  49. NTSTATUS Status;
  50. KIRQL OldIrql;
  51. #ifdef PROFILING
  52. TIME TimeS, TimeE, TimeD;
  53. #endif
  54. ASSERT (VALID_SWMR(pSwmr));
  55. // This should never be called at DISPATCH_LEVEL
  56. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  57. ACQUIRE_SPIN_LOCK(&AfpSwmrLock, &OldIrql);
  58. if ((pSwmr->swmr_cOwnedExclusive > 0) ||
  59. (pSwmr->swmr_cExclWaiting != 0))
  60. {
  61. pSwmr->swmr_cSharedWaiting++;
  62. RELEASE_SPIN_LOCK(&AfpSwmrLock, OldIrql);
  63. DBGPRINT(DBG_COMP_LOCKS, DBG_LEVEL_INFO,
  64. ("AfpSwmrAcquireShared: Blocking for Shared %lx\n", pSwmr));
  65. #ifdef PROFILING
  66. AfpGetPerfCounter(&TimeS);
  67. #endif
  68. do
  69. {
  70. Status = AfpIoWait(&pSwmr->swmr_SharedSem, &FiveSecTimeOut);
  71. if (Status == STATUS_TIMEOUT)
  72. {
  73. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_INFO,
  74. ("AfpSwmrAcquireShared: Timeout Waiting for Shared acess, re-waiting (%lx)\n", pSwmr));
  75. }
  76. } while (Status == STATUS_TIMEOUT);
  77. ASSERT (pSwmr->swmr_cOwnedExclusive == 0);
  78. ASSERT (pSwmr->swmr_cSharedOwners != 0);
  79. #ifdef PROFILING
  80. AfpGetPerfCounter(&TimeE);
  81. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  82. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_SwmrWaitCount);
  83. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_SwmrWaitTime,
  84. TimeD,
  85. &AfpStatisticsLock);
  86. #endif
  87. }
  88. else // Its either free or shared owners are present with no exclusive waiters
  89. {
  90. pSwmr->swmr_cSharedOwners++;
  91. RELEASE_SPIN_LOCK(&AfpSwmrLock, OldIrql);
  92. }
  93. #ifdef PROFILING
  94. AfpGetPerfCounter(&TimeE);
  95. TimeE.QuadPart = -(TimeE.QuadPart);
  96. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_SwmrLockTimeR,
  97. TimeE,
  98. &AfpStatisticsLock);
  99. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_SwmrLockCountR);
  100. #endif
  101. }
  102. /*** AfpSwmrAcquireExclusive
  103. *
  104. * Take the semaphore for exclusive access.
  105. */
  106. VOID FASTCALL
  107. AfpSwmrAcquireExclusive(
  108. IN PSWMR pSwmr
  109. )
  110. {
  111. NTSTATUS Status;
  112. KIRQL OldIrql;
  113. #ifdef PROFILING
  114. TIME TimeS, TimeE, TimeD;
  115. #endif
  116. ASSERT (VALID_SWMR(pSwmr));
  117. // This should never be called at DISPATCH_LEVEL
  118. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  119. ACQUIRE_SPIN_LOCK(&AfpSwmrLock, &OldIrql);
  120. // If the exclusive access is already granted, Check if it is
  121. // the same thread requesting. If so grant it.
  122. if ((pSwmr->swmr_cOwnedExclusive != 0) &&
  123. (pSwmr->swmr_ExclusiveOwner == PsGetCurrentThread()))
  124. {
  125. pSwmr->swmr_cOwnedExclusive ++;
  126. RELEASE_SPIN_LOCK(&AfpSwmrLock, OldIrql);
  127. }
  128. else if ((pSwmr->swmr_cOwnedExclusive > 0) ||
  129. (pSwmr->swmr_cExclWaiting != 0) ||
  130. (pSwmr->swmr_cSharedOwners != 0))
  131. {
  132. pSwmr->swmr_cExclWaiting++;
  133. RELEASE_SPIN_LOCK(&AfpSwmrLock, OldIrql);
  134. DBGPRINT(DBG_COMP_LOCKS, DBG_LEVEL_INFO,
  135. ("AfpSwmrAcquireExclusive: Blocking for exclusive %lx\n", pSwmr));
  136. #ifdef PROFILING
  137. AfpGetPerfCounter(&TimeS);
  138. #endif
  139. do
  140. {
  141. Status = AfpIoWait(&pSwmr->swmr_ExclSem, &FiveSecTimeOut);
  142. if (Status == STATUS_TIMEOUT)
  143. {
  144. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_INFO,
  145. ("AfpSwmrAcquireExclusive: Timeout Waiting for exclusive acess, re-waiting\n"));
  146. }
  147. } while (Status == STATUS_TIMEOUT);
  148. ASSERT (pSwmr->swmr_cOwnedExclusive == 1);
  149. pSwmr->swmr_ExclusiveOwner = PsGetCurrentThread();
  150. #ifdef PROFILING
  151. AfpGetPerfCounter(&TimeE);
  152. TimeD.QuadPart = TimeE.QuadPart - TimeS.QuadPart;
  153. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_SwmrWaitCount);
  154. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_SwmrWaitTime,
  155. TimeD,
  156. &AfpStatisticsLock);
  157. #endif
  158. }
  159. else // it is free
  160. {
  161. pSwmr->swmr_cOwnedExclusive ++;
  162. ASSERT(pSwmr->swmr_ExclusiveOwner == NULL);
  163. pSwmr->swmr_ExclusiveOwner = PsGetCurrentThread();
  164. RELEASE_SPIN_LOCK(&AfpSwmrLock, OldIrql);
  165. }
  166. #ifdef PROFILING
  167. AfpGetPerfCounter(&TimeE);
  168. TimeE.QuadPart = -(TimeE.QuadPart);
  169. INTERLOCKED_ADD_LARGE_INTGR(&AfpServerProfile->perf_SwmrLockTimeW,
  170. TimeE,
  171. &AfpStatisticsLock);
  172. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_SwmrLockCountW);
  173. #endif
  174. }
  175. /*** AfpSwmrRelease
  176. *
  177. * Release the specified access. It is assumed that the current thread had
  178. * called AfpSwmrAcquirexxxAccess() before this is called. If the SWMR is owned
  179. * exclusively, then there cannot possibly be any shared owners active. When releasing
  180. * the swmr, we first check for exclusive waiters before shared waiters.
  181. */
  182. VOID FASTCALL
  183. AfpSwmrRelease(
  184. IN PSWMR pSwmr
  185. )
  186. {
  187. KIRQL OldIrql;
  188. #ifdef PROFILING
  189. TIME Time;
  190. BOOLEAN Exclusive = False;
  191. #endif
  192. BOOLEAN fWasShared=FALSE;
  193. ASSERT (VALID_SWMR(pSwmr));
  194. ACQUIRE_SPIN_LOCK(&AfpSwmrLock, &OldIrql);
  195. if (pSwmr->swmr_cOwnedExclusive > 0)
  196. {
  197. ASSERT((pSwmr->swmr_cSharedOwners == 0) &&
  198. (pSwmr->swmr_ExclusiveOwner == PsGetCurrentThread()));
  199. pSwmr->swmr_cOwnedExclusive--;
  200. if (pSwmr->swmr_cOwnedExclusive == 0)
  201. pSwmr->swmr_ExclusiveOwner = NULL;
  202. #ifdef PROFILING
  203. Exclusive = True;
  204. #endif
  205. }
  206. else if (pSwmr->swmr_cSharedOwners != 0)
  207. {
  208. // Was owned for shared access
  209. pSwmr->swmr_cSharedOwners--;
  210. fWasShared = TRUE;
  211. }
  212. else
  213. {
  214. // Releasing w/o acquiring ?
  215. KeBugCheck(0);
  216. }
  217. // If there are shared owners present then we are done. Else check for any
  218. // waiting shared/exclusive waiters
  219. if ((pSwmr->swmr_cOwnedExclusive == 0) && (pSwmr->swmr_cSharedOwners == 0))
  220. {
  221. if ( (pSwmr->swmr_cExclWaiting) &&
  222. (fWasShared || (!pSwmr->swmr_cSharedWaiting)) )
  223. {
  224. ASSERT(pSwmr->swmr_cOwnedExclusive == 0);
  225. pSwmr->swmr_cOwnedExclusive = 1;
  226. pSwmr->swmr_cExclWaiting--;
  227. DBGPRINT(DBG_COMP_LOCKS, DBG_LEVEL_INFO,
  228. ("AfpSwmrReleasAccess: Waking exclusive waiter %lx\n", pSwmr));
  229. // Wake up the first exclusive waiter. Everybody else coming in will
  230. // see the access is busy.
  231. KeReleaseSemaphore(&pSwmr->swmr_ExclSem,
  232. SEMAPHORE_INCREMENT,
  233. 1,
  234. False);
  235. }
  236. else if (pSwmr->swmr_cSharedWaiting)
  237. {
  238. pSwmr->swmr_cSharedOwners = pSwmr->swmr_cSharedWaiting;
  239. pSwmr->swmr_cSharedWaiting = 0;
  240. DBGPRINT(DBG_COMP_LOCKS, DBG_LEVEL_INFO,
  241. ("AfpSwmrReleasAccess: Waking %d shared owner(s) %lx\n",
  242. pSwmr->swmr_cSharedOwners, pSwmr));
  243. KeReleaseSemaphore(&pSwmr->swmr_SharedSem,
  244. SEMAPHORE_INCREMENT,
  245. pSwmr->swmr_cSharedOwners,
  246. False);
  247. }
  248. }
  249. RELEASE_SPIN_LOCK(&AfpSwmrLock, OldIrql);
  250. #ifdef PROFILING
  251. AfpGetPerfCounter(&Time);
  252. INTERLOCKED_ADD_LARGE_INTGR(Exclusive ?
  253. &AfpServerProfile->perf_SwmrLockTimeW :
  254. &AfpServerProfile->perf_SwmrLockTimeR,
  255. Time,
  256. &AfpStatisticsLock);
  257. #endif
  258. }
  259. /*** AfpSwmrUpgradeAccess
  260. *
  261. * The caller currently has shared access. Upgrade him to exclusive, if possible.
  262. */
  263. BOOLEAN FASTCALL
  264. AfpSwmrUpgradeToExclusive(
  265. IN PSWMR pSwmr
  266. )
  267. {
  268. KIRQL OldIrql;
  269. BOOLEAN RetCode = False; // Assume failed
  270. ASSERT (VALID_SWMR(pSwmr));
  271. ASSERT((pSwmr->swmr_cOwnedExclusive == 0) && (pSwmr->swmr_cSharedOwners != 0));
  272. ACQUIRE_SPIN_LOCK(&AfpSwmrLock, &OldIrql);
  273. if (pSwmr->swmr_cSharedOwners == 1) // Possible if there are no more shared owners
  274. {
  275. pSwmr->swmr_cSharedOwners = 0;
  276. pSwmr->swmr_cOwnedExclusive = 1;
  277. pSwmr->swmr_ExclusiveOwner = PsGetCurrentThread();
  278. RetCode = True;
  279. #ifdef PROFILING
  280. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_SwmrUpgradeCount);
  281. #endif
  282. }
  283. RELEASE_SPIN_LOCK(&AfpSwmrLock, OldIrql);
  284. return RetCode;
  285. }
  286. /*** AfpSwmrDowngradeAccess
  287. *
  288. * The caller currently has exclusive access. Downgrade him to shared.
  289. */
  290. VOID FASTCALL
  291. AfpSwmrDowngradeToShared(
  292. IN PSWMR pSwmr
  293. )
  294. {
  295. KIRQL OldIrql;
  296. int cSharedWaiting;
  297. ASSERT (VALID_SWMR(pSwmr));
  298. ASSERT((pSwmr->swmr_cOwnedExclusive == 1) &&
  299. (pSwmr->swmr_ExclusiveOwner == PsGetCurrentThread()) &&
  300. (pSwmr->swmr_cSharedOwners == 0));
  301. ACQUIRE_SPIN_LOCK(&AfpSwmrLock, &OldIrql);
  302. pSwmr->swmr_cOwnedExclusive = 0;
  303. pSwmr->swmr_ExclusiveOwner = NULL;
  304. pSwmr->swmr_cSharedOwners = 1;
  305. if (cSharedWaiting = pSwmr->swmr_cSharedWaiting)
  306. {
  307. pSwmr->swmr_cSharedOwners += (BYTE)cSharedWaiting;
  308. pSwmr->swmr_cSharedWaiting = 0;
  309. DBGPRINT(DBG_COMP_LOCKS, DBG_LEVEL_INFO,
  310. ("AfpSwmrDowngradeAccess: Waking %d Reader(s) %lx\n",
  311. cSharedWaiting, pSwmr));
  312. KeReleaseSemaphore(&pSwmr->swmr_SharedSem,
  313. SEMAPHORE_INCREMENT,
  314. cSharedWaiting,
  315. False);
  316. }
  317. RELEASE_SPIN_LOCK(&AfpSwmrLock, OldIrql);
  318. #ifdef PROFILING
  319. INTERLOCKED_INCREMENT_LONG(&AfpServerProfile->perf_SwmrDowngradeCount);
  320. #endif
  321. }
  322.