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.
625 lines
12 KiB
625 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 1990-2002 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pool.cxx
|
|
|
|
Abstract:
|
|
|
|
Implementation for class ThreadPool.
|
|
|
|
Author:
|
|
|
|
Ali Naqvi (alinaqvi) 3-May-2002
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
#include "pool.hxx"
|
|
|
|
#pragma hdrstop
|
|
|
|
|
|
#define SIZE_OF_TOKEN_INFORMATION \
|
|
sizeof( TOKEN_USER ) \
|
|
+ sizeof( SID ) \
|
|
+ sizeof( ULONG ) * SID_MAX_SUB_AUTHORITIES
|
|
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TThreadPool::TThreadPool
|
|
|
|
Description:
|
|
|
|
Constructor
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
TThreadPool::TThreadPool()
|
|
{
|
|
pHead = NULL;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TThreadPool::~ThreadPool
|
|
|
|
Description:
|
|
|
|
Destructor
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
TThreadPool::~TThreadPool()
|
|
{
|
|
PWIN32THREAD pElem = NULL;
|
|
|
|
while (pHead != NULL)
|
|
{
|
|
pElem = pHead;
|
|
pHead = pHead->pNext;
|
|
|
|
FreeThread(pHead);
|
|
}
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TThreadPool::CreateThreadEntry
|
|
|
|
Description:
|
|
|
|
Create and Initialize a WIN32THREAD object with provided printer name and printer defaults.
|
|
|
|
Arguments:
|
|
|
|
pName - Printer Name
|
|
pDefaults - Printer Defaults
|
|
ppThread - Out parameter pointer to the created WIN32THREAD
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
HRESULT
|
|
TThreadPool::CreateThreadEntry(
|
|
LPWSTR pName,
|
|
PPRINTER_DEFAULTSW pDefaults,
|
|
PWIN32THREAD *ppThread
|
|
)
|
|
{
|
|
PWIN32THREAD pThread = NULL;
|
|
HRESULT hReturn = E_FAIL;
|
|
|
|
SplInSem();
|
|
|
|
hReturn = ppThread && pName ? S_OK : E_INVALIDARG;
|
|
|
|
if (SUCCEEDED(hReturn))
|
|
{
|
|
//
|
|
// Create the thread wrapper object.
|
|
//
|
|
pThread = reinterpret_cast<PWIN32THREAD>(AllocSplMem(sizeof(WIN32THREAD)));
|
|
|
|
hReturn = pThread ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
if(SUCCEEDED(hReturn))
|
|
{
|
|
pThread->signature = TP_SIGNATURE;
|
|
pThread->pName = AllocSplStr(pName);
|
|
|
|
hReturn = pThread->pName ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (SUCCEEDED(hReturn))
|
|
{
|
|
hReturn = GetThreadSid(pThread);
|
|
}
|
|
|
|
if (SUCCEEDED(hReturn))
|
|
{
|
|
pThread->hRpcHandle = NULL;
|
|
|
|
pThread->hWaitValidHandle = CreateEvent(NULL,
|
|
EVENT_RESET_MANUAL,
|
|
EVENT_INITIAL_STATE_NOT_SIGNALED,
|
|
NULL);
|
|
|
|
pThread->dwStatus = THREAD_STATUS_EXECUTING;
|
|
pThread->dwRpcOpenPrinterError = 0;
|
|
|
|
pThread->pDefaults = reinterpret_cast<PPRINTER_DEFAULTSW>(AllocSplMem(sizeof(PRINTER_DEFAULTSW)));
|
|
|
|
hReturn = pThread->pDefaults ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (SUCCEEDED(hReturn))
|
|
{
|
|
pThread->pDefaults->pDatatype = NULL;
|
|
pThread->pDefaults->pDevMode = NULL;
|
|
pThread->pDefaults->DesiredAccess = 0;
|
|
pThread->bForegroundClose = FALSE;
|
|
|
|
hReturn = CopypDefaults(pDefaults, pThread->pDefaults) ? S_OK : E_OUTOFMEMORY;
|
|
|
|
pThread->pNext = NULL;
|
|
}
|
|
|
|
if (SUCCEEDED(hReturn))
|
|
{
|
|
*ppThread = pThread;
|
|
}
|
|
else
|
|
{
|
|
FreeThread(pThread);
|
|
|
|
*ppThread = NULL;
|
|
}
|
|
|
|
return hReturn;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TThreadPool::GetThreadSid
|
|
|
|
Description:
|
|
|
|
Gets the SID from the thread token and makes a copy.
|
|
|
|
Arguments:
|
|
|
|
pThread - Pointer to the WIN32THREAD from which we get our user SID.
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
HRESULT
|
|
TThreadPool::GetThreadSid(
|
|
PWIN32THREAD pThread
|
|
)
|
|
{
|
|
UCHAR ThreadTokenInformation[SIZE_OF_TOKEN_INFORMATION];
|
|
DWORD dwSidLength;
|
|
ULONG ReturnLength;
|
|
HRESULT hReturn = E_FAIL;
|
|
|
|
hReturn = pThread ? S_OK : E_INVALIDARG;
|
|
|
|
if (SUCCEEDED(hReturn))
|
|
{
|
|
hReturn = OpenThreadToken(GetCurrentThread(),
|
|
TOKEN_READ | TOKEN_IMPERSONATE,
|
|
TRUE,
|
|
&(pThread->hToken)) ? S_OK : GetLastErrorAsHResultAndFail();
|
|
}
|
|
|
|
if (SUCCEEDED(hReturn))
|
|
{
|
|
hReturn = GetTokenInformation(pThread->hToken,
|
|
TokenUser,
|
|
ThreadTokenInformation,
|
|
sizeof(ThreadTokenInformation),
|
|
&ReturnLength) ? S_OK : GetLastErrorAsHResultAndFail();
|
|
}
|
|
|
|
if (SUCCEEDED(hReturn))
|
|
{
|
|
dwSidLength = RtlLengthSid((reinterpret_cast<PTOKEN_USER>(ThreadTokenInformation))->User.Sid);
|
|
pThread->pSid = reinterpret_cast<PSID>(AllocSplMem(dwSidLength));
|
|
|
|
hReturn = pThread->pSid ? S_OK : E_OUTOFMEMORY;
|
|
}
|
|
|
|
if (SUCCEEDED(hReturn))
|
|
{
|
|
RtlCopySid( dwSidLength, pThread->pSid, (reinterpret_cast<PTOKEN_USER>(ThreadTokenInformation))->User.Sid);
|
|
}
|
|
|
|
return hReturn;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TThreadPool::DeleteThreadEntry
|
|
|
|
Description:
|
|
|
|
Delink thread item from the threadpool and delete it.
|
|
|
|
Arguments:
|
|
|
|
pThread - Pointer to the WIN322THREAD item to be deleted
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
HRESULT
|
|
TThreadPool::DeleteThreadEntry(
|
|
PWIN32THREAD pThread
|
|
)
|
|
{
|
|
PWIN32THREAD *ppElem = &pHead;
|
|
HRESULT hReturn = E_FAIL;
|
|
|
|
SplInSem();
|
|
|
|
hReturn = pThread ? S_OK : E_INVALIDARG;
|
|
|
|
SPLASSERT(IsValid(pThread));
|
|
|
|
if (SUCCEEDED(hReturn))
|
|
{
|
|
//
|
|
// If the thread is in the pool, delink it.
|
|
//
|
|
while (*ppElem && (*ppElem) != pThread)
|
|
{
|
|
ppElem = &((*ppElem)->pNext);
|
|
}
|
|
|
|
if (*ppElem)
|
|
{
|
|
(*ppElem) = (*ppElem)->pNext;
|
|
}
|
|
|
|
FreeThread(pThread);
|
|
}
|
|
|
|
return hReturn;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TThreadPool::UseThread
|
|
|
|
Description:
|
|
|
|
If exists a thread item for the particular printer name in the pool, it delinks and returns
|
|
a pointer to the thread item.
|
|
|
|
Arguments:
|
|
|
|
pName - Printer Name to be looked for
|
|
ppThread - Pointer to the thread item if found
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
S_OK - If thread item found
|
|
S_FALSE - If thread is not found
|
|
|
|
--*/
|
|
HRESULT
|
|
TThreadPool::UseThread(
|
|
LPWSTR pName,
|
|
PWIN32THREAD *ppThread,
|
|
ACCESS_MASK DesiredAccess
|
|
)
|
|
{
|
|
PWIN32THREAD *ppElem = NULL;
|
|
HRESULT hReturn = E_FAIL;
|
|
PVOID pUserTokenInformation = NULL;
|
|
DWORD dwInformationLength = SIZE_OF_TOKEN_INFORMATION;
|
|
|
|
SplInSem();
|
|
|
|
hReturn = ppThread ? S_OK : E_INVALIDARG;
|
|
|
|
if (SUCCEEDED(hReturn))
|
|
{
|
|
//
|
|
// Get User information for current thread
|
|
//
|
|
pUserTokenInformation = reinterpret_cast<UCHAR*>(AllocSplMem(dwInformationLength));
|
|
hReturn = GetUserTokenInformation(&pUserTokenInformation, dwInformationLength);
|
|
}
|
|
|
|
if (SUCCEEDED(hReturn))
|
|
{
|
|
*ppThread = NULL;
|
|
|
|
//
|
|
// If we dont find a thread we return S_FALSE
|
|
//
|
|
hReturn = S_FALSE;
|
|
|
|
for (ppElem = &pHead; *ppElem; ppElem = &((*ppElem)->pNext))
|
|
{
|
|
//
|
|
// If we found the thread we return it and break.
|
|
//
|
|
if (wcscmp(pName, (*ppElem)->pName) == 0 &&
|
|
IsValidUser(*ppElem, pUserTokenInformation) &&
|
|
(*ppElem)->pDefaults->DesiredAccess == DesiredAccess &&
|
|
(*ppElem)->dwStatus == THREAD_STATUS_EXECUTING)
|
|
{
|
|
*ppThread = *ppElem;
|
|
|
|
*ppElem = (*ppElem)->pNext;
|
|
|
|
hReturn = S_OK;
|
|
|
|
(*ppThread)->pNext = NULL;
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
FreeSplMem(pUserTokenInformation);
|
|
|
|
return hReturn;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TThreadPool::GetUserTokenInformation
|
|
|
|
Description:
|
|
|
|
Returns the current thread users Sid information in the out parameter.
|
|
|
|
Arguments:
|
|
|
|
pUserTokenInformation - Is set to the current user's Sid information
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
HRESULT
|
|
TThreadPool::GetUserTokenInformation(
|
|
PVOID *ppUserTokenInformation,
|
|
DWORD dwInformationLength
|
|
)
|
|
{
|
|
HANDLE UserTokenHandle;
|
|
ULONG ReturnLength;
|
|
HRESULT hResult = E_FAIL;
|
|
|
|
hResult = ppUserTokenInformation ? S_OK : E_INVALIDARG;
|
|
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
hResult = OpenThreadToken( GetCurrentThread(),
|
|
TOKEN_READ,
|
|
TRUE,
|
|
&UserTokenHandle) ? S_OK : E_HANDLE;
|
|
}
|
|
|
|
if (SUCCEEDED(hResult))
|
|
{
|
|
hResult = GetTokenInformation( UserTokenHandle,
|
|
TokenUser,
|
|
*ppUserTokenInformation,
|
|
dwInformationLength,
|
|
&ReturnLength) ? S_OK : E_ACCESSDENIED;
|
|
}
|
|
if (UserTokenHandle)
|
|
{
|
|
CloseHandle(UserTokenHandle);
|
|
}
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TThreadPool::IsValidUser
|
|
|
|
Description:
|
|
|
|
Checks the Sid of the current user to that of the Sid token save in thread and determines if it is
|
|
the same user. Other users cannot use the same RpcHandle therefore cannot use the same thread from
|
|
the pool.
|
|
|
|
Arguments:
|
|
|
|
pThread - The thread whichs Sid we want to check against current user
|
|
|
|
Return Value:
|
|
|
|
BOOL - Returns true if it is the same user
|
|
|
|
--*/
|
|
BOOL
|
|
TThreadPool::IsValidUser(
|
|
PWIN32THREAD pThread,
|
|
PVOID pCurrentTokenInformation
|
|
)
|
|
{
|
|
BOOL bReturn = FALSE;
|
|
|
|
bReturn = RtlEqualSid((reinterpret_cast<PTOKEN_USER>(pCurrentTokenInformation))->User.Sid,
|
|
pThread->pSid);
|
|
|
|
return bReturn;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TThreadPool::ReturnThread
|
|
|
|
Description:
|
|
|
|
Return thread item to the pool, signal event that we are done using the thread.
|
|
|
|
Arguments:
|
|
|
|
pThread - Thread item to be returned
|
|
|
|
Return Value:
|
|
|
|
HRESULT
|
|
|
|
--*/
|
|
HRESULT
|
|
TThreadPool::ReturnThread(
|
|
PWIN32THREAD pThread
|
|
)
|
|
{
|
|
HRESULT hReturn = E_FAIL;
|
|
|
|
SplInSem();
|
|
|
|
hReturn = pThread ? S_OK : E_INVALIDARG;
|
|
|
|
SPLASSERT(IsValid(pThread));
|
|
|
|
if (SUCCEEDED(hReturn))
|
|
{
|
|
//
|
|
// We only return a thread from the foreground if it is actuall still
|
|
// executing and not terminated.
|
|
//
|
|
SPLASSERT(pThread->dwStatus == THREAD_STATUS_EXECUTING);
|
|
|
|
pThread->pNext = pHead;
|
|
pHead = pThread;
|
|
}
|
|
|
|
return hReturn;
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TThreadPool::IsValid
|
|
|
|
Description:
|
|
|
|
Checks signature of the thread item to see if it is valid.
|
|
|
|
Arguments:
|
|
|
|
pThread - The thread to check for validity
|
|
|
|
Return Value:
|
|
|
|
BOOL - Returns true if it is the same user
|
|
|
|
--*/
|
|
BOOL
|
|
TThreadPool::IsValid(
|
|
PWIN32THREAD pThread
|
|
)
|
|
{
|
|
return (pThread->signature == TP_SIGNATURE);
|
|
}
|
|
|
|
/*++
|
|
|
|
Name:
|
|
|
|
TThreadPool::FreeThread
|
|
|
|
Description:
|
|
|
|
Frees the data in the given thread.
|
|
|
|
Arguments:
|
|
|
|
pThread - The thread to free
|
|
|
|
Return Value:
|
|
|
|
Nothing
|
|
|
|
--*/
|
|
VOID
|
|
TThreadPool::FreeThread(
|
|
IN PWIN32THREAD pThread
|
|
)
|
|
{
|
|
|
|
if (pThread)
|
|
{
|
|
//
|
|
// Now delete the thread.
|
|
//
|
|
pThread->hRpcHandle = NULL;
|
|
|
|
if (pThread->pDefaults)
|
|
{
|
|
FreeSplStr(pThread->pDefaults->pDatatype);
|
|
FreeSplMem(pThread->pDefaults->pDevMode);
|
|
FreeSplMem(pThread->pDefaults);
|
|
}
|
|
|
|
if (pThread->hWaitValidHandle)
|
|
{
|
|
CloseHandle(pThread->hWaitValidHandle);
|
|
}
|
|
|
|
if( pThread->hToken != INVALID_HANDLE_VALUE )
|
|
{
|
|
CloseHandle( pThread->hToken );
|
|
pThread->hToken = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (pThread->pName)
|
|
{
|
|
FreeSplStr(pThread->pName);
|
|
}
|
|
|
|
if (pThread->pSid)
|
|
{
|
|
FreeSplMem(pThread->pSid);
|
|
}
|
|
|
|
FreeSplMem(pThread);
|
|
}
|
|
}
|
|
|
|
|