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.

426 lines
9.1 KiB

  1. /*++
  2. Copyright (c) 1996-1997 Microsoft Corporation
  3. Module Name:
  4. evntlist.c
  5. Abstract:
  6. This module contains routines to process the Poll Event List.
  7. Author:
  8. Rod Gamache (rodga) 9-April-1996
  9. Revision History:
  10. --*/
  11. #include "nt.h"
  12. #include "ntrtl.h"
  13. #include "nturtl.h"
  14. #include "resmonp.h"
  15. #include "stdio.h"
  16. #define RESMON_MODULE RESMON_MODULE_EVNTLIST
  17. //
  18. // Global data defined by this module
  19. //
  20. LIST_ENTRY RmpEventListHead; // Event list (under construction)
  21. //
  22. // Function prototypes local to this module
  23. //
  24. DWORD
  25. RmpAddPollEvent(
  26. IN PPOLL_EVENT_LIST EventList,
  27. IN HANDLE EventHandle,
  28. IN PRESOURCE Resource OPTIONAL
  29. )
  30. /*++
  31. Routine Description:
  32. Add a new EventHandle to the list of events in the Poll EventList.
  33. Arguments:
  34. EventList - The event list associated with this event handle and resource.
  35. EventHandle - The new event handle to be added.
  36. Resource - The resource associated with the event handle.
  37. Return Value:
  38. ERROR_SUCCESS - if the request is successful.
  39. ERROR_DUPLICATE_SERVICE_NAME - if the event handle is already in the list
  40. Win32 error code on other failures.
  41. Note:
  42. Since the resource is optional, we cannot get the event list from the
  43. resource.
  44. --*/
  45. {
  46. DWORD i;
  47. DWORD status;
  48. PLIST_ENTRY listEntry;
  49. CL_ASSERT( EventHandle != NULL );
  50. if ( ARGUMENT_PRESENT( Resource ) ) {
  51. CL_ASSERT( Resource->EventHandle == NULL );
  52. }
  53. AcquireEventListLock( EventList );
  54. //
  55. // First, make sure this handle isn't already present.
  56. //
  57. for ( i = 0; i < EventList->EventCount; i++ ) {
  58. if ( EventHandle == EventList->Handle[i] ) {
  59. ReleaseEventListLock( EventList );
  60. return(ERROR_DUPLICATE_SERVICE_NAME);
  61. }
  62. }
  63. //
  64. // Now make sure that we don't have too many events in this list!
  65. //
  66. CL_ASSERT ( EventList->EventCount < MAX_HANDLES_PER_THREAD );
  67. //
  68. // Now add our event to our list.
  69. //
  70. EventList->Handle[EventList->EventCount] = EventHandle;
  71. EventList->Resource[EventList->EventCount] = Resource;
  72. if ( ARGUMENT_PRESENT( Resource ) ) {
  73. Resource->EventHandle = EventHandle;
  74. }
  75. ++EventList->EventCount;
  76. ReleaseEventListLock( EventList );
  77. //
  78. // Now wake up our poller thread to get the new list.
  79. // Currently, the Online routine will pulse the poller thread - so
  80. // no need to do it here.
  81. //SignalPoller( EventList );
  82. return(ERROR_SUCCESS);
  83. } // RmpAddPollEvent
  84. DWORD
  85. RmpRemovePollEvent(
  86. IN HANDLE EventHandle
  87. )
  88. /*++
  89. Routine Description:
  90. Remove an EventHandle from the list of events in the Poll EventList.
  91. Arguments:
  92. EventHandle - The event handle to be removed.
  93. Return Value:
  94. ERROR_SUCCESS - if the request is successful.
  95. ERROR_RESOURCE_NOT_FOUND - if the EventHandle is not in the list.
  96. Note:
  97. We can only add to the event lists listhead - we can never remove a
  98. POLL_EVENT_LIST structure from the list!
  99. --*/
  100. {
  101. DWORD i;
  102. DWORD j;
  103. PRESOURCE resource;
  104. PPOLL_EVENT_LIST eventList;
  105. PLIST_ENTRY listEntry;
  106. CL_ASSERT( ARGUMENT_PRESENT(EventHandle) );
  107. AcquireListLock();
  108. for ( listEntry = RmpEventListHead.Flink;
  109. listEntry != &RmpEventListHead;
  110. listEntry = listEntry->Flink ) {
  111. eventList = CONTAINING_RECORD( listEntry, POLL_EVENT_LIST, Next );
  112. AcquireEventListLock( eventList );
  113. //
  114. // Find the entry in the event list.
  115. //
  116. for ( i = 0; i < eventList->EventCount; i++ ) {
  117. if ( eventList->Handle[i] == EventHandle ) {
  118. break;
  119. }
  120. }
  121. if ( i < eventList->EventCount ) {
  122. break;
  123. }
  124. ReleaseEventListLock( eventList );
  125. }
  126. ReleaseListLock();
  127. //
  128. // If we hit the end of the list without finding our event, return error.
  129. //
  130. if ( (listEntry == &RmpEventListHead) || (i >= eventList->EventCount) ) {
  131. return(ERROR_RESOURCE_NOT_FOUND);
  132. }
  133. //
  134. // Otherwise, collapse lists, but first save pointer to the resource.
  135. //
  136. resource = eventList->Resource[i];
  137. CL_ASSERT( resource != NULL );
  138. for ( j = i; j < (eventList->EventCount-1); j++ ) {
  139. eventList->Handle[j] = eventList->Handle[j+1];
  140. eventList->Resource[j] = eventList->Resource[j+1];
  141. }
  142. --eventList->EventCount;
  143. eventList->Handle[eventList->EventCount] = NULL;
  144. eventList->Resource[eventList->EventCount] = NULL;
  145. //
  146. // Event handle is of no use anymore until Online returns a new one.
  147. // N.B. We do not close the event handle, since the resource DLL is
  148. // responsible for taking care of this.
  149. //
  150. CL_ASSERT( EventHandle == resource->EventHandle );
  151. resource->EventHandle = NULL;
  152. ReleaseEventListLock( eventList );
  153. //
  154. // Now wake up the poll thread to get the new list.
  155. //
  156. RmpSignalPoller( eventList );
  157. return(ERROR_SUCCESS);
  158. } // RmpRemovePollEvent
  159. PVOID
  160. RmpCreateEventList(
  161. VOID
  162. )
  163. /*++
  164. Routine Description:
  165. Allocates, initializes and inserts a new event list.
  166. Arguments:
  167. None.
  168. Returns:
  169. NULL - we failed.
  170. non-NULL - a pointer to the new event list.
  171. If NULL, it does a SetLastError() to indicate the failure.
  172. Notes:
  173. This routine assumes that the EventListLock is held during this call.
  174. This routine will start a new event processing thread that will handle
  175. the list.
  176. There is one ListNotify event and one BucketListHead per event list!
  177. --*/
  178. {
  179. PPOLL_EVENT_LIST newEventList=NULL;
  180. DWORD threadId;
  181. DWORD dwError = ERROR_SUCCESS;
  182. AcquireListLock();
  183. if ( RmpShutdown || (RmpNumberOfThreads >= MAX_THREADS) ) {
  184. dwError = ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED;
  185. goto FnExit;
  186. }
  187. newEventList = LocalAlloc(LMEM_ZEROINIT,
  188. sizeof( POLL_EVENT_LIST ));
  189. if ( newEventList == NULL ) {
  190. dwError = ERROR_NOT_ENOUGH_MEMORY;
  191. goto FnExit;
  192. }
  193. //
  194. // Initialize the newEventList.
  195. //
  196. InitializeListHead( &newEventList->BucketListHead );
  197. InitializeCriticalSection( &newEventList->ListLock );
  198. //
  199. // Create a list notification event.
  200. //
  201. newEventList->ListNotify = CreateEvent( NULL, FALSE, FALSE, NULL );
  202. if ( newEventList->ListNotify == NULL ) {
  203. dwError = GetLastError();
  204. goto FnExit;
  205. }
  206. //
  207. // Now create a thread and pass this Event List to it.
  208. //
  209. newEventList->ThreadHandle = CreateThread(NULL,
  210. 0,
  211. RmpPollerThread,
  212. newEventList,
  213. 0,
  214. &threadId);
  215. if ( newEventList->ThreadHandle == NULL ) {
  216. dwError = GetLastError();
  217. goto FnExit;
  218. }
  219. //
  220. // Tally one more event list, and insert onto list of event lists.
  221. //
  222. RmpWaitArray[RmpNumberOfThreads] = newEventList->ThreadHandle;
  223. ++RmpNumberOfThreads;
  224. InsertTailList( &RmpEventListHead, &newEventList->Next );
  225. //
  226. // Signal the main thread to rewait and watch the new thread.
  227. //
  228. SetEvent( RmpRewaitEvent );
  229. FnExit:
  230. ReleaseListLock();
  231. if (dwError != ERROR_SUCCESS)
  232. {
  233. //we failed, release any resource we might have allocated
  234. if (newEventList)
  235. {
  236. if (newEventList->ListNotify) CloseHandle( newEventList->ListNotify );
  237. RmpFree( newEventList );
  238. }
  239. SetLastError(dwError);
  240. }
  241. return(newEventList);
  242. } // RmpCreateEventList
  243. DWORD
  244. RmpResourceEventSignaled(
  245. IN PPOLL_EVENT_LIST EventList,
  246. IN DWORD EventIndex
  247. )
  248. /*++
  249. Routine Description:
  250. A resource event has been signaled. This indicates that the specified
  251. resource has failed.
  252. Arguments:
  253. EventList - the waiting event list.
  254. EventIndex - index of the event that was signaled.
  255. Return Value:
  256. ERROR_SUCCESS - if the request is successful.
  257. --*/
  258. {
  259. PRESOURCE resource;
  260. //
  261. // Don't post any events if resmon is shutting down. This causes cluster service policies
  262. // to be triggered while resmon is shutting down and that causes bogus RPC failures in
  263. // cluster service.
  264. //
  265. if ( RmpShutdown ) return ( ERROR_SUCCESS );
  266. CL_ASSERT( EventIndex <= MAX_HANDLES_PER_THREAD );
  267. //
  268. // Get our resource.
  269. //
  270. resource = EventList->Resource[EventIndex];
  271. if ( resource == NULL ) {
  272. return(ERROR_RESOURCE_NOT_FOUND);
  273. }
  274. //
  275. // Remove the failed resource from the event notification list.
  276. // N.B. we do not need to acquire the eventlist lock because there is
  277. // only one thread that can ever touch the waiting event list!
  278. //
  279. if ( resource->EventHandle ) {
  280. RmpRemovePollEvent( resource->EventHandle );
  281. }
  282. //
  283. // Post the failure of the resource, if the resource is not being taken
  284. // offline.
  285. //
  286. if ( resource->State != ClusterResourceOffline ) {
  287. resource->State = ClusterResourceFailed;
  288. RmpPostNotify(resource, NotifyResourceStateChange);
  289. }
  290. return(ERROR_SUCCESS);
  291. } // RmpResourceEventSignaled