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.

436 lines
11 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. PLIST_ENTRY pListEntry;
  48. PPOLL_EVENT_LIST pTempEventList;
  49. CL_ASSERT( EventHandle != NULL );
  50. if ( ARGUMENT_PRESENT( Resource ) ) {
  51. CL_ASSERT( Resource->EventHandle == NULL );
  52. }
  53. //
  54. // Acquire the global lock to walk all event list heads.
  55. //
  56. AcquireListLock();
  57. //
  58. // Since the global lock is acquired above, there is no danger of eventlist lock ordering being reversed
  59. // even as multiple eventlist lock acquisitions are made below.
  60. //
  61. AcquireEventListLock( EventList );
  62. for ( pListEntry = RmpEventListHead.Flink;
  63. pListEntry != &RmpEventListHead;
  64. pListEntry = pListEntry->Flink )
  65. {
  66. pTempEventList = CONTAINING_RECORD( pListEntry, POLL_EVENT_LIST, Next );
  67. AcquireEventListLock( pTempEventList );
  68. //
  69. // First, make sure this handle isn't already present in ANY list.
  70. //
  71. for ( i = 0; i < pTempEventList->EventCount; i++ )
  72. {
  73. if ( pTempEventList->Handle[i] == EventHandle )
  74. {
  75. ClRtlLogPrint(LOG_UNUSUAL,
  76. "[RM] RmpAddPollEvent: Event handle 0x%1!08lx! is a duplicate of that of resource %2!ws!...\n",
  77. EventHandle,
  78. pTempEventList->Resource[i]->ResourceName);
  79. ReleaseEventListLock( pTempEventList );
  80. ReleaseEventListLock( EventList );
  81. ReleaseListLock();
  82. return( ERROR_DUPLICATE_SERVICE_NAME );
  83. }
  84. }
  85. ReleaseEventListLock( pTempEventList );
  86. }// for
  87. //
  88. // Release the global lock. Note that since we acquire the eventlist lock of the list we are
  89. // going to change, say lock L, a second thread cannot sneak in and insert a duplicate event after the first
  90. // thread has ensured that there are no duplicate events. This is because the second thread won't
  91. // be able to acquire the eventlist lock L acquired by the first thread.
  92. //
  93. ReleaseListLock();
  94. //
  95. // Now make sure that we don't have too many events in this list!
  96. //
  97. CL_ASSERT ( EventList->EventCount < MAX_HANDLES_PER_THREAD );
  98. //
  99. // Now add our event to our list.
  100. //
  101. EventList->Handle[EventList->EventCount] = EventHandle;
  102. EventList->Resource[EventList->EventCount] = Resource;
  103. if ( ARGUMENT_PRESENT( Resource ) ) {
  104. Resource->EventHandle = EventHandle;
  105. }
  106. ++EventList->EventCount;
  107. ReleaseEventListLock( EventList );
  108. //
  109. // Now wake up our poller thread to get the new list.
  110. // Currently, the Online routine will pulse the poller thread - so
  111. // no need to do it here.
  112. //SignalPoller( EventList );
  113. return(ERROR_SUCCESS);
  114. } // RmpAddPollEvent
  115. DWORD
  116. RmpRemovePollEvent(
  117. PPOLL_EVENT_LIST pEventList,
  118. IN HANDLE EventHandle
  119. )
  120. /*++
  121. Routine Description:
  122. Remove an EventHandle from the list of events in the Poll EventList.
  123. Arguments:
  124. pEventList - The event list from which a handle is to be removed.
  125. EventHandle - The event handle to be removed.
  126. Return Value:
  127. ERROR_SUCCESS - if the request is successful.
  128. ERROR_RESOURCE_NOT_FOUND - if the EventHandle is not in the list.
  129. Note:
  130. We can only add to the event lists listhead - we can never remove a
  131. POLL_EVENT_LIST structure from the list!
  132. --*/
  133. {
  134. DWORD i;
  135. DWORD j;
  136. PRESOURCE resource;
  137. PLIST_ENTRY listEntry;
  138. CL_ASSERT( ARGUMENT_PRESENT( EventHandle ) );
  139. AcquireEventListLock( pEventList );
  140. //
  141. // Find the entry in the event list.
  142. //
  143. for ( i = 0; i < pEventList->EventCount; i++ ) {
  144. if ( pEventList->Handle[i] == EventHandle ) {
  145. break;
  146. }
  147. }
  148. //
  149. // If we hit the end of the list without finding our event, return error.
  150. //
  151. if ( i >= pEventList->EventCount ) {
  152. ReleaseEventListLock( pEventList );
  153. ClRtlLogPrint(LOG_UNUSUAL,
  154. "[RM] RmpRemovePollEvent: Event handle 0x%1!08lx! not found in the eventlist...\n",
  155. EventHandle);
  156. return( ERROR_RESOURCE_NOT_FOUND );
  157. }
  158. //
  159. // Otherwise, collapse lists, but first save pointer to the resource.
  160. //
  161. resource = pEventList->Resource[i];
  162. CL_ASSERT( resource != NULL );
  163. for ( j = i; j < (pEventList->EventCount-1); j++ ) {
  164. pEventList->Handle[j] = pEventList->Handle[j+1];
  165. pEventList->Resource[j] = pEventList->Resource[j+1];
  166. }
  167. --pEventList->EventCount;
  168. pEventList->Handle[pEventList->EventCount] = NULL;
  169. pEventList->Resource[pEventList->EventCount] = NULL;
  170. //
  171. // Event handle is of no use anymore until Online returns a new one.
  172. // N.B. We do not close the event handle, since the resource DLL is
  173. // responsible for taking care of this.
  174. //
  175. CL_ASSERT( EventHandle == resource->EventHandle );
  176. resource->EventHandle = NULL;
  177. ReleaseEventListLock( pEventList );
  178. //
  179. // Now wake up the poll thread to get the new list.
  180. //
  181. RmpSignalPoller( pEventList );
  182. return(ERROR_SUCCESS);
  183. } // RmpRemovePollEvent
  184. PVOID
  185. RmpCreateEventList(
  186. VOID
  187. )
  188. /*++
  189. Routine Description:
  190. Allocates, initializes and inserts a new event list.
  191. Arguments:
  192. None.
  193. Returns:
  194. NULL - we failed.
  195. non-NULL - a pointer to the new event list.
  196. If NULL, it does a SetLastError() to indicate the failure.
  197. Notes:
  198. This routine assumes that the EventListLock is held during this call.
  199. This routine will start a new event processing thread that will handle
  200. the list.
  201. There is one ListNotify event and one BucketListHead per event list!
  202. --*/
  203. {
  204. PPOLL_EVENT_LIST newEventList=NULL;
  205. DWORD threadId;
  206. DWORD dwError = ERROR_SUCCESS;
  207. AcquireListLock();
  208. if ( RmpShutdown || (RmpNumberOfThreads >= MAX_THREADS) ) {
  209. dwError = ERROR_CLUSTER_MAXNUM_OF_RESOURCES_EXCEEDED;
  210. goto FnExit;
  211. }
  212. newEventList = LocalAlloc(LMEM_ZEROINIT,
  213. sizeof( POLL_EVENT_LIST ));
  214. if ( newEventList == NULL ) {
  215. dwError = ERROR_NOT_ENOUGH_MEMORY;
  216. goto FnExit;
  217. }
  218. //
  219. // Initialize the newEventList.
  220. //
  221. InitializeListHead( &newEventList->BucketListHead );
  222. InitializeCriticalSection( &newEventList->ListLock );
  223. //
  224. // Now create a thread and pass this Event List to it.
  225. //
  226. newEventList->ThreadHandle = CreateThread(NULL,
  227. 0,
  228. RmpPollerThread,
  229. newEventList,
  230. 0,
  231. &threadId);
  232. if ( newEventList->ThreadHandle == NULL ) {
  233. dwError = GetLastError();
  234. goto FnExit;
  235. }
  236. //
  237. // Tally one more event list, and insert onto list of event lists.
  238. //
  239. RmpWaitArray[RmpNumberOfThreads] = newEventList->ThreadHandle;
  240. ++RmpNumberOfThreads;
  241. InsertTailList( &RmpEventListHead, &newEventList->Next );
  242. //
  243. // Signal the main thread to rewait and watch the new thread.
  244. //
  245. SetEvent( RmpRewaitEvent );
  246. FnExit:
  247. ReleaseListLock();
  248. if (dwError != ERROR_SUCCESS)
  249. {
  250. //we failed, release any resource we might have allocated
  251. if (newEventList)
  252. {
  253. RmpFree( newEventList );
  254. }
  255. SetLastError(dwError);
  256. }
  257. return(newEventList);
  258. } // RmpCreateEventList
  259. DWORD
  260. RmpResourceEventSignaled(
  261. IN PPOLL_EVENT_LIST EventList,
  262. IN DWORD EventIndex
  263. )
  264. /*++
  265. Routine Description:
  266. A resource event has been signaled. This indicates that the specified
  267. resource has failed.
  268. Arguments:
  269. EventList - the waiting event list.
  270. EventIndex - index of the event that was signaled.
  271. Return Value:
  272. ERROR_SUCCESS - if the request is successful.
  273. --*/
  274. {
  275. PRESOURCE resource;
  276. //
  277. // Don't post any events if resmon is shutting down. This causes cluster service policies
  278. // to be triggered while resmon is shutting down and that causes bogus RPC failures in
  279. // cluster service.
  280. //
  281. if ( RmpShutdown ) return ( ERROR_SUCCESS );
  282. CL_ASSERT( EventIndex <= MAX_HANDLES_PER_THREAD );
  283. //
  284. // Get our resource.
  285. //
  286. resource = EventList->Resource[EventIndex];
  287. if ( resource == NULL ) {
  288. return(ERROR_RESOURCE_NOT_FOUND);
  289. }
  290. //
  291. // Remove the failed resource from the event notification list.
  292. // N.B. we do not need to acquire the eventlist lock because there is
  293. // only one thread that can ever touch the waiting event list!
  294. //
  295. if ( resource->EventHandle ) {
  296. RmpRemovePollEvent( resource->EventList, resource->EventHandle );
  297. }
  298. //
  299. // Post the failure of the resource, if the resource is not being taken
  300. // offline.
  301. //
  302. if ( resource->State != ClusterResourceOffline ) {
  303. CL_ASSERT( resource->State != ClusterResourceFailed );
  304. resource->State = ClusterResourceFailed;
  305. RmpPostNotify(resource, NotifyResourceStateChange);
  306. }
  307. return(ERROR_SUCCESS);
  308. } // RmpResourceEventSignaled