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.

555 lines
17 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. locker.c
  5. Abstract:
  6. Routines for managing the locker node of the GUM component.
  7. Author:
  8. John Vert (jvert) 17-Apr-1996
  9. Revision History:
  10. --*/
  11. #include "gump.h"
  12. DWORD
  13. GumpDoLockingUpdate(
  14. IN GUM_UPDATE_TYPE Type,
  15. IN DWORD NodeId,
  16. OUT LPDWORD Sequence,
  17. OUT LPDWORD pdwGenerationNum
  18. )
  19. /*++
  20. Routine Description:
  21. Waits for the GUM lock, captures the sequence number, and issues
  22. the update on the current node.
  23. Arguments:
  24. Type - Supplies the type of update
  25. NodeId - Supplies the node id of the locking node.
  26. Sequence - Returns the sequence number the update will be issued with
  27. Return Value:
  28. ERROR_SUCCESS if successful
  29. Win32 error code otherwise
  30. --*/
  31. {
  32. PGUM_INFO GumInfo;
  33. CL_ASSERT(Type < GumUpdateMaximum);
  34. GumInfo = &GumTable[Type];
  35. ClRtlLogPrint(LOG_NOISE,"[GUM] Thread 0x%1!x! UpdateLock wait on Type %2!u!\n", GetCurrentThreadId(), Type);
  36. //
  37. // Acquire the critical section and see if a GUM update is in progress.
  38. //
  39. EnterCriticalSection(&GumpLock);
  40. EnterCriticalSection(&GumpUpdateLock);
  41. //SS: instead of protecting this with GumpLock, I could simply protect
  42. //GumNodeGeneration with GumpUpdateLock and remove GumpLock from here and
  43. //add it to the sync handler. Chittur, Comments??
  44. //SS: Actually, I am not sure why we cant fold GumpLock and GumpUpdate lock
  45. //into one lock
  46. //because the session cleanup is not synchronized with regroup
  47. //and there is no hold-io and release-io
  48. if (GumpLockerNode != NmLocalNodeId)
  49. {
  50. ClRtlLogPrint(LOG_NOISE,
  51. "[GUM] GumpDoLockingUpdate: I, node id %1!d!, am not the locker any more\r\n",
  52. NmLocalNodeId);
  53. LeaveCriticalSection(&GumpLock);
  54. LeaveCriticalSection(&GumpUpdateLock);
  55. return(ERROR_CLUSTER_GUM_NOT_LOCKER);
  56. }
  57. if (GumpLockingNode == -1) {
  58. //
  59. // Nobody owns the lock, therefore we can acquire it and continue immediately.
  60. // There should also be no waiters.
  61. //
  62. CL_ASSERT(IsListEmpty(&GumpLockQueue));
  63. ClRtlLogPrint(LOG_NOISE,
  64. "[GUM] GumpDoLockingUpdate: lock was free, granted to %1!d!\n",
  65. NodeId);
  66. GumpLockingNode = NodeId;
  67. *pdwGenerationNum = GumNodeGeneration[NodeId];
  68. LeaveCriticalSection(&GumpLock);
  69. LeaveCriticalSection(&GumpUpdateLock);
  70. } else {
  71. GUM_WAITER WaitBlock;
  72. //
  73. // Another node owns the lock. Put ourselves onto the GUM lock queue and
  74. // release the critical section.
  75. //
  76. ClRtlLogPrint(LOG_NOISE,"[GUM] GumpDoLockingUpdate: waiting.\n");
  77. WaitBlock.WaitType = GUM_WAIT_SYNC;
  78. WaitBlock.NodeId = NodeId;
  79. WaitBlock.Sync.WakeEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
  80. CL_ASSERT(WaitBlock.Sync.WakeEvent != NULL);
  81. InsertTailList(&GumpLockQueue, &WaitBlock.ListEntry);
  82. LeaveCriticalSection(&GumpLock);
  83. LeaveCriticalSection(&GumpUpdateLock);
  84. //
  85. // We are on the GUM queue, so just wait for the unlocker to wake
  86. // us up. When we are woken up, we will have ownership of the GUM
  87. // lock.
  88. //
  89. WaitForSingleObject(WaitBlock.Sync.WakeEvent,INFINITE);
  90. *pdwGenerationNum = WaitBlock.GenerationNum; //waitblock contains the generation number of this node wrt to locker when it obtains the lock
  91. CloseHandle(WaitBlock.Sync.WakeEvent);
  92. CL_ASSERT(GumpLockingNode == NodeId);
  93. ClRtlLogPrint(LOG_NOISE,
  94. "[GUM] GumpDoLockingUpdate : waiter awakened, lock granted to %1!d!\n",
  95. NodeId);
  96. }
  97. *Sequence = GumpSequence;
  98. ClRtlLogPrint(LOG_NOISE,
  99. "[GUM] GumpDoLockingUpdate successful, Sequence=%1!u! Generation=%2!u!\n",
  100. *Sequence, *pdwGenerationNum);
  101. return(ERROR_SUCCESS);
  102. }
  103. #ifdef GUM_POST_SUPPORT
  104. John Vert (jvert) 11/18/1996
  105. POST is disabled for now since nobody uses it.
  106. DWORD
  107. GumpDoLockingPost(
  108. IN GUM_UPDATE_TYPE Type,
  109. IN LONG NodeId,
  110. OUT LPDWORD Sequence,
  111. IN DWORD Context,
  112. IN DWORD LockerNodeId,
  113. IN DWORD BufferLength,
  114. IN DWORD BufferPtr,
  115. IN UCHAR Buffer[]
  116. )
  117. /*++
  118. Routine Description:
  119. Posts an update.
  120. If the GUM lock can be immediately acquired, this routine
  121. behaves exactly like GumpDoLockingUpdate and returns
  122. ERROR_SUCCESS.
  123. If the GUM lock is held, this routine queues an asynchronous
  124. wait block onto the GUM queue and returns ERROR_IO_PENDING.
  125. When the wait block is removed from the GUM queue, the unlocking
  126. thread will call GumpDeliverPostUpdate on the specified node
  127. and supply the passed in context. The calling node can then
  128. deliver the update.
  129. Arguments:
  130. Type - Supplies the type of update
  131. NodeId - Supplies the node id of the locking node.
  132. Context - Supplies a DWORD context to be used by the post callback.
  133. Sequence - Returns the sequence number the update will be issued with.
  134. This is only valid if ERROR_SUCCESS is returned.
  135. Context - Supplies a DWORD context to be used by the post callback.
  136. BufferLength - Supplies the length of the buffer to be used by the post callback
  137. BufferPtr - Supplies the pointer to the actual data on the originating node.
  138. Buffer - Supplies a pointer to the buffer to be used by the post callback.
  139. Return Value:
  140. ERROR_SUCCESS if the lock was immediately acquired.
  141. ERROR_IO_PENDING if the request was queued and the caller will be called back.
  142. --*/
  143. {
  144. PGUM_INFO GumInfo;
  145. PGUM_WAITER WaitBlock;
  146. CL_ASSERT(Type < GumUpdateMaximum);
  147. GumInfo = &GumTable[Type];
  148. ClRtlLogPrint(LOG_NOISE,"[GUM] Thread 0x%1!x! UpdateLock post on Type %2!u!\n", GetCurrentThreadId(), Type);
  149. //
  150. // Acquire the critical section and see if a GUM update is in progress.
  151. //
  152. EnterCriticalSection(&GumpUpdateLock);
  153. if (GumpLockingNode == -1) {
  154. //
  155. // Nobody owns the lock, therefore we can acquire it and continue immediately.
  156. // There should also be no waiters.
  157. //
  158. CL_ASSERT(IsListEmpty(&GumpLockQueue));
  159. ClRtlLogPrint(LOG_NOISE,"[GUM] PostLockingUpdate successful.\n");
  160. GumpLockingNode = NodeId;
  161. LeaveCriticalSection(&GumpUpdateLock);
  162. *Sequence = GumpSequence;
  163. return(ERROR_SUCCESS);
  164. }
  165. //
  166. // Another node owns the lock. Put ourselves onto the GUM lock queue and
  167. // release the critical section.
  168. //
  169. ClRtlLogPrint(LOG_NOISE,"[GUM] PostLockingUpdate posting.\n");
  170. WaitBlock = LocalAlloc(LMEM_FIXED, sizeof(GUM_WAITER));
  171. CL_ASSERT(WaitBlock != NULL);
  172. if (WaitBlock ! = NULL)
  173. {
  174. ClRtlLogPrint(LOG_UNUSUAL,"[GUM] GumpDoLockingPost : LocalAlloc failed\r\n");
  175. CL_UNEXPECTED_ERROR(GetLastError());
  176. }
  177. WaitBlock->WaitType = GUM_WAIT_ASYNC;
  178. WaitBlock->NodeId = NodeId;
  179. WaitBlock->Async.Context = Context;
  180. WaitBlock->Async.LockerNodeId = LockerNodeId;
  181. WaitBlock->Async.BufferLength = BufferLength;
  182. WaitBlock->Async.BufferPtr = BufferPtr;
  183. WaitBlock->Async.Buffer = Buffer;
  184. InsertTailList(&GumpLockQueue, &WaitBlock->ListEntry);
  185. LeaveCriticalSection(&GumpUpdateLock);
  186. //
  187. // We are on the GUM queue, so just return ERROR_IO_PENDING. When the
  188. // unlocking thread pulls us off the GUM queue, it will call our callback
  189. // and the update can proceed.
  190. //
  191. return(ERROR_IO_PENDING);
  192. }
  193. #endif
  194. BOOL
  195. GumpTryLockingUpdate(
  196. IN GUM_UPDATE_TYPE Type,
  197. IN DWORD NodeId,
  198. IN DWORD Sequence,
  199. OUT LPDWORD pdwGenerationNum
  200. )
  201. /*++
  202. Routine Description:
  203. Trys to acquire the GUM lock (does not wait). If successful, compares the
  204. passed in sequence number to the current sequence number. If they match,
  205. the locking update is performed.
  206. Arguments:
  207. Type - Supplies the type of update
  208. NodeId - Supplies the node id of the locking node.
  209. Sequence - Supplies the sequence number the update must be issued with
  210. pdwGenerationNum - If TRUE is returned, then this contains the generation number of the
  211. NodeId when it is granted the lock.
  212. Return Value:
  213. TRUE if successful
  214. FALSE if unsuccessful
  215. --*/
  216. {
  217. PGUM_INFO GumInfo;
  218. BOOL Success;
  219. CL_ASSERT(Type < GumUpdateMaximum);
  220. GumInfo = &GumTable[Type];
  221. ClRtlLogPrint(LOG_NOISE,
  222. "[GUM] GumpTryLockingUpdate Thread 0x%1!x! UpdateLock wait on Type %2!u!\n",
  223. GetCurrentThreadId(), Type);
  224. //
  225. // Acquire the critical section and see if a GUM update is in progress.
  226. //
  227. // SS: Acquire the GumpLock to protect the node generation number
  228. // Or should we just use the GumpUpdateLock to protect the generation number of nodes
  229. EnterCriticalSection(&GumpLock);
  230. EnterCriticalSection(&GumpUpdateLock);
  231. CL_ASSERT(GumpLockerNode == NmLocalNodeId);
  232. if (GumpSequence != Sequence)
  233. {
  234. //
  235. // The supplied sequence number does not match.
  236. //
  237. ClRtlLogPrint(LOG_UNUSUAL,
  238. "[GUM] GumpTryLockingUpdate supplied sequence %1!d! doesn't match %2!d!\n",
  239. Sequence,
  240. GumpSequence);
  241. Success = FALSE;
  242. goto FnExit;
  243. }
  244. if (GumpLockingNode == -1) {
  245. //
  246. // Nobody owns the lock, therefore we can acquire it and continue immediately.
  247. // There should also be no waiters.
  248. //
  249. CL_ASSERT(IsListEmpty(&GumpLockQueue));
  250. GumpLockingNode = NodeId;
  251. *pdwGenerationNum = GumNodeGeneration[NodeId];
  252. ClRtlLogPrint(LOG_NOISE,
  253. "[GUM] GumpTryLockingUpdate successful. Lock granted to node %1!d! at GenerationNum %2!u!\n",
  254. NodeId, *pdwGenerationNum);
  255. Success = TRUE;;
  256. } else {
  257. ClRtlLogPrint(LOG_UNUSUAL,
  258. "[GUM] GumpTryLockingUpdate update lock held\n");
  259. Success = FALSE;
  260. }
  261. //release the critical section and return
  262. FnExit:
  263. LeaveCriticalSection(&GumpLock);
  264. LeaveCriticalSection(&GumpUpdateLock);
  265. return(Success);
  266. }
  267. VOID
  268. GumpDoUnlockingUpdate(
  269. IN GUM_UPDATE_TYPE Type,
  270. IN DWORD Sequence,
  271. IN DWORD NodeId,
  272. IN DWORD GenerationNum
  273. )
  274. /*++
  275. Routine Description:
  276. Unlocks an earlier locking update
  277. Arguments:
  278. Type - Supplies the type of update to unlock
  279. Sequence - Supplies the sequence number to unlock
  280. Return Value:
  281. None.
  282. --*/
  283. {
  284. PGUM_INFO GumInfo;
  285. PGUM_WAITER Waiter;
  286. PLIST_ENTRY ListEntry;
  287. //Dont use the gumupdate type in this function, otherwise
  288. //know that it may be set to gumupdatemaximum in case the
  289. //forming node fails immediately after a join and the joiner
  290. //node becomes the locker node. The new locker might then
  291. //call reupdate/unlock with type=gumupdatemaximum
  292. CL_ASSERT(Type <= GumUpdateMaximum);
  293. GumInfo = &GumTable[Type];
  294. //SS: should we remove this assert
  295. //CL_ASSERT(Sequence == GumpSequence - 1);
  296. if (Sequence != GumpSequence - 1) {
  297. ClRtlLogPrint(LOG_UNUSUAL,
  298. "[GUM] GumpDoLockingUpdate: Sequence Mismatch, Type %1!u!, Sequence %2!u!, GumpSequence %3!u!\n",
  299. Type, Sequence, GumpSequence);
  300. return;
  301. }
  302. //
  303. // Acquire the critical section and see if there are any waiters.
  304. //
  305. // SS: acquire the GumpLock to protect the Gumnodegeneration array
  306. EnterCriticalSection(&GumpLock);
  307. EnterCriticalSection(&GumpUpdateLock);
  308. // If the unlock is made in a different generation from which the lock was issued in
  309. // then fail the request. If the request comes from a win2K node, the node id will
  310. // be set to ClusterInvalidNodeId in which case we will simply not perform the check
  311. // This implies that we dont fix the bug where a dead node can unlock the gumlock
  312. // while the locking node has assumed its ownership in a mixed mode cluster
  313. // Oh well, I dont think that is too bad :-)
  314. if ((NodeId != ClusterInvalidNodeId) &&
  315. (GumNodeGeneration[NodeId] != GenerationNum))
  316. {
  317. ClRtlLogPrint(LOG_UNUSUAL,
  318. "[GUM] GumpDoUnlockingUpdate: Generation Mismatch, Type %1!u! Sequence %2!u! NodeId %3!u! GenNum %4!u! CurrentGen %5!u!\n",
  319. Type, Sequence, NodeId, GenerationNum, GumNodeGeneration[NodeId]);
  320. LeaveCriticalSection(&GumpLock);
  321. LeaveCriticalSection(&GumpUpdateLock);
  322. return;
  323. }
  324. //
  325. // Pull the next waiter off the queue. If it is an async waiter,
  326. // issue that update now. If it is a sync waiter, grant ownership
  327. // of the GUM lock and wake the waiting thread.
  328. //
  329. while (!IsListEmpty(&GumpLockQueue)) {
  330. ListEntry = RemoveHeadList(&GumpLockQueue);
  331. Waiter = CONTAINING_RECORD(ListEntry,
  332. GUM_WAITER,
  333. ListEntry);
  334. //
  335. // Set the new locking node, then process the update
  336. //
  337. // The new locker node may not be a part of the cluster any more.
  338. // We check if the Waiter node has rebooted when we wake up.
  339. ClRtlLogPrint(LOG_NOISE,
  340. "[GUM] GumpDoUnlockingUpdate granting lock ownership to node %1!d!\n",
  341. Waiter->NodeId);
  342. GumpLockingNode = Waiter->NodeId;
  343. #ifndef GUM_POST_SUPPORT
  344. CL_ASSERT(Waiter->WaitType == GUM_WAIT_SYNC);
  345. Waiter->GenerationNum = GumNodeGeneration[GumpLockingNode];
  346. SetEvent(Waiter->Sync.WakeEvent);
  347. //
  348. // The waiting thread now has ownership and is responsible
  349. // for any other items on the queue. Drop the lock and
  350. // return now.
  351. //
  352. LeaveCriticalSection(&GumpLock);
  353. LeaveCriticalSection(&GumpUpdateLock);
  354. return;
  355. #else
  356. if (Waiter->WaitType == GUM_WAIT_SYNC) {
  357. Waiter.Generation = GumNodeGeneration[GumpLockingNode]
  358. SetEvent(Waiter->Sync.WakeEvent);
  359. //
  360. // The waiting thread now has ownership and is responsible
  361. // for any other items on the queue. Drop the lock and
  362. // return now.
  363. //
  364. LeaveCriticalSection(&GumpUpdateLock);
  365. LeaveCriticalSection(GumpLock);
  366. return;
  367. } else {
  368. CL_ASSERT(Waiter->WaitType == GUM_WAIT_ASYNC);
  369. //
  370. // If the update originated on this node, go ahead and do the work
  371. // right here. Otherwise, issue the GUM callback to the originating
  372. // node to let them complete the post.
  373. //
  374. LeaveCriticalSection(&GumpUpdateLock);
  375. if (Waiter->NodeId == NmGetNodeId(NmLocalNode)) {
  376. //
  377. // Deliver the updates to the other nodes.
  378. //
  379. //SS:BUG BUG sort the locker details
  380. GumpDeliverPosts(NmGetNodeId(NmLocalNode)+1,
  381. Type,
  382. GumpSequence,
  383. Waiter->Async.Context,
  384. FALSE,
  385. Waiter->Async.BufferLength,
  386. Waiter->Async.Buffer);
  387. GumpSequence += 1; // update ourself to stay in sync.
  388. } else {
  389. //
  390. // Call back to the originating node to deliver the posts.
  391. // First dispatch the update locally to save a round-trip.
  392. //
  393. //SS: sort thelocker details
  394. GumpDispatchUpdate(Type,
  395. Waiter->Async.Context,
  396. FALSE,
  397. FALSE,
  398. Waiter->Async.BufferLength,
  399. Waiter->Async.Buffer);
  400. CL_ASSERT(GumpRpcBindings[Waiter->NodeId] != NULL);
  401. GumDeliverPostCallback(GumpRpcBindings[Waiter->NodeId],
  402. NmGetNodeId(NmLocalNode)+1,
  403. Type,
  404. GumpSequence-1,
  405. Waiter->Async.Context,
  406. Waiter->Async.BufferLength,
  407. Waiter->Async.BufferPtr);
  408. MIDL_user_free(Waiter->Async.Buffer);
  409. }
  410. //
  411. // Free the wait block and process the next entry on the queue.
  412. //
  413. LocalFree(Waiter);
  414. EnterCriticalSection(&GumpUpdateLock);
  415. }
  416. #endif
  417. }
  418. //
  419. // No more waiters, just unlock and we are done.
  420. //
  421. ClRtlLogPrint(LOG_NOISE,
  422. "[GUM] GumpDoUnlockingUpdate releasing lock ownership\n");
  423. GumpLockingNode = (DWORD)-1;
  424. LeaveCriticalSection(&GumpUpdateLock);
  425. LeaveCriticalSection(&GumpLock);
  426. return;
  427. }