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.

710 lines
15 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. event.c
  5. Abstract:
  6. Event Engine for the Event Processor component of the Cluster Service.
  7. Author:
  8. Rod Gamache (rodga) 28-Feb-1996
  9. Revision History:
  10. --*/
  11. #include "epp.h"
  12. //
  13. // Event Processor State.
  14. //
  15. ULONG EventProcessorState = EventProcessorStateIniting;
  16. //
  17. // Global data
  18. //
  19. //
  20. // Local data
  21. //
  22. EVENT_DISPATCH_TABLE EventDispatchTable[NUMBER_OF_COMPONENTS] = {0};
  23. EVENT_DISPATCH_TABLE SyncEventDispatchTable[NUMBER_OF_COMPONENTS] = {0};
  24. PCLRTL_BUFFER_POOL EventPool = NULL;
  25. DWORD EventHandlerCount = 0;
  26. DWORD SyncEventHandlerCount = 0;
  27. DWORD EventBufferOffset = EpQuadAlign(sizeof(CLRTL_WORK_ITEM));
  28. //
  29. // Functions
  30. //
  31. DWORD
  32. WINAPI
  33. EpInitialize(
  34. VOID
  35. )
  36. /*++
  37. Routine Description:
  38. Event Processor Initialize routine.
  39. Arguments:
  40. None.
  41. Return Value:
  42. A Win32 status code.
  43. --*/
  44. {
  45. DWORD status = ERROR_SUCCESS;
  46. DWORD index;
  47. DWORD i;
  48. PVOID eventArray[EP_MAX_CACHED_EVENTS];
  49. ClRtlLogPrint(LOG_NOISE,"[EP] Initialization...\n");
  50. //
  51. // Create the event pool. The event structure must be quadword aligned.
  52. //
  53. EventPool = ClRtlCreateBufferPool(
  54. EventBufferOffset + sizeof(EP_EVENT),
  55. EP_MAX_CACHED_EVENTS,
  56. EP_MAX_ALLOCATED_EVENTS,
  57. NULL,
  58. NULL
  59. );
  60. if (EventPool == NULL) {
  61. ClRtlLogPrint(LOG_NOISE,"[EP] Unable to allocate event buffer pool\n");
  62. return(ERROR_NOT_ENOUGH_MEMORY);
  63. }
  64. //
  65. // Prime the event pool cache to minimize the chance of an allocation
  66. // failure.
  67. //
  68. ZeroMemory(&(eventArray[0]), sizeof(PVOID) * EP_MAX_CACHED_EVENTS);
  69. for (i=0; i<EP_MAX_CACHED_EVENTS; i++) {
  70. eventArray[i] = ClRtlAllocateBuffer(EventPool);
  71. if (eventArray[i] == NULL) {
  72. ClRtlLogPrint(LOG_NOISE,
  73. "[EP] Unable to prime event buffer cache, buf num %1!u!!!!\n",
  74. i
  75. );
  76. status = ERROR_NOT_ENOUGH_MEMORY;
  77. CsInconsistencyHalt( status );
  78. }
  79. }
  80. for (i=0; i<EP_MAX_CACHED_EVENTS; i++) {
  81. if (eventArray[i] != NULL) {
  82. ClRtlFreeBuffer(eventArray[i]);
  83. }
  84. }
  85. if (status != ERROR_SUCCESS) {
  86. return(status);
  87. }
  88. return(ERROR_SUCCESS);
  89. } // EpInitialize
  90. void
  91. EppLogEvent(
  92. IN CLUSTER_EVENT Event
  93. )
  94. {
  95. switch( Event ) {
  96. case CLUSTER_EVENT_ONLINE:
  97. ClRtlLogPrint(LOG_NOISE,"[EP] Cluster Service online event received\n");
  98. break;
  99. case CLUSTER_EVENT_SHUTDOWN:
  100. ClRtlLogPrint(LOG_NOISE,"[EP] Cluster Service shutdown event received\n");
  101. break;
  102. case CLUSTER_EVENT_NODE_UP:
  103. ClRtlLogPrint(LOG_NOISE,"[EP] Node up event received\n");
  104. break;
  105. case CLUSTER_EVENT_NODE_DOWN:
  106. ClRtlLogPrint(LOG_NOISE,"[EP] Node down event received\n");
  107. break;
  108. case CLUSTER_EVENT_NODE_DOWN_EX:
  109. ClRtlLogPrint(LOG_NOISE,"[EP] Nodes down event received\n");
  110. break;
  111. default:
  112. break;
  113. } // switch( Event )
  114. }
  115. VOID
  116. EpEventHandler(
  117. IN PCLRTL_WORK_ITEM WorkItem,
  118. IN DWORD Ignored1,
  119. IN DWORD Ignored2,
  120. IN ULONG_PTR Ignored3
  121. )
  122. /*++
  123. --*/
  124. {
  125. DWORD index;
  126. PEP_EVENT Event = (PEP_EVENT) (((char *) WorkItem) + EventBufferOffset);
  127. if (Event->Id == CLUSTER_EVENT_SHUTDOWN) {
  128. //
  129. // To shutdown, we just need to stop the service.
  130. //
  131. CsStopService();
  132. }
  133. //
  134. // Now deliver the event to all of the other components.
  135. // Eventually, we might filter events based on the mask
  136. // returned on the init call.
  137. //
  138. for ( index = 0; index < NUMBER_OF_COMPONENTS; index++ ) {
  139. if ( EventDispatchTable[index].EventRoutine == NULL ) {
  140. continue;
  141. }
  142. (EventDispatchTable[index].EventRoutine)(
  143. Event->Id,
  144. Event->Context
  145. );
  146. }
  147. //
  148. // Handle any post processing that might be required.
  149. //
  150. if (Event->Flags & EP_CONTEXT_VALID) {
  151. if (Event->Flags & EP_DEREF_CONTEXT) {
  152. OmDereferenceObject(Event->Context);
  153. }
  154. if (Event->Flags & EP_FREE_CONTEXT) {
  155. LocalFree(Event->Context);
  156. }
  157. }
  158. ClRtlFreeBuffer(WorkItem);
  159. return;
  160. }
  161. DWORD
  162. WINAPI
  163. EpPostSyncEvent(
  164. IN CLUSTER_EVENT Event,
  165. IN DWORD Flags,
  166. IN PVOID Context
  167. )
  168. /*++
  169. Routine Description:
  170. Synchronously posts an event to the rest of the cluster
  171. Arguments:
  172. Event - Supplies the type of event
  173. Flags - Supplies any post processing that should be done to the
  174. context after all dispatch handlers have been called
  175. Context - Supplies the context.
  176. Return Value:
  177. ERROR_SUCCESS if successful
  178. Win32 error code otherwise
  179. Notes:
  180. If flags is NULL, then we assume Context points to a standard (OM known)
  181. object, and we'll reference and dereference that object appropriately.
  182. If flags is non-NULL, then don't reference/dereference the Context object.
  183. --*/
  184. {
  185. DWORD index;
  186. // log event
  187. EppLogEvent(Event);
  188. //
  189. // Reference to keep the context object around.
  190. //
  191. if (Context) {
  192. if ( Flags == 0) {
  193. OmReferenceObject( Context );
  194. Flags = EP_DEREF_CONTEXT;
  195. }
  196. Flags |= EP_CONTEXT_VALID;
  197. }
  198. //
  199. // Now deliver the event to all of the other components.
  200. // Eventually, we might filter events based on the mask
  201. // returned on the init call.
  202. //
  203. for ( index = 0; index < NUMBER_OF_COMPONENTS; index++ ) {
  204. if ( SyncEventDispatchTable[index].EventRoutine == NULL ) {
  205. continue;
  206. }
  207. (SyncEventDispatchTable[index].EventRoutine)(
  208. Event,
  209. Context
  210. );
  211. }
  212. //
  213. // Handle any post processing that might be required.
  214. //
  215. if (Flags & EP_CONTEXT_VALID) {
  216. if (Flags & EP_DEREF_CONTEXT) {
  217. OmDereferenceObject(Context);
  218. }
  219. if (Flags & EP_FREE_CONTEXT) {
  220. LocalFree(Context);
  221. }
  222. }
  223. return (ERROR_SUCCESS);
  224. }
  225. DWORD
  226. WINAPI
  227. EpPostEvent(
  228. IN CLUSTER_EVENT Event,
  229. IN DWORD Flags,
  230. IN PVOID Context
  231. )
  232. /*++
  233. Routine Description:
  234. Asynchronously posts an event to the rest of the cluster
  235. Arguments:
  236. Event - Supplies the type of event
  237. Flags - Supplies any post processing that should be done to the
  238. context after all dispatch handlers have been called
  239. Context - Supplies the context.
  240. Return Value:
  241. ERROR_SUCCESS if successful
  242. Win32 error code otherwise
  243. Notes:
  244. If flags is NULL, then we assume Context points to a standard (OM known)
  245. object, and we'll reference and dereference that object appropriately.
  246. If flags is non-NULL, then don't reference/dereference the Context object.
  247. --*/
  248. {
  249. PCLRTL_WORK_ITEM workItem;
  250. PEP_EVENT event;
  251. DWORD status;
  252. // log event
  253. EppLogEvent(Event);
  254. // handle async handlers.
  255. workItem = ClRtlAllocateBuffer(EventPool);
  256. if (workItem != NULL) {
  257. ClRtlInitializeWorkItem(workItem, EpEventHandler, NULL);
  258. //
  259. // Reference to keep the context object around.
  260. //
  261. if (Context) {
  262. if ( Flags == 0) {
  263. OmReferenceObject( Context );
  264. Flags = EP_DEREF_CONTEXT;
  265. }
  266. Flags |= EP_CONTEXT_VALID;
  267. }
  268. event = (PEP_EVENT) ( ((char *) workItem) + EventBufferOffset );
  269. event->Id = Event;
  270. event->Flags = Flags;
  271. event->Context = Context;
  272. status = ClRtlPostItemWorkQueue(CsCriticalWorkQueue, workItem, 0, 0);
  273. if (status == ERROR_SUCCESS) {
  274. return(ERROR_SUCCESS);
  275. }
  276. ClRtlLogPrint(LOG_NOISE,
  277. "[EP] Failed to post item to critical work queue, status %1!u!\n",
  278. status
  279. );
  280. ClRtlFreeBuffer(workItem);
  281. return(status);
  282. }
  283. ClRtlLogPrint(LOG_NOISE,"[EP] Failed to allocate an event buffer!!!\n");
  284. return(ERROR_NOT_ENOUGH_MEMORY);
  285. }
  286. VOID
  287. EpShutdown(
  288. VOID
  289. )
  290. /*++
  291. Routine Description:
  292. This routine shuts down the components of the Cluster Service.
  293. Arguments:
  294. None.
  295. Returns:
  296. None.
  297. --*/
  298. {
  299. if ( EventPool ) {
  300. ClRtlDestroyBufferPool(EventPool);
  301. }
  302. // Now shutdown the event processor by just cleaning up.
  303. }
  304. DWORD
  305. EpRegisterEventHandler(
  306. IN CLUSTER_EVENT EventMask,
  307. IN PEVENT_ROUTINE EventRoutine
  308. )
  309. /*++
  310. Routine Description:
  311. Registers an event handler for the specified type of event.
  312. Arguments:
  313. EventMask - Supplies the mask of events that should be delivered.
  314. EventRoutine - Supplies the event routine that should be called.
  315. Return Value:
  316. ERROR_SUCCESS if successful
  317. Win32 error code otherwise.
  318. --*/
  319. {
  320. CL_ASSERT(EventHandlerCount < NUMBER_OF_COMPONENTS);
  321. EventDispatchTable[EventHandlerCount].EventMask = EventMask;
  322. EventDispatchTable[EventHandlerCount].EventRoutine = EventRoutine;
  323. ++EventHandlerCount;
  324. return(ERROR_SUCCESS);
  325. }
  326. DWORD
  327. EpRegisterSyncEventHandler(
  328. IN CLUSTER_EVENT EventMask,
  329. IN PEVENT_ROUTINE EventRoutine
  330. )
  331. /*++
  332. Routine Description:
  333. Registers an event handler for the specified type of event. The handler
  334. is called in the context of the dispatcher. Sync event handlers are to
  335. be used by components that require a barrier semanitcs in handling
  336. events e.g. gum, dlm , ...etc.
  337. Arguments:
  338. EventMask - Supplies the mask of events that should be delivered.
  339. EventRoutine - Supplies the event routine that should be called.
  340. Return Value:
  341. ERROR_SUCCESS if successful
  342. Win32 error code otherwise.
  343. --*/
  344. {
  345. CL_ASSERT(SyncEventHandlerCount < NUMBER_OF_COMPONENTS);
  346. // XXX: Do we need locking here in case this is not called from init() ?
  347. SyncEventDispatchTable[EventHandlerCount].EventMask = EventMask;
  348. SyncEventDispatchTable[EventHandlerCount].EventRoutine = EventRoutine;
  349. ++SyncEventHandlerCount;
  350. return(ERROR_SUCCESS);
  351. }
  352. DWORD EpInitPhase1()
  353. {
  354. DWORD dwError=ERROR_SUCCESS;
  355. // ClRtlLogPrint(LOG_NOISE,"[EP] EpInitPhase1\n");
  356. return(dwError);
  357. }
  358. DWORD
  359. WINAPI
  360. EpGumUpdateHandler(
  361. IN DWORD Context,
  362. IN BOOL SourceNode,
  363. IN DWORD BufferLength,
  364. IN PVOID Buffer
  365. )
  366. {
  367. DWORD Status;
  368. switch (Context)
  369. {
  370. default:
  371. Status = ERROR_INVALID_DATA;
  372. CsInconsistencyHalt(ERROR_INVALID_DATA);
  373. break;
  374. }
  375. return(Status);
  376. }
  377. /****
  378. @func WORD| EpClusterWidePostEvent| This generates an event notification on
  379. all the cluster nodes.
  380. @parm IN EVENT | Event | The event to be posted.
  381. @parm IN DWORD | dwFlags | The flags associated with this event.
  382. If zero, pContext points to one of the om objects.
  383. @parm IN PVOID | pContext | A pointer to an object or a buffer.
  384. @parm IN DWORD | cbContext | The size of pContext if it is a buffer.
  385. @rdesc Returns ERROR_SUCCESS for success, else returns the error code.
  386. @comm <f EpClusWidePostEvent>
  387. @xref
  388. ****/
  389. DWORD
  390. WINAPI
  391. EpClusterWidePostEvent(
  392. IN CLUSTER_EVENT Event,
  393. IN DWORD dwFlags,
  394. IN PVOID pContext,
  395. IN DWORD cbContext
  396. )
  397. {
  398. DWORD Status;
  399. DWORD cbObjectId = 0;
  400. PVOID pContext1 = pContext;
  401. DWORD cbContext1 = cbContext;
  402. PVOID pContext2 = NULL;
  403. DWORD cbContext2 = 0;
  404. //
  405. // We have do the work of EpPostEvent here because GUM
  406. // does not correctly pass a NULL pointer.
  407. //
  408. if (pContext) {
  409. if (dwFlags == 0) {
  410. //
  411. // The context is a pointer to a cluster object.
  412. // The caller is assumed to have a reference on the object
  413. // so it won't go away while we are using it.
  414. //
  415. DWORD dwObjectType = OmObjectType(pContext);
  416. LPCWSTR lpszObjectId = OmObjectId(pContext);
  417. cbContext1 = (lstrlen(lpszObjectId) + 1 ) * sizeof(WCHAR);
  418. pContext1 = (PVOID) lpszObjectId;
  419. pContext2 = &dwObjectType;
  420. cbContext2 = sizeof(dwObjectType);
  421. dwFlags = EP_DEREF_CONTEXT;
  422. }
  423. dwFlags |= EP_CONTEXT_VALID;
  424. }
  425. Status = GumSendUpdateEx(GumUpdateFailoverManager,
  426. EmUpdateClusWidePostEvent,
  427. 4,
  428. sizeof(CLUSTER_EVENT),
  429. &Event,
  430. sizeof(DWORD),
  431. &dwFlags,
  432. cbContext1,
  433. pContext1,
  434. cbContext2,
  435. pContext2
  436. );
  437. return(Status);
  438. }
  439. /****
  440. @func WORD| EpUpdateClusWidePostEvent| The update handler for
  441. EmUpdateClusWidePostEvent.
  442. @parm IN BOOL | SourceNode | If this is the source of origin of the gum update.
  443. @parm IN EVENT | pEvent | A pointer to the event to be posted.
  444. @parm IN LPDWORD | pdwFlags | A pointer to the flags associated with this event.
  445. @parm IN PVOID | pContext1 | A pointer to an object or a buffer.
  446. @parm IN PVOID | pContext2 | A pointer to an object type if pContext1 is a
  447. pointer to an object. Else unused.
  448. @rdesc Returns ERROR_SUCCESS for success, else returns the error code.
  449. @comm <f EpClusWidePostEvent>
  450. @xref
  451. ****/
  452. DWORD
  453. EpUpdateClusWidePostEvent(
  454. IN BOOL SourceNode,
  455. IN PCLUSTER_EVENT pEvent,
  456. IN LPDWORD pdwFlags,
  457. IN PVOID pContext1,
  458. IN PVOID pContext2
  459. )
  460. {
  461. DWORD Status = ERROR_INVALID_PARAMETER;
  462. if (*pdwFlags & EP_CONTEXT_VALID)
  463. {
  464. if (*pdwFlags & EP_DEREF_CONTEXT) {
  465. //
  466. // pContext1 is a pointer to an object ID.
  467. // pContext2 is a pointer to an object type.
  468. //
  469. LPCWSTR lpszObjectId = (LPCWSTR) pContext1;
  470. DWORD dwObjectType = *((LPDWORD) pContext2);
  471. PVOID pObject = OmReferenceObjectById(
  472. dwObjectType,
  473. lpszObjectId
  474. );
  475. if (!pObject)
  476. {
  477. //
  478. // Return success if object is not found! The object was
  479. // probably deleted.
  480. //
  481. return(ERROR_SUCCESS);
  482. }
  483. Status = EpPostEvent(*pEvent, *pdwFlags, pObject);
  484. }
  485. else {
  486. //
  487. // pContext1 is a buffer. If the FREE_BUFFER flag is on, turn
  488. // it off since the memory is owned by GUM.
  489. // pContext2 is ignored.
  490. //
  491. *pdwFlags = *pdwFlags & ~EP_FREE_CONTEXT;
  492. Status = EpPostEvent(*pEvent, *pdwFlags, pContext1);
  493. }
  494. }
  495. return(Status);
  496. }