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
522 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1996-2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dlock.c
|
|
|
|
Abstract:
|
|
|
|
Functions for detecting deadlocked resource dll entry point calls.
|
|
|
|
Author:
|
|
|
|
Chittur Subbaraman
|
|
|
|
Revision History:
|
|
|
|
04-11-2002 Created
|
|
|
|
--*/
|
|
#define UNICODE 1
|
|
|
|
#include "nt.h"
|
|
#include "ntrtl.h"
|
|
#include "nturtl.h"
|
|
#include "resmonp.h"
|
|
#include <strsafe.h>
|
|
|
|
#define RESMON_MODULE RESMON_MODULE_DLOCK
|
|
#define FILETIMES_PER_SEC ((__int64) 10000000) // (1 second)/(100 ns)
|
|
|
|
//
|
|
// Globals
|
|
//
|
|
PRM_DUE_TIME_FREE_LIST_HEAD g_pRmDueTimeFreeListHead = NULL;
|
|
PRM_DUE_TIME_MONITORED_LIST_HEAD g_pRmDueTimeMonitoredListHead = NULL;
|
|
CRITICAL_SECTION g_RmDeadlockListLock;
|
|
BOOL g_RmDeadlockMonitorInitialized = FALSE;
|
|
|
|
PRM_DUE_TIME_ENTRY
|
|
RmpInsertDeadlockMonitorList(
|
|
IN LPCWSTR lpszResourceDllName,
|
|
IN LPCWSTR lpszResourceTypeName,
|
|
IN LPCWSTR lpszResourceName, OPTIONAL
|
|
IN LPCWSTR lpszEntryPointName
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Inserts an entry into the deadlock monitoring list.
|
|
|
|
Arguments:
|
|
|
|
lpszResourceDllName - Resource dll name.
|
|
|
|
lpszResourceTypeName - Resource type name.
|
|
|
|
lpszResourceName - Resource name, OPTIONAL
|
|
|
|
lpszEntryPointName - Entry point name.
|
|
|
|
Return Value:
|
|
|
|
A valid due time entry pointer on success, NULL on failure. Use GetLastError() to
|
|
get error code.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRM_DUE_TIME_ENTRY pDueTimeEntry = NULL;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
PLIST_ENTRY pListEntry;
|
|
|
|
if ( !g_RmDeadlockMonitorInitialized )
|
|
{
|
|
SetLastError ( ERROR_INVALID_STATE );
|
|
return ( NULL );
|
|
}
|
|
|
|
//
|
|
// Get an entry from the free list.
|
|
//
|
|
EnterCriticalSection ( &g_RmDeadlockListLock );
|
|
|
|
if ( IsListEmpty ( &g_pRmDueTimeFreeListHead->leDueTimeEntry ) )
|
|
{
|
|
dwStatus = ERROR_NO_MORE_ITEMS;
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[RM] RmpInsertDeadlockMonitorList: Unable to insert DLL '%1!ws!', Type '%2!ws!', Resource '%3!ws!',"
|
|
" Entry point '%4!ws!' info into deadlock monitoring list\n",
|
|
lpszResourceDllName,
|
|
lpszResourceTypeName,
|
|
(lpszResourceName == NULL) ? L"Unknown" : lpszResourceName,
|
|
lpszEntryPointName);
|
|
LeaveCriticalSection ( &g_RmDeadlockListLock );
|
|
goto FnExit;
|
|
}
|
|
|
|
pListEntry = RemoveHeadList( &g_pRmDueTimeFreeListHead->leDueTimeEntry );
|
|
|
|
pDueTimeEntry = CONTAINING_RECORD( pListEntry,
|
|
RM_DUE_TIME_ENTRY,
|
|
leDueTimeEntry );
|
|
|
|
LeaveCriticalSection ( &g_RmDeadlockListLock );
|
|
|
|
//
|
|
// Populate the entry. No locks needed for that.
|
|
//
|
|
StringCchCopy ( pDueTimeEntry->szResourceDllName,
|
|
RTL_NUMBER_OF ( pDueTimeEntry->szResourceDllName ),
|
|
lpszResourceDllName );
|
|
|
|
StringCchCopy ( pDueTimeEntry->szResourceTypeName,
|
|
RTL_NUMBER_OF ( pDueTimeEntry->szResourceTypeName ),
|
|
lpszResourceTypeName );
|
|
|
|
StringCchCopy ( pDueTimeEntry->szEntryPointName,
|
|
RTL_NUMBER_OF ( pDueTimeEntry->szEntryPointName ),
|
|
lpszEntryPointName );
|
|
|
|
if ( ARGUMENT_PRESENT ( lpszResourceName ) )
|
|
{
|
|
StringCchCopy ( pDueTimeEntry->szResourceName,
|
|
RTL_NUMBER_OF ( pDueTimeEntry->szResourceName ),
|
|
lpszResourceName );
|
|
} else
|
|
{
|
|
StringCchCopy ( pDueTimeEntry->szResourceName,
|
|
RTL_NUMBER_OF ( pDueTimeEntry->szResourceName ),
|
|
L"None" );
|
|
}
|
|
|
|
pDueTimeEntry->dwSignature = RM_DUE_TIME_MONITORED_ENTRY_SIGNATURE;
|
|
GetSystemTimeAsFileTime( ( FILETIME * ) &pDueTimeEntry->uliDueTime );
|
|
pDueTimeEntry->dwThreadId = GetCurrentThreadId ();
|
|
|
|
//
|
|
// Insert it into the monitoring list
|
|
//
|
|
EnterCriticalSection ( &g_RmDeadlockListLock );
|
|
pDueTimeEntry->uliDueTime.QuadPart += g_pRmDueTimeMonitoredListHead->ullDeadLockTimeoutSecs * FILETIMES_PER_SEC;
|
|
InsertTailList ( &g_pRmDueTimeMonitoredListHead->leDueTimeEntry, &pDueTimeEntry->leDueTimeEntry );
|
|
LeaveCriticalSection ( &g_RmDeadlockListLock );
|
|
|
|
FnExit:
|
|
if ( dwStatus != ERROR_SUCCESS )
|
|
{
|
|
SetLastError ( dwStatus );
|
|
}
|
|
return ( pDueTimeEntry );
|
|
} // RmpInsertDeadlockMonitorList
|
|
|
|
VOID
|
|
RmpRemoveDeadlockMonitorList(
|
|
IN PRM_DUE_TIME_ENTRY pDueTimeEntry
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes an entry from the deadlock monitoring list.
|
|
|
|
Arguments:
|
|
|
|
pDueTimeEntry - Due time entry to be removed.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if ( !g_RmDeadlockMonitorInitialized )
|
|
{
|
|
goto FnExit;
|
|
}
|
|
|
|
if ( pDueTimeEntry == NULL )
|
|
{
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[RM] RmpRemoveDeadlockMonitorList: Unable to remove NULL entry from deadlock monitoring list\n");
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Remove from the monitoring list and add it into the free list.
|
|
//
|
|
EnterCriticalSection ( &g_RmDeadlockListLock );
|
|
RemoveEntryList ( &pDueTimeEntry->leDueTimeEntry );
|
|
ZeroMemory ( pDueTimeEntry, sizeof ( RM_DUE_TIME_ENTRY ) );
|
|
pDueTimeEntry->dwSignature = RM_DUE_TIME_FREE_ENTRY_SIGNATURE;
|
|
InsertTailList ( &g_pRmDueTimeFreeListHead->leDueTimeEntry, &pDueTimeEntry->leDueTimeEntry );
|
|
LeaveCriticalSection ( &g_RmDeadlockListLock );
|
|
|
|
FnExit:
|
|
return;
|
|
} // RmpRemoveDeadlockMonitorList
|
|
|
|
DWORD
|
|
RmpDeadlockMonitorInitialize(
|
|
IN DWORD dwDeadlockDetectionTimeout
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize the deadlock monitoring system.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS on success, a Win32 error code otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD i, dwStatus = ERROR_SUCCESS;
|
|
HANDLE hDeadlockTimerThread = NULL;
|
|
PRM_DUE_TIME_ENTRY pDueTimeEntryStart = NULL;
|
|
|
|
//
|
|
// If the deadlock monitoring susbsystem is already initialized, you are done.
|
|
//
|
|
if ( g_RmDeadlockMonitorInitialized )
|
|
{
|
|
return ( ERROR_SUCCESS );
|
|
}
|
|
|
|
//
|
|
// Adjust timeouts so that it is at least equal to the minimum allowed.
|
|
//
|
|
dwDeadlockDetectionTimeout = ( dwDeadlockDetectionTimeout < CLUSTER_RESOURCE_DLL_MINIMUM_DEADLOCK_TIMEOUT_SECS ) ?
|
|
CLUSTER_RESOURCE_DLL_MINIMUM_DEADLOCK_TIMEOUT_SECS : dwDeadlockDetectionTimeout;
|
|
|
|
//
|
|
// Initialize the critsec. Catch low memory conditions and return error to caller.
|
|
//
|
|
try
|
|
{
|
|
InitializeCriticalSection( &g_RmDeadlockListLock );
|
|
} except ( EXCEPTION_EXECUTE_HANDLER )
|
|
{
|
|
dwStatus = GetExceptionCode();
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[RM] RmpDeadlockMonitorInitialize: Initialize critsec returned %1!u!\n",
|
|
dwStatus);
|
|
return ( dwStatus );
|
|
}
|
|
|
|
//
|
|
// Build the list heads. All are one time only allocs that are never freed.
|
|
//
|
|
g_pRmDueTimeMonitoredListHead = LocalAlloc ( LPTR, sizeof ( RM_DUE_TIME_MONITORED_LIST_HEAD ) );
|
|
|
|
if ( g_pRmDueTimeMonitoredListHead == NULL )
|
|
{
|
|
dwStatus = GetLastError ();
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[RM] RmpDeadlockMonitorInitialize: Unable to alloc memory for monitor list head, status %1!u!\n",
|
|
dwStatus);
|
|
goto FnExit;
|
|
}
|
|
|
|
InitializeListHead ( &g_pRmDueTimeMonitoredListHead->leDueTimeEntry );
|
|
g_pRmDueTimeMonitoredListHead->ullDeadLockTimeoutSecs = dwDeadlockDetectionTimeout;
|
|
g_pRmDueTimeMonitoredListHead->dwSignature = RM_DUE_TIME_MONITORED_LIST_HEAD_SIGNATURE;
|
|
|
|
g_pRmDueTimeFreeListHead = LocalAlloc ( LPTR, sizeof ( RM_DUE_TIME_FREE_LIST_HEAD ) );
|
|
|
|
if ( g_pRmDueTimeFreeListHead == NULL )
|
|
{
|
|
dwStatus = GetLastError ();
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[RM] RmpDeadlockMonitorInitialize: Unable to alloc memory for free list head, status %1!u!\n",
|
|
dwStatus);
|
|
goto FnExit;
|
|
}
|
|
|
|
InitializeListHead ( &g_pRmDueTimeFreeListHead->leDueTimeEntry );
|
|
g_pRmDueTimeFreeListHead->dwSignature = RM_DUE_TIME_FREE_LIST_HEAD_SIGNATURE;
|
|
|
|
//
|
|
// Build the free list
|
|
//
|
|
pDueTimeEntryStart = LocalAlloc ( LPTR,
|
|
RESMON_MAX_DEADLOCK_MONITOR_ENTRIES *
|
|
sizeof ( RM_DUE_TIME_ENTRY ) );
|
|
|
|
|
|
if ( pDueTimeEntryStart == NULL )
|
|
{
|
|
dwStatus = GetLastError ();
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[RM] RmpDeadlockMonitorInitialize: Unable to alloc memory for monitor list entries, status %1!u!\n",
|
|
dwStatus);
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Populate the free list
|
|
//
|
|
for ( i = 0; i < RESMON_MAX_DEADLOCK_MONITOR_ENTRIES; i++ )
|
|
{
|
|
pDueTimeEntryStart[i].dwSignature = RM_DUE_TIME_FREE_ENTRY_SIGNATURE;
|
|
InsertTailList ( &g_pRmDueTimeFreeListHead->leDueTimeEntry, &pDueTimeEntryStart[i].leDueTimeEntry );
|
|
}
|
|
|
|
//
|
|
// Create the monitor thread
|
|
//
|
|
hDeadlockTimerThread = CreateThread( NULL, // Security attributes
|
|
0, // Use default process stack size
|
|
RmpDeadlockTimerThread, // Function address
|
|
NULL, // Context
|
|
0, // Flags
|
|
NULL ); // Thread ID -- not interested
|
|
|
|
if ( hDeadlockTimerThread == NULL )
|
|
{
|
|
dwStatus = GetLastError ();
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[RM] RmpDeadlockMonitorInitialize: Unable to create monitor thread, status %1!u!\n",
|
|
dwStatus);
|
|
goto FnExit;
|
|
}
|
|
|
|
//
|
|
// Try to set the thread priority to highest. Continue even in case of an error.
|
|
//
|
|
if ( !SetThreadPriority( hDeadlockTimerThread, THREAD_PRIORITY_HIGHEST ) )
|
|
{
|
|
ClRtlLogPrint(LOG_UNUSUAL,
|
|
"[RM] RmpDeadlockMonitorInitialize: Unable to set monitor thread priority, status %1!u!\n",
|
|
GetLastError());
|
|
}
|
|
|
|
CloseHandle( hDeadlockTimerThread );
|
|
|
|
g_RmDeadlockMonitorInitialized = TRUE;
|
|
|
|
ClRtlLogPrint(LOG_NOISE, "[RM] RmpDeadlockMonitorInitialize: Successfully initialized with a timeout of %1!u! secs\n",
|
|
dwDeadlockDetectionTimeout);
|
|
|
|
FnExit:
|
|
if ( dwStatus != ERROR_SUCCESS )
|
|
{
|
|
LocalFree ( g_pRmDueTimeMonitoredListHead );
|
|
g_pRmDueTimeMonitoredListHead = NULL;
|
|
LocalFree ( g_pRmDueTimeFreeListHead );
|
|
g_pRmDueTimeFreeListHead = NULL;
|
|
DeleteCriticalSection ( &g_RmDeadlockListLock );
|
|
}
|
|
|
|
return ( dwStatus );
|
|
} // RmDeadlockMonitorInitialize
|
|
|
|
DWORD
|
|
RmpDeadlockTimerThread(
|
|
IN LPVOID pContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Timer thread that monitors for deadlocks in resource dll entry points.
|
|
|
|
Arguments:
|
|
|
|
pContext - Context, Unused.
|
|
|
|
Returns:
|
|
|
|
ERROR_SUCCESS on success. Win32 error code of failure.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRM_DUE_TIME_ENTRY pDueTimeEntry;
|
|
PLIST_ENTRY pListEntry;
|
|
ULARGE_INTEGER uliCurrentTime;
|
|
|
|
while ( TRUE )
|
|
{
|
|
Sleep ( RESMON_DEADLOCK_TIMER_INTERVAL );
|
|
|
|
GetSystemTimeAsFileTime ( ( FILETIME * ) &uliCurrentTime );
|
|
|
|
EnterCriticalSection ( &g_RmDeadlockListLock );
|
|
|
|
pListEntry = g_pRmDueTimeMonitoredListHead->leDueTimeEntry.Flink;
|
|
|
|
//
|
|
// Walk the deadlock monitoring list looking for a deadlock.
|
|
//
|
|
while ( pListEntry != &g_pRmDueTimeMonitoredListHead->leDueTimeEntry )
|
|
{
|
|
pDueTimeEntry = CONTAINING_RECORD( pListEntry,
|
|
RM_DUE_TIME_ENTRY,
|
|
leDueTimeEntry );
|
|
pListEntry = pListEntry->Flink;
|
|
if ( pDueTimeEntry->uliDueTime.QuadPart <= uliCurrentTime.QuadPart )
|
|
{
|
|
RmpDeclareDeadlock ( pDueTimeEntry, uliCurrentTime );
|
|
}
|
|
} // while
|
|
|
|
LeaveCriticalSection ( & g_RmDeadlockListLock );
|
|
} // while
|
|
|
|
return ( ERROR_SUCCESS );
|
|
}// RmpDeadlockTimerThread
|
|
|
|
VOID
|
|
RmpDeclareDeadlock(
|
|
IN PRM_DUE_TIME_ENTRY pDueTimeEntry,
|
|
IN ULARGE_INTEGER uliCurrentTime
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Declare a deadlock and exit this process.
|
|
|
|
Arguments:
|
|
|
|
pDueTimeEntry - The entry that contains information of possible deadlock causing resource dll.
|
|
|
|
uliCurrentTime - Current time.
|
|
|
|
Returns:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ClRtlLogPrint(LOG_CRITICAL, "[RM] RmpDeclareDeadlock: Declaring deadlock and exiting process\n");
|
|
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[RM] RmpDeclareDeadlock: Deadlock candidate info - DLL '%1!ws!', Type '%2!ws!', Resource '%3!ws!', Entry point '%4!ws!', Thread 0x%5!08lx!\n",
|
|
pDueTimeEntry->szResourceDllName,
|
|
pDueTimeEntry->szResourceTypeName,
|
|
pDueTimeEntry->szResourceName,
|
|
pDueTimeEntry->szEntryPointName,
|
|
pDueTimeEntry->dwThreadId);
|
|
|
|
ClRtlLogPrint(LOG_CRITICAL,
|
|
"[RM] RmpDeclareDeadlock: Current time 0x%1!08lx!:%2!08lx!, due time 0x%3!08lx!:%4!08lx!\n",
|
|
uliCurrentTime.HighPart,
|
|
uliCurrentTime.LowPart,
|
|
pDueTimeEntry->uliDueTime.HighPart,
|
|
pDueTimeEntry->uliDueTime.LowPart);
|
|
|
|
ClusterLogEvent4(LOG_CRITICAL,
|
|
LOG_CURRENT_MODULE,
|
|
__FILE__,
|
|
__LINE__,
|
|
RMON_DEADLOCK_DETECTED,
|
|
0,
|
|
NULL,
|
|
pDueTimeEntry->szResourceDllName,
|
|
pDueTimeEntry->szResourceTypeName,
|
|
pDueTimeEntry->szResourceName,
|
|
pDueTimeEntry->szEntryPointName);
|
|
|
|
RmpSetMonitorState ( RmonDeadlocked, NULL );
|
|
|
|
ExitProcess ( 0 );
|
|
}// RmpDeclareDeadlock
|
|
|
|
DWORD
|
|
RmpUpdateDeadlockDetectionParams(
|
|
IN DWORD dwDeadlockDetectionTimeout
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update the parameters of the deadlock monitoring subsystem.
|
|
|
|
Arguments:
|
|
|
|
dwDeadlockDetectionTimeout - The deadlock detection timeout.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS on success, a Win32 error code otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
if ( !g_RmDeadlockMonitorInitialized )
|
|
{
|
|
ClRtlLogPrint(LOG_UNUSUAL, "[RM] RmpUpdateDeadlockDetectionParams: Deadlock monitor not initialized yet\n");
|
|
return ( ERROR_INVALID_STATE );
|
|
}
|
|
|
|
//
|
|
// Adjust timeouts so that it is at least equal to the minimum allowed.
|
|
//
|
|
dwDeadlockDetectionTimeout = ( dwDeadlockDetectionTimeout < CLUSTER_RESOURCE_DLL_MINIMUM_DEADLOCK_TIMEOUT_SECS ) ?
|
|
CLUSTER_RESOURCE_DLL_MINIMUM_DEADLOCK_TIMEOUT_SECS : dwDeadlockDetectionTimeout;
|
|
|
|
EnterCriticalSection ( &g_RmDeadlockListLock );
|
|
g_pRmDueTimeMonitoredListHead->ullDeadLockTimeoutSecs = dwDeadlockDetectionTimeout;
|
|
LeaveCriticalSection ( &g_RmDeadlockListLock );
|
|
|
|
ClRtlLogPrint(LOG_NOISE, "[RM] RmpUpdateDeadlockDetectionParams: Updated monitor with a deadlock timeout of %1!u! secs\n",
|
|
dwDeadlockDetectionTimeout);
|
|
|
|
return ( ERROR_SUCCESS );
|
|
} // RmpUpdateDeadlockDetectionParams
|