230 lines
4 KiB
C++
230 lines
4 KiB
C++
/*++
|
|
|
|
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;
|
|
}
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
}
|