/*++ Copyright (c) 1998-2001 Microsoft Corporation Module Name: thrdpool.c Abstract: Implements the thrdpool command. Author: Keith Moore (keithmo) 17-Jun-1998 Environment: User Mode. Revision History: --*/ #include "precomp.h" // // Private constants. // // // Private types. // typedef struct _THREAD_ENUM_STATE { ULONG ThreadNumber; } THREAD_ENUM_STATE, *PTHREAD_ENUM_STATE; // // Private prototypes. // BOOLEAN DumpThreadPoolCallback( IN PLIST_ENTRY pRemoteListEntry, IN PVOID pContext ); // // Public functions. // DECLARE_API( thrdpool ) /*++ Routine Description: Dumps the thread pool at the specified address. Arguments: None. Return Value: None. --*/ { ULONG_PTR address = 0; CLONG count = 1; ULONG_PTR countAddress = 0; CLONG i; UL_THREAD_POOL threadPool; ULONG result; THREAD_ENUM_STATE state; SNAPSHOT_EXTENSION_DATA(); state.ThreadNumber = 0; // // Snag the address from the command line. // address = GetExpression( args ); if (address == 0) { address = GetExpression( "&http!g_UlThreadPool" ); if (address == 0) { dprintf( "thrdpool: Cannot find http!g_UlThreadPool\n" ); return; } countAddress = GetExpression( "&http!g_UlNumberOfProcessors" ); if (countAddress == 0) { dprintf( "thrdpool: Cannot find http!g_UlNumberOfProcessors\n" ); return; } if (!ReadMemory( countAddress, &count, sizeof(count), &result )) { dprintf( "thrdpool: Cannot read http!g_UlNumberOfProcessors at %p.\n", countAddress ); return; } } if (address == 0) { PrintUsage( "thrdpool" ); return; } // g_UlThreadPool[g_UlNumberOfProcessors] == WAIT_THREAD_POOL for (i = 0; i <= count; i++) { if (CheckControlC()) { break; } // // Read the thread pool. // if (!ReadMemory( address, &threadPool, sizeof(threadPool), &result )) { dprintf( "thrdpool: cannot read UL_THREAD_POOL @ %p\n", address ); return; } dprintf( "thrdpool: %sthread pool @ %p (%d)\n" " WorkQueueSList @ %p depth=%d\n" " WorkQueueEvent @ %p\n" " ThreadListHead @ %p%s\n" " pIrpThread = %p\n" " ThreadSpinLock @ %p\n" " Initialized = %s\n" " ThreadCount = %lu\n" " ThreadCpu = %lu\n", (i == count) ? "wait " : "", address, threadPool.ThreadCpu, REMOTE_OFFSET( address, UL_THREAD_POOL, WorkQueueSList ), SLIST_HEADER_DEPTH(&threadPool.WorkQueueSList), address + FIELD_OFFSET( UL_THREAD_POOL, WorkQueueEvent ), REMOTE_OFFSET( address, UL_THREAD_POOL, ThreadListHead ), IS_LIST_EMPTY( &threadPool, address, UL_THREAD_POOL, ThreadListHead ) ? " (EMPTY)" : "", threadPool.pIrpThread, address + FIELD_OFFSET( UL_THREAD_POOL, ThreadSpinLock ), threadPool.Initialized ? "TRUE" : "FALSE", (ULONG)threadPool.ThreadCount, (ULONG)threadPool.ThreadCpu ); EnumLinkedList( (PLIST_ENTRY)REMOTE_OFFSET( address, UL_THREAD_POOL, ThreadListHead ), &DumpThreadPoolCallback, (PVOID)&state ); address += sizeof(threadPool); } } // thrdpool BOOLEAN DumpThreadPoolCallback( IN PLIST_ENTRY pRemoteListEntry, IN PVOID pContext ) { UL_THREAD_TRACKER localTracker; PUL_THREAD_TRACKER pRemoteTracker; PTHREAD_ENUM_STATE pState; ULONG result; CHAR temp[sizeof("1234567812345678 f")]; pState = (PTHREAD_ENUM_STATE)pContext; pRemoteTracker = CONTAINING_RECORD( pRemoteListEntry, UL_THREAD_TRACKER, ThreadListEntry ); if (!ReadMemory( (ULONG_PTR)pRemoteTracker, &localTracker, sizeof(localTracker), &result )) { dprintf( "thrdpool: cannot read UL_THREAD_TRACKER @ %p\n", pRemoteTracker ); return FALSE; } sprintf( temp, "%p f", localTracker.pThread ); #if 0 dprintf( "About to `.thread %p f'\n", localTracker.pThread ); // !kdexts.thread appears to be broken if (!CallExtensionRoutine( "thread", temp )) #endif // 0 { dprintf( " %3lu : %p\n", pState->ThreadNumber, localTracker.pThread ); pState->ThreadNumber++; } return TRUE; } // DumpThreadPoolCallback