/*++ Copyright (c) 1998 Microsoft Corporation Module Name: tpsutil.cpp Abstract: Comtains common utility functions for Win32 thread pool services Contents: StartThread TpsEnter QueueNullFunc (NullFunc) Author: Richard L Firth (rfirth) 10-Feb-1998 Environment: Win32 user-mode Notes: Taken from NT-specific code written by Gurdeep Singh Pall (gurdeep) Revision History: 10-Feb-1998 rfirth Created --*/ #include "priv.h" #include "threads.h" // // private prototypes // PRIVATE VOID NullFunc( IN LPVOID pUnused ); // // functions // DWORD StartThread( IN LPTHREAD_START_ROUTINE pfnFunction, OUT PHANDLE phThread, IN BOOL fSynchronize ) /*++ Routine Description: This routine is used start a new thread in the pool. If required, we synchronize with the new thread using an auto-reset event that the new thread must signal once it has completed its initialization Arguments: pfnFunction - pointer to thread function to start phThread - pointer to returned thread handle fSynchronize - used to indicate if we need to synchronize with the new thread before returning Return Value: DWORD Success - ERROR_SUCCESS Failure - ERROR_NOT_ENOUGH_MEMORY Out of memory --*/ { HANDLE hSyncEvent = NULL; if (fSynchronize) { hSyncEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (hSyncEvent == NULL) { return GetLastError(); } } DWORD dwThreadId; HANDLE hThread; DWORD error = ERROR_SUCCESS; hThread = CreateThread(NULL, // lpSecurityAttributes 0, // dwStackSize (0 == same as init thread) pfnFunction, (LPVOID)hSyncEvent, 0, // dwCreationFlags &dwThreadId // throw away ); if (hThread == NULL) { error = GetLastError(); } if (hSyncEvent != NULL) { if (hThread != NULL) { DWORD status = WaitForSingleObject(hSyncEvent, INFINITE); if (status == WAIT_FAILED) { error = GetLastError(); } else if (status == WAIT_TIMEOUT) { error = WAIT_TIMEOUT; } else if (status != WAIT_OBJECT_0) { error = ERROR_GEN_FAILURE; // ? } if (ERROR_SUCCESS != error) { CloseHandle(hThread); hThread = NULL; } } CloseHandle(hSyncEvent); } *phThread = hThread; return error; } DWORD TpsEnter( VOID ) /*++ Routine Description: synchronize with thread shutting down via SHTerminateThreadPool(). If terminating because DLL is unloaded, return error else wait until termination completed Arguments: None. Return Value: DWORD Success - ERROR_SUCCESS Failure - ERROR_SHUTDOWN_IN_PROGRESS --*/ { for (; ; ) { while (g_bTpsTerminating) { if (g_bDllTerminating) { return ERROR_SHUTDOWN_IN_PROGRESS; // error code? looks valid -justmann } SleepEx(0, TRUE); } InterlockedIncrement((LPLONG)&g_ActiveRequests); if (!g_bTpsTerminating) { return ERROR_SUCCESS; } ASSERT( 0 != g_ActiveRequests ); InterlockedDecrement((LPLONG)&g_ActiveRequests); } } VOID QueueNullFunc( IN HANDLE hThread ) /*++ Routine Description: Queues NullFunc as an APC to hThread Arguments: hThread - thread to queue for Return Value: None. --*/ { QueueUserAPC((PAPCFUNC)NullFunc, hThread, NULL); } PRIVATE VOID NullFunc( IN LPVOID pUnused ) /*++ Routine Description: NULL APC function. Used to allow TerminateThreadPool() to wake up dormant APC threads Arguments: pUnused - unused argument pointer Return Value: None. --*/ { }