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.

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