Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenthredsup.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS CSR Sub System 00004 * FILE: subsystems/win32/csrss/csrsrv/thredsup.c 00005 * PURPOSE: CSR Process Management 00006 * PROGRAMMERS: ReactOS Portable Systems Group 00007 * Alex Ionescu 00008 */ 00009 00010 /* INCLUDES *******************************************************************/ 00011 00012 #include <srv.h> 00013 00014 #define NDEBUG 00015 #include <debug.h> 00016 00017 #define CsrHashThread(t) \ 00018 (HandleToUlong(t)&(256 - 1)) 00019 00020 /* GLOBALS ********************************************************************/ 00021 00022 LIST_ENTRY CsrThreadHashTable[256]; 00023 00024 /* FUNCTIONS ******************************************************************/ 00025 00026 /*++ 00027 * @name ProtectHandle 00028 * @implemented NT5.2 00029 * 00030 * The ProtectHandle routine protects an object handle against closure. 00031 * 00032 * @return TRUE or FALSE. 00033 * 00034 * @remarks None. 00035 * 00036 *--*/ 00037 BOOLEAN 00038 NTAPI 00039 ProtectHandle(IN HANDLE ObjectHandle) 00040 { 00041 NTSTATUS Status; 00042 OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo; 00043 00044 /* Query current state */ 00045 Status = NtQueryObject(ObjectHandle, 00046 ObjectHandleFlagInformation, 00047 &HandleInfo, 00048 sizeof(HandleInfo), 00049 NULL); 00050 if (NT_SUCCESS(Status)) 00051 { 00052 /* Enable protect from close */ 00053 HandleInfo.ProtectFromClose = TRUE; 00054 Status = NtSetInformationObject(ObjectHandle, 00055 ObjectHandleFlagInformation, 00056 &HandleInfo, 00057 sizeof(HandleInfo)); 00058 if (NT_SUCCESS(Status)) return TRUE; 00059 } 00060 00061 /* We failed to or set the state */ 00062 return FALSE; 00063 } 00064 00065 /*++ 00066 * @name UnProtectHandle 00067 * @implemented NT5.2 00068 * 00069 * The UnProtectHandle routine unprotects an object handle against closure. 00070 * 00071 * @return TRUE or FALSE. 00072 * 00073 * @remarks None. 00074 * 00075 *--*/ 00076 BOOLEAN 00077 NTAPI 00078 UnProtectHandle(IN HANDLE ObjectHandle) 00079 { 00080 NTSTATUS Status; 00081 OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo; 00082 00083 /* Query current state */ 00084 Status = NtQueryObject(ObjectHandle, 00085 ObjectHandleFlagInformation, 00086 &HandleInfo, 00087 sizeof(HandleInfo), 00088 NULL); 00089 if (NT_SUCCESS(Status)) 00090 { 00091 /* Disable protect from close */ 00092 HandleInfo.ProtectFromClose = FALSE; 00093 Status = NtSetInformationObject(ObjectHandle, 00094 ObjectHandleFlagInformation, 00095 &HandleInfo, 00096 sizeof(HandleInfo)); 00097 if (NT_SUCCESS(Status)) return TRUE; 00098 } 00099 00100 /* We failed to or set the state */ 00101 return FALSE; 00102 } 00103 00104 PCSR_THREAD 00105 NTAPI 00106 CsrAllocateThread(IN PCSR_PROCESS CsrProcess) 00107 { 00108 PCSR_THREAD CsrThread; 00109 00110 /* Allocate the structure */ 00111 CsrThread = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, sizeof(CSR_THREAD)); 00112 if (!CsrThread) return(NULL); 00113 00114 /* Reference the Thread and Process */ 00115 CsrThread->ReferenceCount++; 00116 CsrProcess->ReferenceCount++; 00117 00118 /* Set the Parent Process */ 00119 CsrThread->Process = CsrProcess; 00120 00121 /* Return Thread */ 00122 return CsrThread; 00123 } 00124 00125 /*++ 00126 * @name CsrLockedReferenceThread 00127 * 00128 * The CsrLockedReferenceThread refences a CSR Thread while the 00129 * Process Lock is already being held. 00130 * 00131 * @param CsrThread 00132 * Pointer to the CSR Thread to be referenced. 00133 * 00134 * @return None. 00135 * 00136 * @remarks This routine will return with the Process Lock held. 00137 * 00138 *--*/ 00139 VOID 00140 NTAPI 00141 CsrLockedReferenceThread(IN PCSR_THREAD CsrThread) 00142 { 00143 /* Increment the reference count */ 00144 ++CsrThread->ReferenceCount; 00145 } 00146 00147 PCSR_THREAD 00148 NTAPI 00149 CsrLocateThreadByClientId(OUT PCSR_PROCESS *Process OPTIONAL, 00150 IN PCLIENT_ID ClientId) 00151 { 00152 ULONG i; 00153 PLIST_ENTRY ListHead, NextEntry; 00154 PCSR_THREAD FoundThread; 00155 00156 /* Hash the Thread */ 00157 i = CsrHashThread(ClientId->UniqueThread); 00158 00159 /* Set the list pointers */ 00160 ListHead = &CsrThreadHashTable[i]; 00161 NextEntry = ListHead->Flink; 00162 00163 /* Star the loop */ 00164 while (NextEntry != ListHead) 00165 { 00166 /* Get the thread */ 00167 FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks); 00168 00169 /* Compare the CID */ 00170 if (FoundThread->ClientId.UniqueThread == ClientId->UniqueThread) 00171 { 00172 /* Match found, return the process */ 00173 *Process = FoundThread->Process; 00174 00175 /* Return thread too */ 00176 // DPRINT1("Found: %p %p\n", FoundThread, FoundThread->Process); 00177 return FoundThread; 00178 } 00179 00180 /* Next */ 00181 NextEntry = NextEntry->Flink; 00182 } 00183 00184 /* Nothing found */ 00185 return NULL; 00186 } 00187 00188 PCSR_THREAD 00189 NTAPI 00190 CsrLocateThreadInProcess(IN PCSR_PROCESS CsrProcess OPTIONAL, 00191 IN PCLIENT_ID Cid) 00192 { 00193 PLIST_ENTRY ListHead, NextEntry; 00194 PCSR_THREAD FoundThread = NULL; 00195 00196 /* Use the Root Process if none was specified */ 00197 if (!CsrProcess) CsrProcess = CsrRootProcess; 00198 00199 /* Save the List pointers */ 00200 // DPRINT1("Searching in: %p %d\n", CsrProcess, CsrProcess->ThreadCount); 00201 ListHead = &CsrProcess->ThreadList; 00202 NextEntry = ListHead->Flink; 00203 00204 /* Start the Loop */ 00205 while (NextEntry != ListHead) 00206 { 00207 /* Get Thread Entry */ 00208 FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link); 00209 00210 /* Check for TID Match */ 00211 if (FoundThread->ClientId.UniqueThread == Cid->UniqueThread) break; 00212 00213 /* Next entry */ 00214 NextEntry = NextEntry->Flink; 00215 } 00216 00217 /* Return what we found */ 00218 // DPRINT1("Found: %p\n", FoundThread); 00219 return FoundThread; 00220 } 00221 00222 VOID 00223 NTAPI 00224 CsrInsertThread(IN PCSR_PROCESS Process, 00225 IN PCSR_THREAD Thread) 00226 { 00227 ULONG i; 00228 00229 /* Insert it into the Regular List */ 00230 InsertTailList(&Process->ThreadList, &Thread->Link); 00231 00232 /* Increase Thread Count */ 00233 Process->ThreadCount++; 00234 00235 /* Hash the Thread */ 00236 i = CsrHashThread(Thread->ClientId.UniqueThread); 00237 // DPRINT1("TID %lx HASH: %lx\n", Thread->ClientId.UniqueThread, i); 00238 00239 /* Insert it there too */ 00240 InsertHeadList(&CsrThreadHashTable[i], &Thread->HashLinks); 00241 } 00242 00243 VOID 00244 NTAPI 00245 CsrDeallocateThread(IN PCSR_THREAD CsrThread) 00246 { 00247 /* Free the process object from the heap */ 00248 RtlFreeHeap(CsrHeap, 0, CsrThread); 00249 } 00250 00251 VOID 00252 NTAPI 00253 CsrRemoveThread(IN PCSR_THREAD CsrThread) 00254 { 00255 ASSERT(ProcessStructureListLocked()); 00256 00257 /* Remove it from the List */ 00258 RemoveEntryList(&CsrThread->Link); 00259 00260 /* Decreate the thread count of the process */ 00261 CsrThread->Process->ThreadCount--; 00262 00263 /* Remove it from the Hash List as well */ 00264 if (CsrThread->HashLinks.Flink) RemoveEntryList(&CsrThread->HashLinks); 00265 00266 /* Check if this is the last Thread */ 00267 if (!CsrThread->Process->ThreadCount) 00268 { 00269 /* Check if it's not already been marked for deletion */ 00270 if (!(CsrThread->Process->Flags & CsrProcessLastThreadTerminated)) 00271 { 00272 /* Let everyone know this process is about to lose the thread */ 00273 CsrThread->Process->Flags |= CsrProcessLastThreadTerminated; 00274 00275 /* Reference the Process */ 00276 CsrLockedDereferenceProcess(CsrThread->Process); 00277 } 00278 } 00279 00280 /* Mark the thread for deletion */ 00281 CsrThread->Flags |= CsrThreadInTermination; 00282 } 00283 00284 /*++ 00285 * @name CsrCreateRemoteThread 00286 * @implemented NT4 00287 * 00288 * The CsrCreateRemoteThread routine creates a CSR Thread object for 00289 * an NT Thread which is not part of the current NT Process. 00290 * 00291 * @param hThread 00292 * Handle to an existing NT Thread to which to associate this 00293 * CSR Thread. 00294 * 00295 * @param ClientId 00296 * Pointer to the Client ID structure of the NT Thread to associate 00297 * with this CSR Thread. 00298 * 00299 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL 00300 * othwerwise. 00301 * 00302 * @remarks None. 00303 * 00304 *--*/ 00305 NTSTATUS 00306 NTAPI 00307 CsrCreateRemoteThread(IN HANDLE hThread, 00308 IN PCLIENT_ID ClientId) 00309 { 00310 NTSTATUS Status; 00311 HANDLE ThreadHandle; 00312 PCSR_THREAD CsrThread; 00313 PCSR_PROCESS CsrProcess; 00314 KERNEL_USER_TIMES KernelTimes; 00315 DPRINT("CSRSRV: %s called\n", __FUNCTION__); 00316 00317 /* Get the Thread Create Time */ 00318 Status = NtQueryInformationThread(hThread, 00319 ThreadTimes, 00320 &KernelTimes, 00321 sizeof(KernelTimes), 00322 NULL); 00323 if (!NT_SUCCESS(Status)) 00324 { 00325 DPRINT1("Failed to query thread times: %lx\n", Status); 00326 return Status; 00327 } 00328 00329 /* Lock the Owner Process */ 00330 Status = CsrLockProcessByClientId(&ClientId->UniqueProcess, &CsrProcess); 00331 if (!NT_SUCCESS(Status)) 00332 { 00333 DPRINT1("No known process for %lx\n", ClientId->UniqueProcess); 00334 return Status; 00335 } 00336 00337 /* Make sure the thread didn't terminate */ 00338 if (KernelTimes.ExitTime.QuadPart) 00339 { 00340 /* Unlock the process and return */ 00341 CsrUnlockProcess(CsrProcess); 00342 DPRINT1("Dead thread: %I64x\n", KernelTimes.ExitTime.QuadPart); 00343 return STATUS_THREAD_IS_TERMINATING; 00344 } 00345 00346 /* Allocate a CSR Thread Structure */ 00347 CsrThread = CsrAllocateThread(CsrProcess); 00348 if (!CsrThread) 00349 { 00350 DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__); 00351 CsrUnlockProcess(CsrProcess); 00352 return STATUS_NO_MEMORY; 00353 } 00354 00355 /* Duplicate the Thread Handle */ 00356 Status = NtDuplicateObject(NtCurrentProcess(), 00357 hThread, 00358 NtCurrentProcess(), 00359 &ThreadHandle, 00360 0, 00361 0, 00362 DUPLICATE_SAME_ACCESS); 00363 /* Allow failure */ 00364 if (!NT_SUCCESS(Status)) 00365 { 00366 DPRINT1("Thread duplication failed: %lx\n", Status); 00367 ThreadHandle = hThread; 00368 } 00369 00370 /* Save the data we have */ 00371 CsrThread->CreateTime = KernelTimes.CreateTime; 00372 CsrThread->ClientId = *ClientId; 00373 CsrThread->ThreadHandle = ThreadHandle; 00374 ProtectHandle(ThreadHandle); 00375 CsrThread->Flags = 0; 00376 00377 /* Insert the Thread into the Process */ 00378 CsrInsertThread(CsrProcess, CsrThread); 00379 00380 /* Release the lock and return */ 00381 CsrUnlockProcess(CsrProcess); 00382 return STATUS_SUCCESS; 00383 } 00384 00385 VOID 00386 NTAPI 00387 CsrThreadRefcountZero(IN PCSR_THREAD CsrThread) 00388 { 00389 PCSR_PROCESS CsrProcess = CsrThread->Process; 00390 NTSTATUS Status; 00391 ASSERT(ProcessStructureListLocked()); 00392 00393 /* Remove this thread */ 00394 CsrRemoveThread(CsrThread); 00395 00396 /* Release the Process Lock */ 00397 CsrReleaseProcessLock(); 00398 00399 /* Close the NT Thread Handle */ 00400 if (CsrThread->ThreadHandle) 00401 { 00402 UnProtectHandle(CsrThread->ThreadHandle); 00403 Status = NtClose(CsrThread->ThreadHandle); 00404 ASSERT(NT_SUCCESS(Status)); 00405 } 00406 00407 /* De-allocate the CSR Thread Object */ 00408 CsrDeallocateThread(CsrThread); 00409 00410 /* Remove a reference from the process */ 00411 CsrDereferenceProcess(CsrProcess); 00412 } 00413 00414 /*++ 00415 * @name CsrDestroyThread 00416 * @implemented NT4 00417 * 00418 * The CsrDestroyThread routine destroys the CSR Thread corresponding to 00419 * a given Thread ID. 00420 * 00421 * @param Cid 00422 * Pointer to the Client ID Structure corresponding to the CSR 00423 * Thread which is about to be destroyed. 00424 * 00425 * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING 00426 * if the CSR Thread is already terminating. 00427 * 00428 * @remarks None. 00429 * 00430 *--*/ 00431 NTSTATUS 00432 NTAPI 00433 CsrDestroyThread(IN PCLIENT_ID Cid) 00434 { 00435 CLIENT_ID ClientId = *Cid; 00436 PCSR_THREAD CsrThread; 00437 PCSR_PROCESS CsrProcess; 00438 00439 /* Acquire lock */ 00440 CsrAcquireProcessLock(); 00441 00442 /* Find the thread */ 00443 CsrThread = CsrLocateThreadByClientId(&CsrProcess, 00444 &ClientId); 00445 00446 /* Make sure we got one back, and that it's not already gone */ 00447 if (!CsrThread || CsrThread->Flags & CsrThreadTerminated) 00448 { 00449 /* Release the lock and return failure */ 00450 CsrReleaseProcessLock(); 00451 return STATUS_THREAD_IS_TERMINATING; 00452 } 00453 00454 /* Set the terminated flag */ 00455 CsrThread->Flags |= CsrThreadTerminated; 00456 00457 /* Acquire the Wait Lock */ 00458 CsrAcquireWaitLock(); 00459 00460 /* Do we have an active wait block? */ 00461 if (CsrThread->WaitBlock) 00462 { 00463 /* Notify waiters of termination */ 00464 CsrNotifyWaitBlock(CsrThread->WaitBlock, 00465 NULL, 00466 NULL, 00467 NULL, 00468 CsrProcessTerminating, 00469 TRUE); 00470 } 00471 00472 /* Release the Wait Lock */ 00473 CsrReleaseWaitLock(); 00474 00475 /* Dereference the thread */ 00476 CsrLockedDereferenceThread(CsrThread); 00477 00478 /* Release the Process Lock and return success */ 00479 CsrReleaseProcessLock(); 00480 return STATUS_SUCCESS; 00481 } 00482 00483 /*++ 00484 * @name CsrLockedDereferenceThread 00485 * 00486 * The CsrLockedDereferenceThread derefences a CSR Thread while the 00487 * Process Lock is already being held. 00488 * 00489 * @param CsrThread 00490 * Pointer to the CSR Thread to be dereferenced. 00491 * 00492 * @return None. 00493 * 00494 * @remarks This routine will return with the Process Lock held. 00495 * 00496 *--*/ 00497 VOID 00498 NTAPI 00499 CsrLockedDereferenceThread(IN PCSR_THREAD CsrThread) 00500 { 00501 LONG LockCount; 00502 00503 /* Decrease reference count */ 00504 LockCount = --CsrThread->ReferenceCount; 00505 ASSERT(LockCount >= 0); 00506 if (!LockCount) 00507 { 00508 /* Call the generic cleanup code */ 00509 CsrThreadRefcountZero(CsrThread); 00510 CsrAcquireProcessLock(); 00511 } 00512 } 00513 00514 NTSTATUS 00515 NTAPI 00516 CsrCreateThread(IN PCSR_PROCESS CsrProcess, 00517 IN HANDLE hThread, 00518 IN PCLIENT_ID ClientId) 00519 { 00520 PCSR_THREAD CsrThread; 00521 PCSR_PROCESS CurrentProcess; 00522 PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread; 00523 CLIENT_ID CurrentCid; 00524 KERNEL_USER_TIMES KernelTimes; 00525 00526 /* Get the current thread and CID */ 00527 CurrentCid = CurrentThread->ClientId; 00528 00529 /* Acquire the Process Lock */ 00530 CsrAcquireProcessLock(); 00531 00532 /* Get the current Process and make sure the Thread is valid with this CID */ 00533 CurrentThread = CsrLocateThreadByClientId(&CurrentProcess, 00534 &CurrentCid); 00535 00536 /* Something is wrong if we get an empty thread back */ 00537 if (!CurrentThread) 00538 { 00539 DPRINT1("CSRSRV:%s: invalid thread!\n", __FUNCTION__); 00540 CsrReleaseProcessLock(); 00541 return STATUS_THREAD_IS_TERMINATING; 00542 } 00543 00544 /* Get the Thread Create Time */ 00545 NtQueryInformationThread(hThread, 00546 ThreadTimes, 00547 (PVOID)&KernelTimes, 00548 sizeof(KernelTimes), 00549 NULL); 00550 00551 /* Allocate a CSR Thread Structure */ 00552 if (!(CsrThread = CsrAllocateThread(CsrProcess))) 00553 { 00554 DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__); 00555 CsrReleaseProcessLock(); 00556 return STATUS_NO_MEMORY; 00557 } 00558 00559 /* Save the data we have */ 00560 CsrThread->CreateTime = KernelTimes.CreateTime; 00561 CsrThread->ClientId = *ClientId; 00562 CsrThread->ThreadHandle = hThread; 00563 CsrThread->Flags = 0; 00564 00565 /* Insert the Thread into the Process */ 00566 CsrInsertThread(CsrProcess, CsrThread); 00567 00568 /* Release the lock and return */ 00569 CsrReleaseProcessLock(); 00570 return STATUS_SUCCESS; 00571 } 00572 00573 /*++ 00574 * @name CsrAddStaticServerThread 00575 * @implemented NT4 00576 * 00577 * The CsrAddStaticServerThread routine adds a new CSR Thread to the 00578 * CSR Server Process (CsrRootProcess). 00579 * 00580 * @param hThread 00581 * Handle to an existing NT Thread to which to associate this 00582 * CSR Thread. 00583 * 00584 * @param ClientId 00585 * Pointer to the Client ID structure of the NT Thread to associate 00586 * with this CSR Thread. 00587 * 00588 * @param ThreadFlags 00589 * Initial CSR Thread Flags to associate to this CSR Thread. Usually 00590 * CsrThreadIsServerThread. 00591 * 00592 * @return Pointer to the newly allocated CSR Thread. 00593 * 00594 * @remarks None. 00595 * 00596 *--*/ 00597 PCSR_THREAD 00598 NTAPI 00599 CsrAddStaticServerThread(IN HANDLE hThread, 00600 IN PCLIENT_ID ClientId, 00601 IN ULONG ThreadFlags) 00602 { 00603 PCSR_THREAD CsrThread; 00604 00605 /* Get the Lock */ 00606 CsrAcquireProcessLock(); 00607 00608 /* Allocate the Server Thread */ 00609 CsrThread = CsrAllocateThread(CsrRootProcess); 00610 if (CsrThread) 00611 { 00612 /* Setup the Object */ 00613 CsrThread->ThreadHandle = hThread; 00614 ProtectHandle(hThread); 00615 CsrThread->ClientId = *ClientId; 00616 CsrThread->Flags = ThreadFlags; 00617 00618 /* Insert it into the Thread List */ 00619 InsertTailList(&CsrRootProcess->ThreadList, &CsrThread->Link); 00620 00621 /* Increment the thread count */ 00622 CsrRootProcess->ThreadCount++; 00623 } 00624 else 00625 { 00626 DPRINT1("CsrAddStaticServerThread: alloc failed for thread 0x%x\n", hThread); 00627 } 00628 00629 /* Release the Process Lock and return */ 00630 CsrReleaseProcessLock(); 00631 return CsrThread; 00632 } 00633 00634 /*++ 00635 * @name CsrDereferenceThread 00636 * @implemented NT4 00637 * 00638 * The CsrDereferenceThread routine removes a reference from a CSR Thread. 00639 * 00640 * @param CsrThread 00641 * Pointer to the CSR Thread to dereference. 00642 * 00643 * @return None. 00644 * 00645 * @remarks If the reference count has reached zero (ie: the CSR Thread has 00646 * no more active references), it will be deleted. 00647 * 00648 *--*/ 00649 VOID 00650 NTAPI 00651 CsrDereferenceThread(IN PCSR_THREAD CsrThread) 00652 { 00653 /* Acquire process lock */ 00654 CsrAcquireProcessLock(); 00655 00656 /* Decrease reference count */ 00657 ASSERT(CsrThread->ReferenceCount > 0); 00658 if (!(--CsrThread->ReferenceCount)) 00659 { 00660 /* Call the generic cleanup code */ 00661 CsrThreadRefcountZero(CsrThread); 00662 } 00663 else 00664 { 00665 /* Just release the lock */ 00666 CsrReleaseProcessLock(); 00667 } 00668 } 00669 00670 /* EOF */ Generated on Sat May 26 2012 04:36:33 for ReactOS by
1.7.6.1
|