[CSRSRV]
[reactos.git] / reactos / subsystems / win32 / csrss / csrsrv / thredsup.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS CSR Sub System
4 * FILE: subsystems/win32/csrss/csrsrv/thredsup.c
5 * PURPOSE: CSR Server DLL Thread Implementation
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 * Alex Ionescu
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <srv.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 #define CsrHashThread(t) \
18 (HandleToUlong(t)&(256 - 1))
19
20 /* GLOBALS ********************************************************************/
21
22 LIST_ENTRY CsrThreadHashTable[256];
23
24 /* FUNCTIONS ******************************************************************/
25
26 /*++
27 * @name ProtectHandle
28 * @implemented NT5.2
29 *
30 * The ProtectHandle routine protects an object handle against closure.
31 *
32 * @return TRUE or FALSE.
33 *
34 * @remarks None.
35 *
36 *--*/
37 BOOLEAN
38 NTAPI
39 ProtectHandle(IN HANDLE ObjectHandle)
40 {
41 NTSTATUS Status;
42 OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo;
43
44 /* Query current state */
45 Status = NtQueryObject(ObjectHandle,
46 ObjectHandleFlagInformation,
47 &HandleInfo,
48 sizeof(HandleInfo),
49 NULL);
50 if (NT_SUCCESS(Status))
51 {
52 /* Enable protect from close */
53 HandleInfo.ProtectFromClose = TRUE;
54 Status = NtSetInformationObject(ObjectHandle,
55 ObjectHandleFlagInformation,
56 &HandleInfo,
57 sizeof(HandleInfo));
58 if (NT_SUCCESS(Status)) return TRUE;
59 }
60
61 /* We failed to or set the state */
62 return FALSE;
63 }
64
65 /*++
66 * @name UnProtectHandle
67 * @implemented NT5.2
68 *
69 * The UnProtectHandle routine unprotects an object handle against closure.
70 *
71 * @return TRUE or FALSE.
72 *
73 * @remarks None.
74 *
75 *--*/
76 BOOLEAN
77 NTAPI
78 UnProtectHandle(IN HANDLE ObjectHandle)
79 {
80 NTSTATUS Status;
81 OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo;
82
83 /* Query current state */
84 Status = NtQueryObject(ObjectHandle,
85 ObjectHandleFlagInformation,
86 &HandleInfo,
87 sizeof(HandleInfo),
88 NULL);
89 if (NT_SUCCESS(Status))
90 {
91 /* Disable protect from close */
92 HandleInfo.ProtectFromClose = FALSE;
93 Status = NtSetInformationObject(ObjectHandle,
94 ObjectHandleFlagInformation,
95 &HandleInfo,
96 sizeof(HandleInfo));
97 if (NT_SUCCESS(Status)) return TRUE;
98 }
99
100 /* We failed to or set the state */
101 return FALSE;
102 }
103
104 /*++
105 * @name CsrAllocateThread
106 *
107 * The CsrAllocateThread routine allocates a new CSR Thread object.
108 *
109 * @param CsrProcess
110 * Pointer to the CSR Process which will contain this CSR Thread.
111 *
112 * @return Pointer to the newly allocated CSR Thread.
113 *
114 * @remarks None.
115 *
116 *--*/
117 PCSR_THREAD
118 NTAPI
119 CsrAllocateThread(IN PCSR_PROCESS CsrProcess)
120 {
121 PCSR_THREAD CsrThread;
122
123 /* Allocate the structure */
124 CsrThread = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, sizeof(CSR_THREAD));
125 if (!CsrThread) return(NULL);
126
127 /* Reference the Thread and Process */
128 CsrThread->ReferenceCount++;
129 CsrProcess->ReferenceCount++;
130
131 /* Set the Parent Process */
132 CsrThread->Process = CsrProcess;
133
134 /* Return Thread */
135 return CsrThread;
136 }
137
138 /*++
139 * @name CsrLockedReferenceThread
140 *
141 * The CsrLockedReferenceThread references a CSR Thread while the
142 * Process Lock is already being held.
143 *
144 * @param CsrThread
145 * Pointer to the CSR Thread to be referenced.
146 *
147 * @return None.
148 *
149 * @remarks This routine will return with the Process Lock held.
150 *
151 *--*/
152 VOID
153 NTAPI
154 CsrLockedReferenceThread(IN PCSR_THREAD CsrThread)
155 {
156 /* Increment the reference count */
157 ++CsrThread->ReferenceCount;
158 }
159
160 /*++
161 * @name CsrLocateThreadByClientId
162 *
163 * The CsrLocateThreadByClientId routine locates the CSR Thread and,
164 * optionally, its parent CSR Process, corresponding to a Client ID.
165 *
166 * @param Process
167 * Optional pointer to a CSR Process pointer which will contain
168 * the CSR Thread's parent.
169 *
170 * @param ClientId
171 * Pointer to a Client ID structure containing the Unique Thread ID
172 * to look up.
173 *
174 * @return Pointer to the CSR Thread corresponding to this CID, or NULL if
175 * none was found.
176 *
177 * @remarks None.
178 *
179 *--*/
180 PCSR_THREAD
181 NTAPI
182 CsrLocateThreadByClientId(OUT PCSR_PROCESS *Process OPTIONAL,
183 IN PCLIENT_ID ClientId)
184 {
185 ULONG i;
186 PLIST_ENTRY ListHead, NextEntry;
187 PCSR_THREAD FoundThread;
188 // ASSERT(ProcessStructureListLocked());
189
190 /* Hash the Thread */
191 i = CsrHashThread(ClientId->UniqueThread);
192
193 /* Set the list pointers */
194 ListHead = &CsrThreadHashTable[i];
195 NextEntry = ListHead->Flink;
196
197 /* Star the loop */
198 while (NextEntry != ListHead)
199 {
200 /* Get the thread */
201 FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
202
203 /* Compare the CID */
204 if (FoundThread->ClientId.UniqueThread == ClientId->UniqueThread)
205 {
206 /* Match found, return the process */
207 *Process = FoundThread->Process;
208
209 /* Return thread too */
210 // DPRINT1("Found: %p %p\n", FoundThread, FoundThread->Process);
211 return FoundThread;
212 }
213
214 /* Next */
215 NextEntry = NextEntry->Flink;
216 }
217
218 /* Nothing found */
219 return NULL;
220 }
221
222 /*++
223 * @name CsrLocateThreadInProcess
224 *
225 * The CsrLocateThreadInProcess routine locates the CSR Thread
226 * corresponding to a Client ID inside a specific CSR Process.
227 *
228 * @param Process
229 * Optional pointer to the CSR Process which contains the CSR Thread
230 * that will be looked up.
231 *
232 * @param ClientId
233 * Pointer to a Client ID structure containing the Unique Thread ID
234 * to look up.
235 *
236 * @return Pointer to the CSR Thread corresponding to this CID, or NULL if
237 * none was found.
238 *
239 * @remarks If the CsrProcess argument is NULL, the lookup will be done inside
240 * CsrRootProcess.
241 *
242 *--*/
243 PCSR_THREAD
244 NTAPI
245 CsrLocateThreadInProcess(IN PCSR_PROCESS CsrProcess OPTIONAL,
246 IN PCLIENT_ID Cid)
247 {
248 PLIST_ENTRY ListHead, NextEntry;
249 PCSR_THREAD FoundThread = NULL;
250
251 /* Use the Root Process if none was specified */
252 if (!CsrProcess) CsrProcess = CsrRootProcess;
253
254 /* Save the List pointers */
255 // DPRINT1("Searching in: %p %d\n", CsrProcess, CsrProcess->ThreadCount);
256 ListHead = &CsrProcess->ThreadList;
257 NextEntry = ListHead->Flink;
258
259 /* Start the Loop */
260 while (NextEntry != ListHead)
261 {
262 /* Get Thread Entry */
263 FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
264
265 /* Check for TID Match */
266 if (FoundThread->ClientId.UniqueThread == Cid->UniqueThread) break;
267
268 /* Next entry */
269 NextEntry = NextEntry->Flink;
270 }
271
272 /* Return what we found */
273 // DPRINT1("Found: %p\n", FoundThread);
274 return FoundThread;
275 }
276
277 /*++
278 * @name CsrInsertThread
279 *
280 * The CsrInsertThread routine inserts a CSR Thread into its parent's
281 * Thread List and into the Thread Hash Table.
282 *
283 * @param Process
284 * Pointer to the CSR Process containing this CSR Thread.
285 *
286 * @param Thread
287 * Pointer to the CSR Thread to be inserted.
288 *
289 * @return None.
290 *
291 * @remarks None.
292 *
293 *--*/
294 VOID
295 NTAPI
296 CsrInsertThread(IN PCSR_PROCESS Process,
297 IN PCSR_THREAD Thread)
298 {
299 ULONG i;
300 // ASSERT(ProcessStructureListLocked());
301
302 /* Insert it into the Regular List */
303 InsertTailList(&Process->ThreadList, &Thread->Link);
304
305 /* Increase Thread Count */
306 Process->ThreadCount++;
307
308 /* Hash the Thread */
309 i = CsrHashThread(Thread->ClientId.UniqueThread);
310 // DPRINT1("TID %lx HASH: %lx\n", Thread->ClientId.UniqueThread, i);
311
312 /* Insert it there too */
313 InsertHeadList(&CsrThreadHashTable[i], &Thread->HashLinks);
314 }
315
316 /*++
317 * @name CsrDeallocateThread
318 *
319 * The CsrDeallocateThread frees the memory associated with a CSR Thread.
320 *
321 * @param CsrThread
322 * Pointer to the CSR Thread to be freed.
323 *
324 * @return None.
325 *
326 * @remarks Do not call this routine. It is reserved for the internal
327 * thread management routines when a CSR Thread has been cleanly
328 * dereferenced and killed.
329 *
330 *--*/
331 VOID
332 NTAPI
333 CsrDeallocateThread(IN PCSR_THREAD CsrThread)
334 {
335 /* Free the process object from the heap */
336 // ASSERT(CsrThread->WaitBlock == NULL);
337 RtlFreeHeap(CsrHeap, 0, CsrThread);
338 }
339
340 /*++
341 * @name CsrRemoveThread
342 *
343 * The CsrRemoveThread function undoes a CsrInsertThread operation and
344 * removes the CSR Thread from the the Hash Table and Thread List.
345 *
346 * @param CsrThread
347 * Pointer to the CSR Thread to remove.
348 *
349 * @return None.
350 *
351 * @remarks If this CSR Thread is the last one inside a CSR Process, the
352 * parent will be dereferenced and the CsrProcessLastThreadTerminated
353 * flag will be set.
354 *
355 * After executing this routine, the CSR Thread will have the
356 * CsrThreadInTermination flag set.
357 *
358 *--*/
359 VOID
360 NTAPI
361 CsrRemoveThread(IN PCSR_THREAD CsrThread)
362 {
363 ASSERT(ProcessStructureListLocked());
364
365 /* Remove it from the List */
366 RemoveEntryList(&CsrThread->Link);
367
368 /* Decreate the thread count of the process */
369 CsrThread->Process->ThreadCount--;
370
371 /* Remove it from the Hash List as well */
372 if (CsrThread->HashLinks.Flink) RemoveEntryList(&CsrThread->HashLinks);
373
374 /* Check if this is the last Thread */
375 if (!CsrThread->Process->ThreadCount)
376 {
377 /* Check if it's not already been marked for deletion */
378 if (!(CsrThread->Process->Flags & CsrProcessLastThreadTerminated))
379 {
380 /* Let everyone know this process is about to lose the thread */
381 CsrThread->Process->Flags |= CsrProcessLastThreadTerminated;
382
383 /* Reference the Process */
384 CsrLockedDereferenceProcess(CsrThread->Process);
385 }
386 }
387
388 /* Mark the thread for deletion */
389 CsrThread->Flags |= CsrThreadInTermination;
390 }
391
392 /*++
393 * @name CsrCreateRemoteThread
394 * @implemented NT4
395 *
396 * The CsrCreateRemoteThread routine creates a CSR Thread object for
397 * an NT Thread which is not part of the current NT Process.
398 *
399 * @param hThread
400 * Handle to an existing NT Thread to which to associate this
401 * CSR Thread.
402 *
403 * @param ClientId
404 * Pointer to the Client ID structure of the NT Thread to associate
405 * with this CSR Thread.
406 *
407 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
408 * otherwise.
409 *
410 * @remarks None.
411 *
412 *--*/
413 NTSTATUS
414 NTAPI
415 CsrCreateRemoteThread(IN HANDLE hThread,
416 IN PCLIENT_ID ClientId)
417 {
418 NTSTATUS Status;
419 HANDLE ThreadHandle;
420 PCSR_THREAD CsrThread;
421 PCSR_PROCESS CsrProcess;
422 KERNEL_USER_TIMES KernelTimes;
423 DPRINT("CSRSRV: %s called\n", __FUNCTION__);
424
425 /* Get the Thread Create Time */
426 Status = NtQueryInformationThread(hThread,
427 ThreadTimes,
428 &KernelTimes,
429 sizeof(KernelTimes),
430 NULL);
431 if (!NT_SUCCESS(Status))
432 {
433 DPRINT1("Failed to query thread times: %lx\n", Status);
434 return Status;
435 }
436
437 /* Lock the Owner Process */
438 Status = CsrLockProcessByClientId(&ClientId->UniqueProcess, &CsrProcess);
439 if (!NT_SUCCESS(Status))
440 {
441 DPRINT1("No known process for %lx\n", ClientId->UniqueProcess);
442 return Status;
443 }
444
445 /* Make sure the thread didn't terminate */
446 if (KernelTimes.ExitTime.QuadPart)
447 {
448 /* Unlock the process and return */
449 CsrUnlockProcess(CsrProcess);
450 DPRINT1("Dead thread: %I64x\n", KernelTimes.ExitTime.QuadPart);
451 return STATUS_THREAD_IS_TERMINATING;
452 }
453
454 /* Allocate a CSR Thread Structure */
455 CsrThread = CsrAllocateThread(CsrProcess);
456 if (!CsrThread)
457 {
458 DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
459 CsrUnlockProcess(CsrProcess);
460 return STATUS_NO_MEMORY;
461 }
462
463 /* Duplicate the Thread Handle */
464 Status = NtDuplicateObject(NtCurrentProcess(),
465 hThread,
466 NtCurrentProcess(),
467 &ThreadHandle,
468 0,
469 0,
470 DUPLICATE_SAME_ACCESS);
471 /* Allow failure */
472 if (!NT_SUCCESS(Status))
473 {
474 DPRINT1("Thread duplication failed: %lx\n", Status);
475 ThreadHandle = hThread;
476 }
477
478 /* Save the data we have */
479 CsrThread->CreateTime = KernelTimes.CreateTime;
480 CsrThread->ClientId = *ClientId;
481 CsrThread->ThreadHandle = ThreadHandle;
482 ProtectHandle(ThreadHandle);
483 CsrThread->Flags = 0;
484
485 /* Insert the Thread into the Process */
486 CsrInsertThread(CsrProcess, CsrThread);
487
488 /* Release the lock and return */
489 CsrUnlockProcess(CsrProcess);
490 return STATUS_SUCCESS;
491 }
492
493 /*++
494 * @name CsrThreadRefcountZero
495 *
496 * The CsrThreadRefcountZero routine is executed when a CSR Thread has lost
497 * all its active references. It removes and de-allocates the CSR Thread.
498 *
499 * @param CsrThread
500 * Pointer to the CSR Thread that is to be deleted.
501 *
502 * @return None.
503 *
504 * @remarks Do not call this routine. It is reserved for the internal
505 * thread management routines when a CSR Thread has lost all
506 * its references.
507 *
508 * This routine is called with the Process Lock held.
509 *
510 *--*/
511 VOID
512 NTAPI
513 CsrThreadRefcountZero(IN PCSR_THREAD CsrThread)
514 {
515 PCSR_PROCESS CsrProcess = CsrThread->Process;
516 NTSTATUS Status;
517 ASSERT(ProcessStructureListLocked());
518
519 /* Remove this thread */
520 CsrRemoveThread(CsrThread);
521
522 /* Release the Process Lock */
523 CsrReleaseProcessLock();
524
525 /* Close the NT Thread Handle */
526 if (CsrThread->ThreadHandle)
527 {
528 UnProtectHandle(CsrThread->ThreadHandle);
529 Status = NtClose(CsrThread->ThreadHandle);
530 ASSERT(NT_SUCCESS(Status));
531 }
532
533 /* De-allocate the CSR Thread Object */
534 CsrDeallocateThread(CsrThread);
535
536 /* Remove a reference from the process */
537 CsrDereferenceProcess(CsrProcess);
538 }
539
540 /*++
541 * @name CsrDestroyThread
542 * @implemented NT4
543 *
544 * The CsrDestroyThread routine destroys the CSR Thread corresponding to
545 * a given Thread ID.
546 *
547 * @param Cid
548 * Pointer to the Client ID Structure corresponding to the CSR
549 * Thread which is about to be destroyed.
550 *
551 * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
552 * if the CSR Thread is already terminating.
553 *
554 * @remarks None.
555 *
556 *--*/
557 NTSTATUS
558 NTAPI
559 CsrDestroyThread(IN PCLIENT_ID Cid)
560 {
561 CLIENT_ID ClientId = *Cid;
562 PCSR_THREAD CsrThread;
563 PCSR_PROCESS CsrProcess;
564
565 /* Acquire lock */
566 CsrAcquireProcessLock();
567
568 /* Find the thread */
569 CsrThread = CsrLocateThreadByClientId(&CsrProcess,
570 &ClientId);
571
572 /* Make sure we got one back, and that it's not already gone */
573 if (!CsrThread || CsrThread->Flags & CsrThreadTerminated)
574 {
575 /* Release the lock and return failure */
576 CsrReleaseProcessLock();
577 return STATUS_THREAD_IS_TERMINATING;
578 }
579
580 /* Set the terminated flag */
581 CsrThread->Flags |= CsrThreadTerminated;
582
583 /* Acquire the Wait Lock */
584 CsrAcquireWaitLock();
585
586 /* Do we have an active wait block? */
587 if (CsrThread->WaitBlock)
588 {
589 /* Notify waiters of termination */
590 CsrNotifyWaitBlock(CsrThread->WaitBlock,
591 NULL,
592 NULL,
593 NULL,
594 CsrProcessTerminating,
595 TRUE);
596 }
597
598 /* Release the Wait Lock */
599 CsrReleaseWaitLock();
600
601 /* Dereference the thread */
602 CsrLockedDereferenceThread(CsrThread);
603
604 /* Release the Process Lock and return success */
605 CsrReleaseProcessLock();
606 return STATUS_SUCCESS;
607 }
608
609 /*++
610 * @name CsrLockedDereferenceThread
611 *
612 * The CsrLockedDereferenceThread dereferences a CSR Thread while the
613 * Process Lock is already being held.
614 *
615 * @param CsrThread
616 * Pointer to the CSR Thread to be dereferenced.
617 *
618 * @return None.
619 *
620 * @remarks This routine will return with the Process Lock held.
621 *
622 *--*/
623 VOID
624 NTAPI
625 CsrLockedDereferenceThread(IN PCSR_THREAD CsrThread)
626 {
627 LONG LockCount;
628
629 /* Decrease reference count */
630 LockCount = --CsrThread->ReferenceCount;
631 ASSERT(LockCount >= 0);
632 if (!LockCount)
633 {
634 /* Call the generic cleanup code */
635 CsrThreadRefcountZero(CsrThread);
636 CsrAcquireProcessLock();
637 }
638 }
639
640 /*++
641 * @name CsrCreateThread
642 * @implemented NT4
643 *
644 * The CsrCreateThread routine creates a CSR Thread object for an NT Thread.
645 *
646 * @param CsrProcess
647 * Pointer to the CSR Process which will contain the CSR Thread.
648 *
649 * @param hThread
650 * Handle to an existing NT Thread to which to associate this
651 * CSR Thread.
652 *
653 * @param ClientId
654 * Pointer to the Client ID structure of the NT Thread to associate
655 * with this CSR Thread.
656 *
657 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
658 * otherwise.
659 *
660 * @remarks None.
661 *
662 *--*/
663 NTSTATUS
664 NTAPI
665 CsrCreateThread(IN PCSR_PROCESS CsrProcess,
666 IN HANDLE hThread,
667 IN PCLIENT_ID ClientId)
668 {
669 PCSR_THREAD CsrThread;
670 PCSR_PROCESS CurrentProcess;
671 PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
672 CLIENT_ID CurrentCid;
673 KERNEL_USER_TIMES KernelTimes;
674
675 /* Get the current thread and CID */
676 CurrentCid = CurrentThread->ClientId;
677
678 /* Acquire the Process Lock */
679 CsrAcquireProcessLock();
680
681 /* Get the current Process and make sure the Thread is valid with this CID */
682 CurrentThread = CsrLocateThreadByClientId(&CurrentProcess,
683 &CurrentCid);
684
685 /* Something is wrong if we get an empty thread back */
686 if (!CurrentThread)
687 {
688 DPRINT1("CSRSRV:%s: invalid thread!\n", __FUNCTION__);
689 CsrReleaseProcessLock();
690 return STATUS_THREAD_IS_TERMINATING;
691 }
692
693 /* Get the Thread Create Time */
694 NtQueryInformationThread(hThread,
695 ThreadTimes,
696 (PVOID)&KernelTimes,
697 sizeof(KernelTimes),
698 NULL);
699
700 /* Allocate a CSR Thread Structure */
701 if (!(CsrThread = CsrAllocateThread(CsrProcess)))
702 {
703 DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
704 CsrReleaseProcessLock();
705 return STATUS_NO_MEMORY;
706 }
707
708 /* Save the data we have */
709 CsrThread->CreateTime = KernelTimes.CreateTime;
710 CsrThread->ClientId = *ClientId;
711 CsrThread->ThreadHandle = hThread;
712 CsrThread->Flags = 0;
713
714 /* Insert the Thread into the Process */
715 CsrInsertThread(CsrProcess, CsrThread);
716
717 /* Release the lock and return */
718 CsrReleaseProcessLock();
719 return STATUS_SUCCESS;
720 }
721
722 /*++
723 * @name CsrAddStaticServerThread
724 * @implemented NT4
725 *
726 * The CsrAddStaticServerThread routine adds a new CSR Thread to the
727 * CSR Server Process (CsrRootProcess).
728 *
729 * @param hThread
730 * Handle to an existing NT Thread to which to associate this
731 * CSR Thread.
732 *
733 * @param ClientId
734 * Pointer to the Client ID structure of the NT Thread to associate
735 * with this CSR Thread.
736 *
737 * @param ThreadFlags
738 * Initial CSR Thread Flags to associate to this CSR Thread. Usually
739 * CsrThreadIsServerThread.
740 *
741 * @return Pointer to the newly allocated CSR Thread.
742 *
743 * @remarks None.
744 *
745 *--*/
746 PCSR_THREAD
747 NTAPI
748 CsrAddStaticServerThread(IN HANDLE hThread,
749 IN PCLIENT_ID ClientId,
750 IN ULONG ThreadFlags)
751 {
752 PCSR_THREAD CsrThread;
753
754 /* Get the Lock */
755 CsrAcquireProcessLock();
756
757 /* Allocate the Server Thread */
758 CsrThread = CsrAllocateThread(CsrRootProcess);
759 if (CsrThread)
760 {
761 /* Setup the Object */
762 CsrThread->ThreadHandle = hThread;
763 ProtectHandle(hThread);
764 CsrThread->ClientId = *ClientId;
765 CsrThread->Flags = ThreadFlags;
766
767 /* Insert it into the Thread List */
768 InsertTailList(&CsrRootProcess->ThreadList, &CsrThread->Link);
769
770 /* Increment the thread count */
771 CsrRootProcess->ThreadCount++;
772 }
773 else
774 {
775 DPRINT1("CsrAddStaticServerThread: alloc failed for thread 0x%x\n", hThread);
776 }
777
778 /* Release the Process Lock and return */
779 CsrReleaseProcessLock();
780 return CsrThread;
781 }
782
783 /*++
784 * @name CsrDereferenceThread
785 * @implemented NT4
786 *
787 * The CsrDereferenceThread routine removes a reference from a CSR Thread.
788 *
789 * @param CsrThread
790 * Pointer to the CSR Thread to dereference.
791 *
792 * @return None.
793 *
794 * @remarks If the reference count has reached zero (ie: the CSR Thread has
795 * no more active references), it will be deleted.
796 *
797 *--*/
798 VOID
799 NTAPI
800 CsrDereferenceThread(IN PCSR_THREAD CsrThread)
801 {
802 /* Acquire process lock */
803 CsrAcquireProcessLock();
804
805 /* Decrease reference count */
806 ASSERT(CsrThread->ReferenceCount > 0);
807 if (!(--CsrThread->ReferenceCount))
808 {
809 /* Call the generic cleanup code */
810 CsrThreadRefcountZero(CsrThread);
811 }
812 else
813 {
814 /* Just release the lock */
815 CsrReleaseProcessLock();
816 }
817 }
818
819 /* EOF */