reactos/subsystems/csr/csrsrv/thredsup.c
Hermès Bélusca-Maïto d2aeaba5f8
[CSR][NTDLL] Move the CSR subsystem into its own "csr" sub-directory. (#4802)
Move CSRSS, CSRSRV there, as well as CSR client calls from NTDLL into a "CSRLIB" library.
2022-10-29 17:17:29 +02:00

1086 lines
28 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Client/Server Runtime SubSystem
* FILE: subsystems/win32/csrsrv/thredsup.c
* PURPOSE: CSR Server DLL Thread Management
* PROGRAMMERS: ReactOS Portable Systems Group
* Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES *******************************************************************/
#include <srv.h>
#define NDEBUG
#include <debug.h>
#define CsrHashThread(t) (HandleToUlong(t) % NUMBER_THREAD_HASH_BUCKETS)
/* GLOBALS ********************************************************************/
LIST_ENTRY CsrThreadHashTable[NUMBER_THREAD_HASH_BUCKETS];
/* PRIVATE FUNCTIONS **********************************************************/
/*++
* @name ProtectHandle
* @implemented NT5.2
*
* The ProtectHandle routine protects an object handle against closure.
*
* @return TRUE or FALSE.
*
* @remarks None.
*
*--*/
BOOLEAN
NTAPI
ProtectHandle(IN HANDLE ObjectHandle)
{
NTSTATUS Status;
OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo;
/* Query current state */
Status = NtQueryObject(ObjectHandle,
ObjectHandleFlagInformation,
&HandleInfo,
sizeof(HandleInfo),
NULL);
if (NT_SUCCESS(Status))
{
/* Enable protect from close */
HandleInfo.ProtectFromClose = TRUE;
Status = NtSetInformationObject(ObjectHandle,
ObjectHandleFlagInformation,
&HandleInfo,
sizeof(HandleInfo));
if (NT_SUCCESS(Status)) return TRUE;
}
/* We failed to or set the state */
return FALSE;
}
/*++
* @name UnProtectHandle
* @implemented NT5.2
*
* The UnProtectHandle routine unprotects an object handle against closure.
*
* @return TRUE or FALSE.
*
* @remarks None.
*
*--*/
BOOLEAN
NTAPI
UnProtectHandle(IN HANDLE ObjectHandle)
{
NTSTATUS Status;
OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo;
/* Query current state */
Status = NtQueryObject(ObjectHandle,
ObjectHandleFlagInformation,
&HandleInfo,
sizeof(HandleInfo),
NULL);
if (NT_SUCCESS(Status))
{
/* Disable protect from close */
HandleInfo.ProtectFromClose = FALSE;
Status = NtSetInformationObject(ObjectHandle,
ObjectHandleFlagInformation,
&HandleInfo,
sizeof(HandleInfo));
if (NT_SUCCESS(Status)) return TRUE;
}
/* We failed to or set the state */
return FALSE;
}
/*++
* @name CsrAllocateThread
*
* The CsrAllocateThread routine allocates a new CSR Thread object.
*
* @param CsrProcess
* Pointer to the CSR Process which will contain this CSR Thread.
*
* @return Pointer to the newly allocated CSR Thread.
*
* @remarks None.
*
*--*/
PCSR_THREAD
NTAPI
CsrAllocateThread(IN PCSR_PROCESS CsrProcess)
{
PCSR_THREAD CsrThread;
/* Allocate the structure */
CsrThread = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, sizeof(CSR_THREAD));
if (!CsrThread) return NULL;
/* Reference the Thread and Process */
CsrLockedReferenceThread(CsrThread);
CsrLockedReferenceProcess(CsrProcess);
/* Set the Parent Process */
CsrThread->Process = CsrProcess;
/* Return Thread */
return CsrThread;
}
/*++
* @name CsrLockedReferenceThread
*
* The CsrLockedReferenceThread references a CSR Thread while the
* Process Lock is already being held.
*
* @param CsrThread
* Pointer to the CSR Thread to be referenced.
*
* @return None.
*
* @remarks This routine will return with the Process Lock held.
*
*--*/
VOID
NTAPI
CsrLockedReferenceThread(IN PCSR_THREAD CsrThread)
{
/* Increment the reference count */
++CsrThread->ReferenceCount;
}
/*++
* @name CsrLocateThreadByClientId
*
* The CsrLocateThreadByClientId routine locates the CSR Thread and,
* optionally, its parent CSR Process, corresponding to a Client ID.
*
* @param Process
* Optional pointer to a CSR Process pointer which will contain
* the CSR Thread's parent.
*
* @param ClientId
* Pointer to a Client ID structure containing the Unique Thread ID
* to look up.
*
* @return Pointer to the CSR Thread corresponding to this CID, or NULL if
* none was found.
*
* @remarks None.
*
*--*/
PCSR_THREAD
NTAPI
CsrLocateThreadByClientId(OUT PCSR_PROCESS *Process OPTIONAL,
IN PCLIENT_ID ClientId)
{
ULONG i;
PLIST_ENTRY ListHead, NextEntry;
PCSR_THREAD FoundThread;
// ASSERT(ProcessStructureListLocked());
if (Process) *Process = NULL;
/* Hash the Thread */
i = CsrHashThread(ClientId->UniqueThread);
/* Set the list pointers */
ListHead = &CsrThreadHashTable[i];
NextEntry = ListHead->Flink;
/* Star the loop */
while (NextEntry != ListHead)
{
/* Get the thread */
FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
/* Move to the next entry */
NextEntry = NextEntry->Flink;
/* Compare the CID */
// if (*(PULONGLONG)&FoundThread->ClientId == *(PULONGLONG)ClientId)
if ( FoundThread->ClientId.UniqueProcess == ClientId->UniqueProcess &&
FoundThread->ClientId.UniqueThread == ClientId->UniqueThread )
{
/* Match found, return the process */
if (Process) *Process = FoundThread->Process;
/* Return thread too */
return FoundThread;
}
}
/* Nothing found */
return NULL;
}
/*++
* @name CsrLocateThreadInProcess
*
* The CsrLocateThreadInProcess routine locates the CSR Thread
* corresponding to a Client ID inside a specific CSR Process.
*
* @param Process
* Optional pointer to the CSR Process which contains the CSR Thread
* that will be looked up.
*
* @param ClientId
* Pointer to a Client ID structure containing the Unique Thread ID
* to look up.
*
* @return Pointer to the CSR Thread corresponding to this CID, or NULL if
* none was found.
*
* @remarks If the CsrProcess argument is NULL, the lookup will be done inside
* CsrRootProcess.
*
*--*/
PCSR_THREAD
NTAPI
CsrLocateThreadInProcess(IN PCSR_PROCESS CsrProcess OPTIONAL,
IN PCLIENT_ID Cid)
{
PLIST_ENTRY ListHead, NextEntry;
PCSR_THREAD FoundThread = NULL;
/* Use the Root Process if none was specified */
if (!CsrProcess) CsrProcess = CsrRootProcess;
/* Save the List pointers */
ListHead = &CsrProcess->ThreadList;
NextEntry = ListHead->Flink;
/* Start the Loop */
while (NextEntry != ListHead)
{
/* Get Thread Entry */
FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
/* Check for TID Match */
if (FoundThread->ClientId.UniqueThread == Cid->UniqueThread) break;
/* Move to the next entry */
NextEntry = NextEntry->Flink;
}
/* Return what we found */
return FoundThread;
}
/*++
* @name CsrInsertThread
*
* The CsrInsertThread routine inserts a CSR Thread into its parent's
* Thread List and into the Thread Hash Table.
*
* @param Process
* Pointer to the CSR Process containing this CSR Thread.
*
* @param Thread
* Pointer to the CSR Thread to be inserted.
*
* @return None.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
CsrInsertThread(IN PCSR_PROCESS Process,
IN PCSR_THREAD Thread)
{
ULONG i;
NTSTATUS Status;
ULONG ThreadInfo;
// ASSERT(ProcessStructureListLocked());
/* Make sure the thread isn't already dead by the time we got this */
Status = NtQueryInformationThread(Thread->ThreadHandle,
ThreadIsTerminated,
&ThreadInfo,
sizeof(ThreadInfo),
NULL);
if (!NT_SUCCESS(Status)) return Status;
if (ThreadInfo) return STATUS_THREAD_IS_TERMINATING;
/* Insert it into the Regular List */
InsertTailList(&Process->ThreadList, &Thread->Link);
/* Increase Thread Count */
Process->ThreadCount++;
/* Hash the Thread */
i = CsrHashThread(Thread->ClientId.UniqueThread);
/* Insert it there too */
InsertHeadList(&CsrThreadHashTable[i], &Thread->HashLinks);
return STATUS_SUCCESS;
}
/*++
* @name CsrDeallocateThread
*
* The CsrDeallocateThread frees the memory associated with a CSR Thread.
*
* @param CsrThread
* Pointer to the CSR Thread to be freed.
*
* @return None.
*
* @remarks Do not call this routine. It is reserved for the internal
* thread management routines when a CSR Thread has been cleanly
* dereferenced and killed.
*
*--*/
VOID
NTAPI
CsrDeallocateThread(IN PCSR_THREAD CsrThread)
{
/* Free the process object from the heap */
// ASSERT(CsrThread->WaitBlock == NULL);
RtlFreeHeap(CsrHeap, 0, CsrThread);
}
/*++
* @name CsrRemoveThread
*
* The CsrRemoveThread function undoes a CsrInsertThread operation and
* removes the CSR Thread from the the Hash Table and Thread List.
*
* @param CsrThread
* Pointer to the CSR Thread to remove.
*
* @return None.
*
* @remarks If this CSR Thread is the last one inside a CSR Process, the
* parent will be dereferenced and the CsrProcessLastThreadTerminated
* flag will be set.
*
* After executing this routine, the CSR Thread will have the
* CsrThreadInTermination flag set.
*
*--*/
VOID
NTAPI
CsrRemoveThread(IN PCSR_THREAD CsrThread)
{
ASSERT(ProcessStructureListLocked());
/* Remove it from the List */
RemoveEntryList(&CsrThread->Link);
/* Decreate the thread count of the process */
CsrThread->Process->ThreadCount--;
/* Remove it from the Hash List as well */
if (CsrThread->HashLinks.Flink) RemoveEntryList(&CsrThread->HashLinks);
/* Check if this is the last Thread */
if (CsrThread->Process->ThreadCount == 0)
{
/* Check if it's not already been marked for deletion */
if ((CsrThread->Process->Flags & CsrProcessLastThreadTerminated) == 0)
{
/* Let everyone know this process is about to lose the thread */
CsrThread->Process->Flags |= CsrProcessLastThreadTerminated;
/* Reference the Process */
CsrLockedDereferenceProcess(CsrThread->Process);
}
}
/* Mark the thread for deletion */
CsrThread->Flags |= CsrThreadInTermination;
}
/*++
* @name CsrThreadRefcountZero
*
* The CsrThreadRefcountZero routine is executed when a CSR Thread has lost
* all its active references. It removes and de-allocates the CSR Thread.
*
* @param CsrThread
* Pointer to the CSR Thread that is to be deleted.
*
* @return None.
*
* @remarks Do not call this routine. It is reserved for the internal
* thread management routines when a CSR Thread has lost all
* its references.
*
* This routine is called with the Process Lock held.
*
*--*/
VOID
NTAPI
CsrThreadRefcountZero(IN PCSR_THREAD CsrThread)
{
PCSR_PROCESS CsrProcess = CsrThread->Process;
NTSTATUS Status;
ASSERT(ProcessStructureListLocked());
/* Remove this thread */
CsrRemoveThread(CsrThread);
/* Release the Process Lock */
CsrReleaseProcessLock();
/* Close the NT Thread Handle */
if (CsrThread->ThreadHandle)
{
UnProtectHandle(CsrThread->ThreadHandle);
Status = NtClose(CsrThread->ThreadHandle);
ASSERT(NT_SUCCESS(Status));
}
/* De-allocate the CSR Thread Object */
CsrDeallocateThread(CsrThread);
/* Remove a reference from the process */
CsrDereferenceProcess(CsrProcess);
}
/*++
* @name CsrLockedDereferenceThread
*
* The CsrLockedDereferenceThread dereferences a CSR Thread while the
* Process Lock is already being held.
*
* @param CsrThread
* Pointer to the CSR Thread to be dereferenced.
*
* @return None.
*
* @remarks This routine will return with the Process Lock held.
*
*--*/
VOID
NTAPI
CsrLockedDereferenceThread(IN PCSR_THREAD CsrThread)
{
LONG LockCount;
/* Decrease reference count */
LockCount = --CsrThread->ReferenceCount;
ASSERT(LockCount >= 0);
if (LockCount == 0)
{
/* Call the generic cleanup code */
CsrThreadRefcountZero(CsrThread);
/* Acquire the lock again, it was released by CsrThreadRefcountZero */
CsrAcquireProcessLock();
}
}
/* PUBLIC FUNCTIONS ***********************************************************/
/*++
* @name CsrAddStaticServerThread
* @implemented NT4
*
* The CsrAddStaticServerThread routine adds a new CSR Thread to the
* CSR Server Process (CsrRootProcess).
*
* @param hThread
* Handle to an existing NT Thread to which to associate this
* CSR Thread.
*
* @param ClientId
* Pointer to the Client ID structure of the NT Thread to associate
* with this CSR Thread.
*
* @param ThreadFlags
* Initial CSR Thread Flags to associate to this CSR Thread. Usually
* CsrThreadIsServerThread.
*
* @return Pointer to the newly allocated CSR Thread.
*
* @remarks None.
*
*--*/
PCSR_THREAD
NTAPI
CsrAddStaticServerThread(IN HANDLE hThread,
IN PCLIENT_ID ClientId,
IN ULONG ThreadFlags)
{
PCSR_THREAD CsrThread;
/* Get the Lock */
CsrAcquireProcessLock();
/* Allocate the Server Thread */
CsrThread = CsrAllocateThread(CsrRootProcess);
if (CsrThread)
{
/* Setup the Object */
CsrThread->ThreadHandle = hThread;
ProtectHandle(hThread);
CsrThread->ClientId = *ClientId;
CsrThread->Flags = ThreadFlags;
/* Insert it into the Thread List */
InsertTailList(&CsrRootProcess->ThreadList, &CsrThread->Link);
/* Increment the thread count */
CsrRootProcess->ThreadCount++;
}
else
{
DPRINT1("CsrAddStaticServerThread: alloc failed for thread 0x%x\n", hThread);
}
/* Release the Process Lock and return */
CsrReleaseProcessLock();
return CsrThread;
}
/*++
* @name CsrCreateRemoteThread
* @implemented NT4
*
* The CsrCreateRemoteThread routine creates a CSR Thread object for
* an NT Thread which is not part of the current NT Process.
*
* @param hThread
* Handle to an existing NT Thread to which to associate this
* CSR Thread.
*
* @param ClientId
* Pointer to the Client ID structure of the NT Thread to associate
* with this CSR Thread.
*
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
CsrCreateRemoteThread(IN HANDLE hThread,
IN PCLIENT_ID ClientId)
{
NTSTATUS Status;
HANDLE ThreadHandle;
PCSR_THREAD CsrThread;
PCSR_PROCESS CsrProcess;
KERNEL_USER_TIMES KernelTimes;
/* Get the Thread Create Time */
Status = NtQueryInformationThread(hThread,
ThreadTimes,
&KernelTimes,
sizeof(KernelTimes),
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to query thread times: %lx\n", Status);
return Status;
}
/* Lock the Owner Process */
Status = CsrLockProcessByClientId(ClientId->UniqueProcess, &CsrProcess);
if (!NT_SUCCESS(Status))
{
DPRINT1("No known process for %lx\n", ClientId->UniqueProcess);
return Status;
}
/* Make sure the thread didn't terminate */
if (KernelTimes.ExitTime.QuadPart)
{
/* Unlock the process and return */
CsrUnlockProcess(CsrProcess);
DPRINT1("Dead thread: %I64x\n", KernelTimes.ExitTime.QuadPart);
return STATUS_THREAD_IS_TERMINATING;
}
/* Allocate a CSR Thread Structure */
CsrThread = CsrAllocateThread(CsrProcess);
if (!CsrThread)
{
DPRINT1("CSRSRV: %s: out of memory!\n", __FUNCTION__);
CsrUnlockProcess(CsrProcess);
return STATUS_NO_MEMORY;
}
/* Duplicate the Thread Handle */
Status = NtDuplicateObject(NtCurrentProcess(),
hThread,
NtCurrentProcess(),
&ThreadHandle,
0,
0,
DUPLICATE_SAME_ACCESS);
/* Allow failure */
if (!NT_SUCCESS(Status))
{
DPRINT1("Thread duplication failed: %lx\n", Status);
ThreadHandle = hThread;
}
/* Save the data we have */
CsrThread->CreateTime = KernelTimes.CreateTime;
CsrThread->ClientId = *ClientId;
CsrThread->ThreadHandle = ThreadHandle;
ProtectHandle(ThreadHandle);
CsrThread->Flags = 0;
/* Insert the Thread into the Process */
Status = CsrInsertThread(CsrProcess, CsrThread);
if (!NT_SUCCESS(Status))
{
/* Bail out */
if (CsrThread->ThreadHandle != hThread) NtClose(CsrThread->ThreadHandle);
CsrUnlockProcess(CsrProcess);
CsrDeallocateThread(CsrThread);
return Status;
}
/* Release the lock and return */
CsrUnlockProcess(CsrProcess);
return STATUS_SUCCESS;
}
/*++
* @name CsrCreateThread
* @implemented NT4
*
* The CsrCreateThread routine creates a CSR Thread object for an NT Thread.
*
* @param CsrProcess
* Pointer to the CSR Process which will contain the CSR Thread.
*
* @param hThread
* Handle to an existing NT Thread to which to associate this
* CSR Thread.
*
* @param ClientId
* Pointer to the Client ID structure of the NT Thread to associate
* with this CSR Thread.
*
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
CsrCreateThread(IN PCSR_PROCESS CsrProcess,
IN HANDLE hThread,
IN PCLIENT_ID ClientId,
IN BOOLEAN HaveClient)
{
NTSTATUS Status;
PCSR_THREAD CsrThread, CurrentThread;
PCSR_PROCESS CurrentProcess;
CLIENT_ID CurrentCid;
KERNEL_USER_TIMES KernelTimes;
if (HaveClient)
{
/* Get the current thread and CID */
CurrentThread = CsrGetClientThread();
CurrentCid = CurrentThread->ClientId;
/* Acquire the Process Lock */
CsrAcquireProcessLock();
/* Get the current Process and make sure the Thread is valid with this CID */
CurrentThread = CsrLocateThreadByClientId(&CurrentProcess, &CurrentCid);
/* Something is wrong if we get an empty thread back */
if (!CurrentThread)
{
DPRINT1("CSRSRV: %s: invalid thread!\n", __FUNCTION__);
CsrReleaseProcessLock();
return STATUS_THREAD_IS_TERMINATING;
}
}
else
{
/* Acquire the Process Lock */
CsrAcquireProcessLock();
}
/* Get the Thread Create Time */
Status = NtQueryInformationThread(hThread,
ThreadTimes,
&KernelTimes,
sizeof(KernelTimes),
NULL);
if (!NT_SUCCESS(Status))
{
CsrReleaseProcessLock();
return Status;
}
/* Allocate a CSR Thread Structure */
CsrThread = CsrAllocateThread(CsrProcess);
if (!CsrThread)
{
DPRINT1("CSRSRV: %s: out of memory!\n", __FUNCTION__);
CsrReleaseProcessLock();
return STATUS_NO_MEMORY;
}
/* Save the data we have */
CsrThread->CreateTime = KernelTimes.CreateTime;
CsrThread->ClientId = *ClientId;
CsrThread->ThreadHandle = hThread;
ProtectHandle(hThread);
CsrThread->Flags = 0;
/* Insert the Thread into the Process */
Status = CsrInsertThread(CsrProcess, CsrThread);
if (!NT_SUCCESS(Status))
{
/* Bail out */
CsrUnlockProcess(CsrProcess);
CsrDeallocateThread(CsrThread);
return Status;
}
/* Release the lock and return */
CsrReleaseProcessLock();
return STATUS_SUCCESS;
}
/*++
* @name CsrDereferenceThread
* @implemented NT4
*
* The CsrDereferenceThread routine removes a reference from a CSR Thread.
*
* @param CsrThread
* Pointer to the CSR Thread to dereference.
*
* @return None.
*
* @remarks If the reference count has reached zero (ie: the CSR Thread has
* no more active references), it will be deleted.
*
*--*/
VOID
NTAPI
CsrDereferenceThread(IN PCSR_THREAD CsrThread)
{
/* Acquire process lock */
CsrAcquireProcessLock();
/* Decrease reference count */
ASSERT(CsrThread->ReferenceCount > 0);
if ((--CsrThread->ReferenceCount) == 0)
{
/* Call the generic cleanup code */
CsrThreadRefcountZero(CsrThread);
}
else
{
/* Just release the lock */
CsrReleaseProcessLock();
}
}
/*++
* @name CsrDestroyThread
* @implemented NT4
*
* The CsrDestroyThread routine destroys the CSR Thread corresponding to
* a given Thread ID.
*
* @param Cid
* Pointer to the Client ID Structure corresponding to the CSR
* Thread which is about to be destroyed.
*
* @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
* if the CSR Thread is already terminating.
*
* @remarks None.
*
*--*/
NTSTATUS
NTAPI
CsrDestroyThread(IN PCLIENT_ID Cid)
{
CLIENT_ID ClientId = *Cid;
PCSR_THREAD CsrThread;
PCSR_PROCESS CsrProcess;
/* Acquire lock */
CsrAcquireProcessLock();
/* Find the thread */
CsrThread = CsrLocateThreadByClientId(&CsrProcess,
&ClientId);
/* Make sure we got one back, and that it's not already gone */
if (!CsrThread || (CsrThread->Flags & CsrThreadTerminated))
{
/* Release the lock and return failure */
CsrReleaseProcessLock();
return STATUS_THREAD_IS_TERMINATING;
}
/* Set the terminated flag */
CsrThread->Flags |= CsrThreadTerminated;
/* Acquire the Wait Lock */
CsrAcquireWaitLock();
/* Do we have an active wait block? */
if (CsrThread->WaitBlock)
{
/* Notify waiters of termination */
CsrNotifyWaitBlock(CsrThread->WaitBlock,
NULL,
NULL,
NULL,
CsrProcessTerminating,
TRUE);
}
/* Release the Wait Lock */
CsrReleaseWaitLock();
/* Dereference the thread */
CsrLockedDereferenceThread(CsrThread);
/* Release the Process Lock and return success */
CsrReleaseProcessLock();
return STATUS_SUCCESS;
}
/*++
* @name CsrExecServerThread
* @implemented NT4
*
* The CsrExecServerThread routine creates an NT Thread and then
* initializes a CSR Thread for it.
*
* @param ThreadHandler
* Pointer to the thread's startup routine.
*
* @param Flags
* Initial CSR Thread Flags to set to the CSR Thread.
*
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
*
* @remarks This routine is similar to CsrAddStaticServerThread, but it
* also creates an NT Thread instead of expecting one to already
* exist.
*
*--*/
NTSTATUS
NTAPI
CsrExecServerThread(IN PVOID ThreadHandler,
IN ULONG Flags)
{
PCSR_THREAD CsrThread;
HANDLE hThread;
CLIENT_ID ClientId;
NTSTATUS Status;
/* Acquire process lock */
CsrAcquireProcessLock();
/* Allocate a CSR Thread in the Root Process */
ASSERT(CsrRootProcess != NULL);
CsrThread = CsrAllocateThread(CsrRootProcess);
if (!CsrThread)
{
/* Fail */
CsrReleaseProcessLock();
return STATUS_NO_MEMORY;
}
/* Create the Thread */
Status = RtlCreateUserThread(NtCurrentProcess(),
NULL,
FALSE,
0,
0,
0,
ThreadHandler,
NULL,
&hThread,
&ClientId);
if (!NT_SUCCESS(Status))
{
/* Fail */
CsrDeallocateThread(CsrThread);
CsrReleaseProcessLock();
return Status;
}
/* Setup the Thread Object */
CsrThread->ThreadHandle = hThread;
ProtectHandle(hThread);
CsrThread->ClientId = ClientId;
CsrThread->Flags = Flags;
/* Insert it into the Thread List */
InsertHeadList(&CsrRootProcess->ThreadList, &CsrThread->Link);
/* Increase the thread count */
CsrRootProcess->ThreadCount++;
/* Return */
CsrReleaseProcessLock();
return Status;
}
/*++
* @name CsrLockThreadByClientId
* @implemented NT4
*
* The CsrLockThreadByClientId routine locks the CSR Thread corresponding
* to the given Thread ID and optionally returns it.
*
* @param Tid
* Thread ID corresponding to the CSR Thread which will be locked.
*
* @param CsrThread
* Optional pointer to a CSR Thread pointer which will hold the
* CSR Thread corresponding to the given Thread ID.
*
* @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
*
* @remarks Locking a CSR Thread is defined as acquiring an extra
* reference to it and returning with the Process Lock held.
*
*--*/
NTSTATUS
NTAPI
CsrLockThreadByClientId(IN HANDLE Tid,
OUT PCSR_THREAD *CsrThread)
{
PLIST_ENTRY NextEntry;
PCSR_THREAD CurrentThread = NULL;
NTSTATUS Status = STATUS_UNSUCCESSFUL;
ULONG i;
/* Acquire the lock */
CsrAcquireProcessLock();
/* Assume failure */
ASSERT(CsrThread != NULL);
*CsrThread = NULL;
/* Convert to Hash */
i = CsrHashThread(Tid);
/* Setup the List Pointers */
NextEntry = CsrThreadHashTable[i].Flink;
/* Start Loop */
while (NextEntry != &CsrThreadHashTable[i])
{
/* Get the Thread */
CurrentThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
/* Check for TID Match */
if ((CurrentThread->ClientId.UniqueThread == Tid) &&
(CurrentThread->Flags & CsrThreadTerminated) == 0)
{
/* Get out of here */
break;
}
/* Move to the next entry */
NextEntry = NextEntry->Flink;
}
/* Nothing found if we got back to the list */
if (NextEntry == &CsrThreadHashTable[i]) CurrentThread = NULL;
/* Did the loop find something? */
if (CurrentThread)
{
/* Reference the found thread */
Status = STATUS_SUCCESS;
CsrLockedReferenceThread(CurrentThread);
*CsrThread = CurrentThread;
}
else
{
/* Nothing found, release the lock */
Status = STATUS_UNSUCCESSFUL;
CsrReleaseProcessLock();
}
/* Return the status */
return Status;
}
/*++
* @name CsrReferenceThread
* @implemented NT4
*
* The CsrReferenceThread routine increases the active reference count of
* a CSR Thread.
*
* @param CsrThread
* Pointer to the CSR Thread whose reference count will be increased.
*
* @return None.
*
* @remarks Do not use this routine if the Process Lock is already held.
*
*--*/
VOID
NTAPI
CsrReferenceThread(IN PCSR_THREAD CsrThread)
{
/* Acquire process lock */
CsrAcquireProcessLock();
/* Sanity checks */
ASSERT((CsrThread->Flags & CsrThreadTerminated) == 0);
ASSERT(CsrThread->ReferenceCount != 0);
/* Increment reference count */
CsrThread->ReferenceCount++;
/* Release the lock */
CsrReleaseProcessLock();
}
/*++
* @name CsrUnlockThread
* @implemented NT4
*
* The CsrUnlockThread undoes a previous CsrLockThreadByClientId operation.
*
* @param CsrThread
* Pointer to a previously locked CSR Thread.
*
* @return STATUS_SUCCESS.
*
* @remarks This routine must be called with the Process Lock held.
*
*--*/
NTSTATUS
NTAPI
CsrUnlockThread(IN PCSR_THREAD CsrThread)
{
/* Dereference the Thread */
ASSERT(ProcessStructureListLocked());
CsrLockedDereferenceThread(CsrThread);
/* Release the lock and return */
CsrReleaseProcessLock();
return STATUS_SUCCESS;
}
/* EOF */