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.

522 lines
16 KiB

  1. /*++
  2. Copyright (c) 1996-2002 Microsoft Corporation
  3. Module Name:
  4. dlock.c
  5. Abstract:
  6. Functions for detecting deadlocked resource dll entry point calls.
  7. Author:
  8. Chittur Subbaraman
  9. Revision History:
  10. 04-11-2002 Created
  11. --*/
  12. #define UNICODE 1
  13. #include "nt.h"
  14. #include "ntrtl.h"
  15. #include "nturtl.h"
  16. #include "resmonp.h"
  17. #include <strsafe.h>
  18. #define RESMON_MODULE RESMON_MODULE_DLOCK
  19. #define FILETIMES_PER_SEC ((__int64) 10000000) // (1 second)/(100 ns)
  20. //
  21. // Globals
  22. //
  23. PRM_DUE_TIME_FREE_LIST_HEAD g_pRmDueTimeFreeListHead = NULL;
  24. PRM_DUE_TIME_MONITORED_LIST_HEAD g_pRmDueTimeMonitoredListHead = NULL;
  25. CRITICAL_SECTION g_RmDeadlockListLock;
  26. BOOL g_RmDeadlockMonitorInitialized = FALSE;
  27. PRM_DUE_TIME_ENTRY
  28. RmpInsertDeadlockMonitorList(
  29. IN LPCWSTR lpszResourceDllName,
  30. IN LPCWSTR lpszResourceTypeName,
  31. IN LPCWSTR lpszResourceName, OPTIONAL
  32. IN LPCWSTR lpszEntryPointName
  33. )
  34. /*++
  35. Routine Description:
  36. Inserts an entry into the deadlock monitoring list.
  37. Arguments:
  38. lpszResourceDllName - Resource dll name.
  39. lpszResourceTypeName - Resource type name.
  40. lpszResourceName - Resource name, OPTIONAL
  41. lpszEntryPointName - Entry point name.
  42. Return Value:
  43. A valid due time entry pointer on success, NULL on failure. Use GetLastError() to
  44. get error code.
  45. --*/
  46. {
  47. PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
  48. DWORD dwStatus = ERROR_SUCCESS;
  49. PLIST_ENTRY pListEntry;
  50. if ( !g_RmDeadlockMonitorInitialized )
  51. {
  52. SetLastError ( ERROR_INVALID_STATE );
  53. return ( NULL );
  54. }
  55. //
  56. // Get an entry from the free list.
  57. //
  58. EnterCriticalSection ( &g_RmDeadlockListLock );
  59. if ( IsListEmpty ( &g_pRmDueTimeFreeListHead->leDueTimeEntry ) )
  60. {
  61. dwStatus = ERROR_NO_MORE_ITEMS;
  62. ClRtlLogPrint(LOG_CRITICAL,
  63. "[RM] RmpInsertDeadlockMonitorList: Unable to insert DLL '%1!ws!', Type '%2!ws!', Resource '%3!ws!',"
  64. " Entry point '%4!ws!' info into deadlock monitoring list\n",
  65. lpszResourceDllName,
  66. lpszResourceTypeName,
  67. (lpszResourceName == NULL) ? L"Unknown" : lpszResourceName,
  68. lpszEntryPointName);
  69. LeaveCriticalSection ( &g_RmDeadlockListLock );
  70. goto FnExit;
  71. }
  72. pListEntry = RemoveHeadList( &g_pRmDueTimeFreeListHead->leDueTimeEntry );
  73. pDueTimeEntry = CONTAINING_RECORD( pListEntry,
  74. RM_DUE_TIME_ENTRY,
  75. leDueTimeEntry );
  76. LeaveCriticalSection ( &g_RmDeadlockListLock );
  77. //
  78. // Populate the entry. No locks needed for that.
  79. //
  80. StringCchCopy ( pDueTimeEntry->szResourceDllName,
  81. RTL_NUMBER_OF ( pDueTimeEntry->szResourceDllName ),
  82. lpszResourceDllName );
  83. StringCchCopy ( pDueTimeEntry->szResourceTypeName,
  84. RTL_NUMBER_OF ( pDueTimeEntry->szResourceTypeName ),
  85. lpszResourceTypeName );
  86. StringCchCopy ( pDueTimeEntry->szEntryPointName,
  87. RTL_NUMBER_OF ( pDueTimeEntry->szEntryPointName ),
  88. lpszEntryPointName );
  89. if ( ARGUMENT_PRESENT ( lpszResourceName ) )
  90. {
  91. StringCchCopy ( pDueTimeEntry->szResourceName,
  92. RTL_NUMBER_OF ( pDueTimeEntry->szResourceName ),
  93. lpszResourceName );
  94. } else
  95. {
  96. StringCchCopy ( pDueTimeEntry->szResourceName,
  97. RTL_NUMBER_OF ( pDueTimeEntry->szResourceName ),
  98. L"None" );
  99. }
  100. pDueTimeEntry->dwSignature = RM_DUE_TIME_MONITORED_ENTRY_SIGNATURE;
  101. GetSystemTimeAsFileTime( ( FILETIME * ) &pDueTimeEntry->uliDueTime );
  102. pDueTimeEntry->dwThreadId = GetCurrentThreadId ();
  103. //
  104. // Insert it into the monitoring list
  105. //
  106. EnterCriticalSection ( &g_RmDeadlockListLock );
  107. pDueTimeEntry->uliDueTime.QuadPart += g_pRmDueTimeMonitoredListHead->ullDeadLockTimeoutSecs * FILETIMES_PER_SEC;
  108. InsertTailList ( &g_pRmDueTimeMonitoredListHead->leDueTimeEntry, &pDueTimeEntry->leDueTimeEntry );
  109. LeaveCriticalSection ( &g_RmDeadlockListLock );
  110. FnExit:
  111. if ( dwStatus != ERROR_SUCCESS )
  112. {
  113. SetLastError ( dwStatus );
  114. }
  115. return ( pDueTimeEntry );
  116. } // RmpInsertDeadlockMonitorList
  117. VOID
  118. RmpRemoveDeadlockMonitorList(
  119. IN PRM_DUE_TIME_ENTRY pDueTimeEntry
  120. )
  121. /*++
  122. Routine Description:
  123. Removes an entry from the deadlock monitoring list.
  124. Arguments:
  125. pDueTimeEntry - Due time entry to be removed.
  126. Return Value:
  127. None.
  128. --*/
  129. {
  130. if ( !g_RmDeadlockMonitorInitialized )
  131. {
  132. goto FnExit;
  133. }
  134. if ( pDueTimeEntry == NULL )
  135. {
  136. ClRtlLogPrint(LOG_CRITICAL,
  137. "[RM] RmpRemoveDeadlockMonitorList: Unable to remove NULL entry from deadlock monitoring list\n");
  138. goto FnExit;
  139. }
  140. //
  141. // Remove from the monitoring list and add it into the free list.
  142. //
  143. EnterCriticalSection ( &g_RmDeadlockListLock );
  144. RemoveEntryList ( &pDueTimeEntry->leDueTimeEntry );
  145. ZeroMemory ( pDueTimeEntry, sizeof ( RM_DUE_TIME_ENTRY ) );
  146. pDueTimeEntry->dwSignature = RM_DUE_TIME_FREE_ENTRY_SIGNATURE;
  147. InsertTailList ( &g_pRmDueTimeFreeListHead->leDueTimeEntry, &pDueTimeEntry->leDueTimeEntry );
  148. LeaveCriticalSection ( &g_RmDeadlockListLock );
  149. FnExit:
  150. return;
  151. } // RmpRemoveDeadlockMonitorList
  152. DWORD
  153. RmpDeadlockMonitorInitialize(
  154. IN DWORD dwDeadlockDetectionTimeout
  155. )
  156. /*++
  157. Routine Description:
  158. Initialize the deadlock monitoring system.
  159. Arguments:
  160. None.
  161. Return Value:
  162. ERROR_SUCCESS on success, a Win32 error code otherwise.
  163. --*/
  164. {
  165. DWORD i, dwStatus = ERROR_SUCCESS;
  166. HANDLE hDeadlockTimerThread = NULL;
  167. PRM_DUE_TIME_ENTRY pDueTimeEntryStart = NULL;
  168. //
  169. // If the deadlock monitoring susbsystem is already initialized, you are done.
  170. //
  171. if ( g_RmDeadlockMonitorInitialized )
  172. {
  173. return ( ERROR_SUCCESS );
  174. }
  175. //
  176. // Adjust timeouts so that it is at least equal to the minimum allowed.
  177. //
  178. dwDeadlockDetectionTimeout = ( dwDeadlockDetectionTimeout < CLUSTER_RESOURCE_DLL_MINIMUM_DEADLOCK_TIMEOUT_SECS ) ?
  179. CLUSTER_RESOURCE_DLL_MINIMUM_DEADLOCK_TIMEOUT_SECS : dwDeadlockDetectionTimeout;
  180. //
  181. // Initialize the critsec. Catch low memory conditions and return error to caller.
  182. //
  183. try
  184. {
  185. InitializeCriticalSection( &g_RmDeadlockListLock );
  186. } except ( EXCEPTION_EXECUTE_HANDLER )
  187. {
  188. dwStatus = GetExceptionCode();
  189. ClRtlLogPrint(LOG_CRITICAL,
  190. "[RM] RmpDeadlockMonitorInitialize: Initialize critsec returned %1!u!\n",
  191. dwStatus);
  192. return ( dwStatus );
  193. }
  194. //
  195. // Build the list heads. All are one time only allocs that are never freed.
  196. //
  197. g_pRmDueTimeMonitoredListHead = LocalAlloc ( LPTR, sizeof ( RM_DUE_TIME_MONITORED_LIST_HEAD ) );
  198. if ( g_pRmDueTimeMonitoredListHead == NULL )
  199. {
  200. dwStatus = GetLastError ();
  201. ClRtlLogPrint(LOG_CRITICAL,
  202. "[RM] RmpDeadlockMonitorInitialize: Unable to alloc memory for monitor list head, status %1!u!\n",
  203. dwStatus);
  204. goto FnExit;
  205. }
  206. InitializeListHead ( &g_pRmDueTimeMonitoredListHead->leDueTimeEntry );
  207. g_pRmDueTimeMonitoredListHead->ullDeadLockTimeoutSecs = dwDeadlockDetectionTimeout;
  208. g_pRmDueTimeMonitoredListHead->dwSignature = RM_DUE_TIME_MONITORED_LIST_HEAD_SIGNATURE;
  209. g_pRmDueTimeFreeListHead = LocalAlloc ( LPTR, sizeof ( RM_DUE_TIME_FREE_LIST_HEAD ) );
  210. if ( g_pRmDueTimeFreeListHead == NULL )
  211. {
  212. dwStatus = GetLastError ();
  213. ClRtlLogPrint(LOG_CRITICAL,
  214. "[RM] RmpDeadlockMonitorInitialize: Unable to alloc memory for free list head, status %1!u!\n",
  215. dwStatus);
  216. goto FnExit;
  217. }
  218. InitializeListHead ( &g_pRmDueTimeFreeListHead->leDueTimeEntry );
  219. g_pRmDueTimeFreeListHead->dwSignature = RM_DUE_TIME_FREE_LIST_HEAD_SIGNATURE;
  220. //
  221. // Build the free list
  222. //
  223. pDueTimeEntryStart = LocalAlloc ( LPTR,
  224. RESMON_MAX_DEADLOCK_MONITOR_ENTRIES *
  225. sizeof ( RM_DUE_TIME_ENTRY ) );
  226. if ( pDueTimeEntryStart == NULL )
  227. {
  228. dwStatus = GetLastError ();
  229. ClRtlLogPrint(LOG_CRITICAL,
  230. "[RM] RmpDeadlockMonitorInitialize: Unable to alloc memory for monitor list entries, status %1!u!\n",
  231. dwStatus);
  232. goto FnExit;
  233. }
  234. //
  235. // Populate the free list
  236. //
  237. for ( i = 0; i < RESMON_MAX_DEADLOCK_MONITOR_ENTRIES; i++ )
  238. {
  239. pDueTimeEntryStart[i].dwSignature = RM_DUE_TIME_FREE_ENTRY_SIGNATURE;
  240. InsertTailList ( &g_pRmDueTimeFreeListHead->leDueTimeEntry, &pDueTimeEntryStart[i].leDueTimeEntry );
  241. }
  242. //
  243. // Create the monitor thread
  244. //
  245. hDeadlockTimerThread = CreateThread( NULL, // Security attributes
  246. 0, // Use default process stack size
  247. RmpDeadlockTimerThread, // Function address
  248. NULL, // Context
  249. 0, // Flags
  250. NULL ); // Thread ID -- not interested
  251. if ( hDeadlockTimerThread == NULL )
  252. {
  253. dwStatus = GetLastError ();
  254. ClRtlLogPrint(LOG_CRITICAL,
  255. "[RM] RmpDeadlockMonitorInitialize: Unable to create monitor thread, status %1!u!\n",
  256. dwStatus);
  257. goto FnExit;
  258. }
  259. //
  260. // Try to set the thread priority to highest. Continue even in case of an error.
  261. //
  262. if ( !SetThreadPriority( hDeadlockTimerThread, THREAD_PRIORITY_HIGHEST ) )
  263. {
  264. ClRtlLogPrint(LOG_UNUSUAL,
  265. "[RM] RmpDeadlockMonitorInitialize: Unable to set monitor thread priority, status %1!u!\n",
  266. GetLastError());
  267. }
  268. CloseHandle( hDeadlockTimerThread );
  269. g_RmDeadlockMonitorInitialized = TRUE;
  270. ClRtlLogPrint(LOG_NOISE, "[RM] RmpDeadlockMonitorInitialize: Successfully initialized with a timeout of %1!u! secs\n",
  271. dwDeadlockDetectionTimeout);
  272. FnExit:
  273. if ( dwStatus != ERROR_SUCCESS )
  274. {
  275. LocalFree ( g_pRmDueTimeMonitoredListHead );
  276. g_pRmDueTimeMonitoredListHead = NULL;
  277. LocalFree ( g_pRmDueTimeFreeListHead );
  278. g_pRmDueTimeFreeListHead = NULL;
  279. DeleteCriticalSection ( &g_RmDeadlockListLock );
  280. }
  281. return ( dwStatus );
  282. } // RmDeadlockMonitorInitialize
  283. DWORD
  284. RmpDeadlockTimerThread(
  285. IN LPVOID pContext
  286. )
  287. /*++
  288. Routine Description:
  289. Timer thread that monitors for deadlocks in resource dll entry points.
  290. Arguments:
  291. pContext - Context, Unused.
  292. Returns:
  293. ERROR_SUCCESS on success. Win32 error code of failure.
  294. --*/
  295. {
  296. PRM_DUE_TIME_ENTRY pDueTimeEntry;
  297. PLIST_ENTRY pListEntry;
  298. ULARGE_INTEGER uliCurrentTime;
  299. while ( TRUE )
  300. {
  301. Sleep ( RESMON_DEADLOCK_TIMER_INTERVAL );
  302. GetSystemTimeAsFileTime ( ( FILETIME * ) &uliCurrentTime );
  303. EnterCriticalSection ( &g_RmDeadlockListLock );
  304. pListEntry = g_pRmDueTimeMonitoredListHead->leDueTimeEntry.Flink;
  305. //
  306. // Walk the deadlock monitoring list looking for a deadlock.
  307. //
  308. while ( pListEntry != &g_pRmDueTimeMonitoredListHead->leDueTimeEntry )
  309. {
  310. pDueTimeEntry = CONTAINING_RECORD( pListEntry,
  311. RM_DUE_TIME_ENTRY,
  312. leDueTimeEntry );
  313. pListEntry = pListEntry->Flink;
  314. if ( pDueTimeEntry->uliDueTime.QuadPart <= uliCurrentTime.QuadPart )
  315. {
  316. RmpDeclareDeadlock ( pDueTimeEntry, uliCurrentTime );
  317. }
  318. } // while
  319. LeaveCriticalSection ( & g_RmDeadlockListLock );
  320. } // while
  321. return ( ERROR_SUCCESS );
  322. }// RmpDeadlockTimerThread
  323. VOID
  324. RmpDeclareDeadlock(
  325. IN PRM_DUE_TIME_ENTRY pDueTimeEntry,
  326. IN ULARGE_INTEGER uliCurrentTime
  327. )
  328. /*++
  329. Routine Description:
  330. Declare a deadlock and exit this process.
  331. Arguments:
  332. pDueTimeEntry - The entry that contains information of possible deadlock causing resource dll.
  333. uliCurrentTime - Current time.
  334. Returns:
  335. None.
  336. --*/
  337. {
  338. ClRtlLogPrint(LOG_CRITICAL, "[RM] RmpDeclareDeadlock: Declaring deadlock and exiting process\n");
  339. ClRtlLogPrint(LOG_CRITICAL,
  340. "[RM] RmpDeclareDeadlock: Deadlock candidate info - DLL '%1!ws!', Type '%2!ws!', Resource '%3!ws!', Entry point '%4!ws!', Thread 0x%5!08lx!\n",
  341. pDueTimeEntry->szResourceDllName,
  342. pDueTimeEntry->szResourceTypeName,
  343. pDueTimeEntry->szResourceName,
  344. pDueTimeEntry->szEntryPointName,
  345. pDueTimeEntry->dwThreadId);
  346. ClRtlLogPrint(LOG_CRITICAL,
  347. "[RM] RmpDeclareDeadlock: Current time 0x%1!08lx!:%2!08lx!, due time 0x%3!08lx!:%4!08lx!\n",
  348. uliCurrentTime.HighPart,
  349. uliCurrentTime.LowPart,
  350. pDueTimeEntry->uliDueTime.HighPart,
  351. pDueTimeEntry->uliDueTime.LowPart);
  352. ClusterLogEvent4(LOG_CRITICAL,
  353. LOG_CURRENT_MODULE,
  354. __FILE__,
  355. __LINE__,
  356. RMON_DEADLOCK_DETECTED,
  357. 0,
  358. NULL,
  359. pDueTimeEntry->szResourceDllName,
  360. pDueTimeEntry->szResourceTypeName,
  361. pDueTimeEntry->szResourceName,
  362. pDueTimeEntry->szEntryPointName);
  363. RmpSetMonitorState ( RmonDeadlocked, NULL );
  364. ExitProcess ( 0 );
  365. }// RmpDeclareDeadlock
  366. DWORD
  367. RmpUpdateDeadlockDetectionParams(
  368. IN DWORD dwDeadlockDetectionTimeout
  369. )
  370. /*++
  371. Routine Description:
  372. Update the parameters of the deadlock monitoring subsystem.
  373. Arguments:
  374. dwDeadlockDetectionTimeout - The deadlock detection timeout.
  375. Return Value:
  376. ERROR_SUCCESS on success, a Win32 error code otherwise.
  377. --*/
  378. {
  379. if ( !g_RmDeadlockMonitorInitialized )
  380. {
  381. ClRtlLogPrint(LOG_UNUSUAL, "[RM] RmpUpdateDeadlockDetectionParams: Deadlock monitor not initialized yet\n");
  382. return ( ERROR_INVALID_STATE );
  383. }
  384. //
  385. // Adjust timeouts so that it is at least equal to the minimum allowed.
  386. //
  387. dwDeadlockDetectionTimeout = ( dwDeadlockDetectionTimeout < CLUSTER_RESOURCE_DLL_MINIMUM_DEADLOCK_TIMEOUT_SECS ) ?
  388. CLUSTER_RESOURCE_DLL_MINIMUM_DEADLOCK_TIMEOUT_SECS : dwDeadlockDetectionTimeout;
  389. EnterCriticalSection ( &g_RmDeadlockListLock );
  390. g_pRmDueTimeMonitoredListHead->ullDeadLockTimeoutSecs = dwDeadlockDetectionTimeout;
  391. LeaveCriticalSection ( &g_RmDeadlockListLock );
  392. ClRtlLogPrint(LOG_NOISE, "[RM] RmpUpdateDeadlockDetectionParams: Updated monitor with a deadlock timeout of %1!u! secs\n",
  393. dwDeadlockDetectionTimeout);
  394. return ( ERROR_SUCCESS );
  395. } // RmpUpdateDeadlockDetectionParams