//+----------------------------------------------------------------------- // // Microsoft Windows // // Copyright (c) Microsoft Corporation // // File: kppool.cxx // // Contents: Routines to manage the thread pool // // History: 10-Jul-2001 t-ryanj Created // //------------------------------------------------------------------------ #include "kppool.h" #include "kpcore.h" #define KP_THREAD_STACKSIZE 0 #define KP_THREAD_CPUFACTOR 10 HANDLE* KpThreadPool = NULL; ULONG KpThreadCount = 0; //+------------------------------------------------------------------------- // // Function: KpInitThreadPool // // Synopsis: Creates the thread pool. // // Effects: // // Arguments: // // Requires: // // Returns: Success status. On failure, no threads are running, no // memory is allocated. // // Notes: TODO: This is a bad way to do threadpools, apparently. // Find a better one. // //-------------------------------------------------------------------------- BOOL KpInitThreadPool( VOID ) { SYSTEM_INFO Sysinfo; ULONG TargetThreadCount; // // Get system info, so we can see how many procs we've got. // GetSystemInfo(&Sysinfo); // // Let's make KP_THREAD_CPUFACTOR * numprocs threads. // TargetThreadCount = Sysinfo.dwNumberOfProcessors * KP_THREAD_CPUFACTOR; // // Make memory to keep track of all these threads. // DsysAssert( KpThreadPool == NULL ); KpThreadPool = (HANDLE*)KpAlloc( TargetThreadCount * sizeof(HANDLE) ); if( !KpThreadPool ) { DebugLog( DEB_ERROR, "%s(%d): Could not allocate memory to keep track of threads.\n" __FILE__, __LINE__ ); goto Error; } // // Zero the memory so we can easily check if a thread creation failed. // RtlZeroMemory( KpThreadPool, TargetThreadCount * sizeof(HANDLE) ); // // Create the Threads // DsysAssert(KpThreadCount == 0); for( KpThreadCount = 0; KpThreadCount < TargetThreadCount; KpThreadCount++ ) { KpThreadPool[KpThreadCount] = CreateThread( NULL, KP_THREAD_STACKSIZE, KpThreadCore, NULL, 0, NULL ); if( !KpThreadPool[KpThreadCount] ) { DebugLog( DEB_ERROR, "%s(%d): Error creating thread: 0x%x.\n", __FILE__, __LINE__, GetLastError() ); goto Error; } } return TRUE; Error: KpCleanupThreadPool(); return FALSE; } //+------------------------------------------------------------------------- // // Function: KpCleanupThreadPool // // Synopsis: Asks all threads to terminate, waits for them to do so, // closes their handles, and frees the memory keeping track of // the threadpool. // // Effects: // // Arguments: // // Requires: // // Returns: // // Notes: // // //-------------------------------------------------------------------------- VOID KpCleanupThreadPool( VOID ) { DWORD dwWaitResult; BOOL fPostStatus; // // Post a terminate request for each thread. // for( ULONG i = KpThreadCount; i > 0; i-- ) { fPostStatus = PostQueuedCompletionStatus(KpGlobalIocp, 0, KPCK_TERMINATE, NULL ); if( !fPostStatus ) { DebugLog( DEB_ERROR, "%s(%d): Unable to post terminate request to the completion port: 0x%x.\n", __FILE__, __LINE__, GetLastError() ); // TODO: Consider if this fails. // we'll probably want to wait for however many threads to terminate // as we were able to post requests, then maybe try again or kill // the rest of the threads } } // // Wait for the threads to terminate // dwWaitResult = WaitForMultipleObjects(KpThreadCount, KpThreadPool, TRUE, INFINITE ); if( dwWaitResult == WAIT_FAILED ) { DebugLog( DEB_ERROR, "%s(%d): Error waiting for thread terminations: 0x%x.", __FILE__, __LINE__, GetLastError() ); } // // Close all the handles // while( KpThreadCount-- ) { CloseHandle(KpThreadPool[KpThreadCount]); } // // Free the memory // KpFree( KpThreadPool ); KpThreadPool = NULL; }