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

/*++
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