ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

thredsup.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.