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.

361 lines
7.4 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1992.
  5. //
  6. // File: credlock.cxx
  7. //
  8. // Contents: routines to manage CredLocks
  9. //
  10. //
  11. // Functions: InitCredLocks
  12. // AllocateCredLock
  13. // BlockOnCredLock
  14. // FreeCredLock
  15. //
  16. //
  17. // History: 12-Jan-94 MikeSw Created
  18. //
  19. //--------------------------------------------------------------------------
  20. #include <secpch2.hxx>
  21. #pragma hdrstop
  22. #include <credlist.hxx>
  23. #include "debug.hxx"
  24. //+-------------------------------------------------------------------------
  25. //
  26. // Function: InitCredLocks
  27. //
  28. // Synopsis: Initialize credential lock events
  29. //
  30. // Effects:
  31. //
  32. // Arguments:
  33. //
  34. // Requires:
  35. //
  36. // Returns:
  37. //
  38. // Notes:
  39. //
  40. //--------------------------------------------------------------------------
  41. void
  42. CCredentialList::InitCredLocks(void)
  43. {
  44. ULONG i;
  45. for (i = 0; i < MAX_CRED_LOCKS ; i++ )
  46. {
  47. LockEvents[i].hEvent = 0;
  48. LockEvents[i].fInUse = 0;
  49. LockEvents[i].cRecursion = 0;
  50. LockEvents[i].cWaiters = 0;
  51. }
  52. (void) RtlInitializeCriticalSection(&csLocks);
  53. cLocks = 0;
  54. }
  55. //+-------------------------------------------------------------------------
  56. //
  57. // Function: AllocateCredLock
  58. //
  59. // Synopsis: Allocates and returns a pointer to a credlock.
  60. //
  61. // Effects:
  62. //
  63. // Arguments:
  64. //
  65. // Requires:
  66. //
  67. // Returns:
  68. //
  69. // Notes:
  70. //
  71. //--------------------------------------------------------------------------
  72. PCredLock
  73. CCredentialList::AllocateCredLock(void)
  74. {
  75. NTSTATUS scRet;
  76. ULONG i = 0;
  77. //
  78. // We enter the semaphore here, guarateeing that when we
  79. // exit this wait, there are enough credlocks for Tom's tests
  80. //
  81. WaitForSingleObject(hCredLockSemaphore, INFINITE);
  82. scRet = RtlEnterCriticalSection(&csLocks);
  83. if (!NT_SUCCESS(scRet))
  84. {
  85. DebugOut((DEB_ERROR, "failed allocating a CredLock, %x\n", scRet));
  86. return(NULL);
  87. }
  88. if (cLocks)
  89. {
  90. for (i = 0; i < cLocks ; i++ )
  91. {
  92. if (!(LockEvents[i].fInUse & CREDLOCK_IN_USE))
  93. {
  94. ResetEvent(LockEvents[i].hEvent);
  95. LockEvents[i].fInUse |= CREDLOCK_IN_USE;
  96. LockEvents[i].cRecursion = 0;
  97. (void) RtlLeaveCriticalSection(&csLocks);
  98. return(&LockEvents[i]);
  99. }
  100. }
  101. }
  102. // No free locks, so we create a new one.
  103. if (cLocks == MAX_CRED_LOCKS)
  104. {
  105. DebugOut((DEB_ERROR, "Ran out of CredLocks?\n"));
  106. (void) RtlLeaveCriticalSection(&csLocks);
  107. return(NULL);
  108. }
  109. // This entails creating an event that is anonymous, auto-reset,
  110. // initally not signalled.
  111. LockEvents[cLocks].hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  112. if (LockEvents[cLocks].hEvent == NULL)
  113. {
  114. DebugOut((DEB_ERROR, "Failed creating event, %d\n", GetLastError()));
  115. }
  116. else
  117. {
  118. i = cLocks;
  119. LockEvents[cLocks++].fInUse = CREDLOCK_IN_USE;
  120. }
  121. (void) RtlLeaveCriticalSection(&csLocks);
  122. return(&LockEvents[i]);
  123. }
  124. //+-------------------------------------------------------------------------
  125. //
  126. // Function: FreeCredLock
  127. //
  128. // Synopsis: Releases a credlock
  129. //
  130. // Effects:
  131. //
  132. // Arguments:
  133. //
  134. // Requires:
  135. //
  136. // Returns: TRUE - Remove the lock record from the credential record
  137. // FALSE - Threads waiting; don't remove from cred
  138. //
  139. // Notes:
  140. //
  141. //--------------------------------------------------------------------------
  142. BOOLEAN
  143. CCredentialList::FreeCredLock( PCredLock pLock,
  144. BOOLEAN fFreeCred)
  145. {
  146. NTSTATUS Status;
  147. BOOL bRet = TRUE;
  148. Status = RtlEnterCriticalSection(&csLocks);
  149. DsysAssert( NT_SUCCESS( Status ) );
  150. //
  151. // The trick: If there is a waiter, then the lock is *not* free
  152. // and we set the flag saying the credential is pending delete, so
  153. // their Lock will fail.
  154. //
  155. if (pLock->cWaiters)
  156. {
  157. SetEvent(pLock->hEvent);
  158. bRet = FALSE;
  159. //
  160. // If the credential has been freed, mark that too
  161. //
  162. if (fFreeCred)
  163. {
  164. pLock->fInUse |= CREDLOCK_FREE_PENDING;
  165. }
  166. } else
  167. {
  168. pLock->fInUse &= ~CREDLOCK_IN_USE;
  169. }
  170. // And clear up the thread id field:
  171. pLock->dwThread = 0;
  172. (void) RtlLeaveCriticalSection(&csLocks);
  173. //
  174. // This is true if the lock has actually been freed
  175. // back to the credlock pool.
  176. //
  177. if (bRet)
  178. {
  179. ReleaseSemaphore(hCredLockSemaphore, 1, NULL);
  180. }
  181. return(bRet);
  182. }
  183. //+-------------------------------------------------------------------------
  184. //
  185. // Function: BlockOnCredLock
  186. //
  187. // Synopsis: Blocks a thread on a credlock.
  188. //
  189. // Effects:
  190. //
  191. // Arguments:
  192. //
  193. // Requires: credentials be blocked for write
  194. //
  195. // Returns:
  196. //
  197. // Notes:
  198. //
  199. //--------------------------------------------------------------------------
  200. BOOLEAN
  201. CCredentialList::BlockOnCredLock(PCredLock pLock)
  202. {
  203. NTSTATUS Status;
  204. DWORD WaitRet;
  205. BOOLEAN bRet = TRUE;
  206. Status = RtlEnterCriticalSection(&csLocks);
  207. DsysAssertMsg(Status == STATUS_SUCCESS, "Critical section csLocks") ;
  208. DebugOut((DEB_TRACE,"Blocking for lock on thread 0x%x\n",pLock->dwThread));
  209. #if DBG
  210. if (pLock->cWaiters < 4)
  211. pLock->WaiterIds[pLock->cWaiters++] = GetCurrentThreadId();
  212. else
  213. pLock->cWaiters++;
  214. #else
  215. pLock->cWaiters++;
  216. #endif
  217. (void) RtlLeaveCriticalSection(&csLocks);
  218. //
  219. // Unlock the list, so that other threads can unlock the credentials
  220. //
  221. rCredentials.Release();
  222. //
  223. // Wait for 100s, or until signalled:
  224. //
  225. WaitRet = WaitForSingleObject(pLock->hEvent, 600000L);
  226. //
  227. // Reacquire exclusive access to the credlock
  228. //
  229. RtlEnterCriticalSection(&csLocks);
  230. if (WaitRet)
  231. {
  232. if (WaitRet == WAIT_TIMEOUT)
  233. {
  234. #if DBG
  235. DebugOut((DEB_ERROR, "Timeout waiting for credlock %x (600s)\n",
  236. pLock));
  237. DebugOut((DEB_ERROR, "Thread 0x%x still owns the lock, revoking\n",
  238. pLock->dwThread));
  239. pLock->dwThread = 0;
  240. #endif // DBG
  241. //
  242. // Blow away any recursion
  243. //
  244. pLock->cRecursion = 0;
  245. }
  246. }
  247. #if DBG
  248. //
  249. // Remove our thread ID from the waiter list:
  250. //
  251. {
  252. int i;
  253. for (i = 0 ; i < 4 ; i++ )
  254. {
  255. if (pLock->WaiterIds[i] == GetCurrentThreadId())
  256. {
  257. int j;
  258. for (j = i; j < 4 - 1 ; j++ )
  259. {
  260. pLock->WaiterIds[j] = pLock->WaiterIds[j+1];
  261. }
  262. pLock->WaiterIds[4 - 1] = 0;
  263. }
  264. }
  265. }
  266. #endif // DBG
  267. pLock->cWaiters--;
  268. if (pLock->fInUse & CREDLOCK_FREE_PENDING)
  269. {
  270. if (pLock->cWaiters == 0)
  271. {
  272. pLock->fInUse &= ~(CREDLOCK_IN_USE | CREDLOCK_FREE_PENDING);
  273. }
  274. bRet = FALSE;
  275. }
  276. //
  277. // Done partying with locks
  278. //
  279. RtlLeaveCriticalSection(&csLocks);
  280. //
  281. // If the credlock needs to be freed, signal the semaphore to
  282. // put it back in the pool.
  283. //
  284. if (!bRet && (pLock->cWaiters == 0))
  285. {
  286. ReleaseSemaphore(hCredLockSemaphore, 1, NULL);
  287. }
  288. //
  289. // Regain exclusive access to the credential list
  290. //
  291. rCredentials.GetWrite();
  292. return(bRet);
  293. }