[CSRSRV]
[reactos.git] / subsystems / win32 / csrsrv / thredsup.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Client/Server Runtime SubSystem
4 * FILE: subsystems/win32/csrsrv/thredsup.c
5 * PURPOSE: CSR Server DLL Thread Management
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 * Alex Ionescu (alex@relsoft.net)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <srv.h>
13
14 #define NDEBUG
15 #include <debug.h>
16
17 #define CsrHashThread(t) (HandleToUlong(t)&(256 - 1))
18
19 /* GLOBALS ********************************************************************/
20
21 LIST_ENTRY CsrThreadHashTable[256];
22
23
24 /* PRIVATE 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 CsrLockedReferenceThread(CsrThread);
129 CsrLockedReferenceProcess(CsrProcess);
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 if (Process) *Process = NULL;
191
192 /* Hash the Thread */
193 i = CsrHashThread(ClientId->UniqueThread);
194
195 /* Set the list pointers */
196 ListHead = &CsrThreadHashTable[i];
197 NextEntry = ListHead->Flink;
198
199 /* Star the loop */
200 while (NextEntry != ListHead)
201 {
202 /* Get the thread */
203 FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
204
205 /* Move to the next entry */
206 NextEntry = NextEntry->Flink;
207
208 /* Compare the CID */
209 // if (*(PULONGLONG)&FoundThread->ClientId == *(PULONGLONG)ClientId)
210 if ( FoundThread->ClientId.UniqueProcess == ClientId->UniqueProcess &&
211 FoundThread->ClientId.UniqueThread == ClientId->UniqueThread )
212 {
213 /* Match found, return the process */
214 if (Process) *Process = FoundThread->Process;
215
216 /* Return thread too */
217 return FoundThread;
218 }
219 }
220
221 /* Nothing found */
222 return NULL;
223 }
224
225 /*++
226 * @name CsrLocateThreadInProcess
227 *
228 * The CsrLocateThreadInProcess routine locates the CSR Thread
229 * corresponding to a Client ID inside a specific CSR Process.
230 *
231 * @param Process
232 * Optional pointer to the CSR Process which contains the CSR Thread
233 * that will be looked up.
234 *
235 * @param ClientId
236 * Pointer to a Client ID structure containing the Unique Thread ID
237 * to look up.
238 *
239 * @return Pointer to the CSR Thread corresponding to this CID, or NULL if
240 * none was found.
241 *
242 * @remarks If the CsrProcess argument is NULL, the lookup will be done inside
243 * CsrRootProcess.
244 *
245 *--*/
246 PCSR_THREAD
247 NTAPI
248 CsrLocateThreadInProcess(IN PCSR_PROCESS CsrProcess OPTIONAL,
249 IN PCLIENT_ID Cid)
250 {
251 PLIST_ENTRY ListHead, NextEntry;
252 PCSR_THREAD FoundThread = NULL;
253
254 /* Use the Root Process if none was specified */
255 if (!CsrProcess) CsrProcess = CsrRootProcess;
256
257 /* Save the List pointers */
258 ListHead = &CsrProcess->ThreadList;
259 NextEntry = ListHead->Flink;
260
261 /* Start the Loop */
262 while (NextEntry != ListHead)
263 {
264 /* Get Thread Entry */
265 FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
266
267 /* Check for TID Match */
268 if (FoundThread->ClientId.UniqueThread == Cid->UniqueThread) break;
269
270 /* Move to the next entry */
271 NextEntry = NextEntry->Flink;
272 }
273
274 /* Return what we found */
275 return FoundThread;
276 }
277
278 /*++
279 * @name CsrInsertThread
280 *
281 * The CsrInsertThread routine inserts a CSR Thread into its parent's
282 * Thread List and into the Thread Hash Table.
283 *
284 * @param Process
285 * Pointer to the CSR Process containing this CSR Thread.
286 *
287 * @param Thread
288 * Pointer to the CSR Thread to be inserted.
289 *
290 * @return None.
291 *
292 * @remarks None.
293 *
294 *--*/
295 VOID
296 NTAPI
297 CsrInsertThread(IN PCSR_PROCESS Process,
298 IN PCSR_THREAD Thread)
299 {
300 ULONG i;
301 // ASSERT(ProcessStructureListLocked());
302
303 /* Insert it into the Regular List */
304 InsertTailList(&Process->ThreadList, &Thread->Link);
305
306 /* Increase Thread Count */
307 Process->ThreadCount++;
308
309 /* Hash the Thread */
310 i = CsrHashThread(Thread->ClientId.UniqueThread);
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 == 0)
376 {
377 /* Check if it's not already been marked for deletion */
378 if ((CsrThread->Process->Flags & CsrProcessLastThreadTerminated) == 0)
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 CsrThreadRefcountZero
394 *
395 * The CsrThreadRefcountZero routine is executed when a CSR Thread has lost
396 * all its active references. It removes and de-allocates the CSR Thread.
397 *
398 * @param CsrThread
399 * Pointer to the CSR Thread that is to be deleted.
400 *
401 * @return None.
402 *
403 * @remarks Do not call this routine. It is reserved for the internal
404 * thread management routines when a CSR Thread has lost all
405 * its references.
406 *
407 * This routine is called with the Process Lock held.
408 *
409 *--*/
410 VOID
411 NTAPI
412 CsrThreadRefcountZero(IN PCSR_THREAD CsrThread)
413 {
414 PCSR_PROCESS CsrProcess = CsrThread->Process;
415 NTSTATUS Status;
416 ASSERT(ProcessStructureListLocked());
417
418 /* Remove this thread */
419 CsrRemoveThread(CsrThread);
420
421 /* Release the Process Lock */
422 CsrReleaseProcessLock();
423
424 /* Close the NT Thread Handle */
425 if (CsrThread->ThreadHandle)
426 {
427 UnProtectHandle(CsrThread->ThreadHandle);
428 Status = NtClose(CsrThread->ThreadHandle);
429 ASSERT(NT_SUCCESS(Status));
430 }
431
432 /* De-allocate the CSR Thread Object */
433 CsrDeallocateThread(CsrThread);
434
435 /* Remove a reference from the process */
436 CsrDereferenceProcess(CsrProcess);
437 }
438
439 /*++
440 * @name CsrLockedDereferenceThread
441 *
442 * The CsrLockedDereferenceThread dereferences a CSR Thread while the
443 * Process Lock is already being held.
444 *
445 * @param CsrThread
446 * Pointer to the CSR Thread to be dereferenced.
447 *
448 * @return None.
449 *
450 * @remarks This routine will return with the Process Lock held.
451 *
452 *--*/
453 VOID
454 NTAPI
455 CsrLockedDereferenceThread(IN PCSR_THREAD CsrThread)
456 {
457 LONG LockCount;
458
459 /* Decrease reference count */
460 LockCount = --CsrThread->ReferenceCount;
461 ASSERT(LockCount >= 0);
462 if (LockCount == 0)
463 {
464 /* Call the generic cleanup code */
465 CsrAcquireProcessLock();
466 CsrThreadRefcountZero(CsrThread);
467 }
468 }
469
470
471 /* PUBLIC FUNCTIONS ***********************************************************/
472
473 /*++
474 * @name CsrAddStaticServerThread
475 * @implemented NT4
476 *
477 * The CsrAddStaticServerThread routine adds a new CSR Thread to the
478 * CSR Server Process (CsrRootProcess).
479 *
480 * @param hThread
481 * Handle to an existing NT Thread to which to associate this
482 * CSR Thread.
483 *
484 * @param ClientId
485 * Pointer to the Client ID structure of the NT Thread to associate
486 * with this CSR Thread.
487 *
488 * @param ThreadFlags
489 * Initial CSR Thread Flags to associate to this CSR Thread. Usually
490 * CsrThreadIsServerThread.
491 *
492 * @return Pointer to the newly allocated CSR Thread.
493 *
494 * @remarks None.
495 *
496 *--*/
497 PCSR_THREAD
498 NTAPI
499 CsrAddStaticServerThread(IN HANDLE hThread,
500 IN PCLIENT_ID ClientId,
501 IN ULONG ThreadFlags)
502 {
503 PCSR_THREAD CsrThread;
504
505 /* Get the Lock */
506 CsrAcquireProcessLock();
507
508 /* Allocate the Server Thread */
509 CsrThread = CsrAllocateThread(CsrRootProcess);
510 if (CsrThread)
511 {
512 /* Setup the Object */
513 CsrThread->ThreadHandle = hThread;
514 ProtectHandle(hThread);
515 CsrThread->ClientId = *ClientId;
516 CsrThread->Flags = ThreadFlags;
517
518 /* Insert it into the Thread List */
519 InsertTailList(&CsrRootProcess->ThreadList, &CsrThread->Link);
520
521 /* Increment the thread count */
522 CsrRootProcess->ThreadCount++;
523 }
524 else
525 {
526 DPRINT1("CsrAddStaticServerThread: alloc failed for thread 0x%x\n", hThread);
527 }
528
529 /* Release the Process Lock and return */
530 CsrReleaseProcessLock();
531 return CsrThread;
532 }
533
534 /*++
535 * @name CsrCreateRemoteThread
536 * @implemented NT4
537 *
538 * The CsrCreateRemoteThread routine creates a CSR Thread object for
539 * an NT Thread which is not part of the current NT Process.
540 *
541 * @param hThread
542 * Handle to an existing NT Thread to which to associate this
543 * CSR Thread.
544 *
545 * @param ClientId
546 * Pointer to the Client ID structure of the NT Thread to associate
547 * with this CSR Thread.
548 *
549 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
550 *
551 * @remarks None.
552 *
553 *--*/
554 NTSTATUS
555 NTAPI
556 CsrCreateRemoteThread(IN HANDLE hThread,
557 IN PCLIENT_ID ClientId)
558 {
559 NTSTATUS Status;
560 HANDLE ThreadHandle;
561 PCSR_THREAD CsrThread;
562 PCSR_PROCESS CsrProcess;
563 KERNEL_USER_TIMES KernelTimes;
564
565 /* Get the Thread Create Time */
566 Status = NtQueryInformationThread(hThread,
567 ThreadTimes,
568 &KernelTimes,
569 sizeof(KernelTimes),
570 NULL);
571 if (!NT_SUCCESS(Status))
572 {
573 DPRINT1("Failed to query thread times: %lx\n", Status);
574 return Status;
575 }
576
577 /* Lock the Owner Process */
578 Status = CsrLockProcessByClientId(ClientId->UniqueProcess, &CsrProcess);
579 if (!NT_SUCCESS(Status))
580 {
581 DPRINT1("No known process for %lx\n", ClientId->UniqueProcess);
582 return Status;
583 }
584
585 /* Make sure the thread didn't terminate */
586 if (KernelTimes.ExitTime.QuadPart)
587 {
588 /* Unlock the process and return */
589 CsrUnlockProcess(CsrProcess);
590 DPRINT1("Dead thread: %I64x\n", KernelTimes.ExitTime.QuadPart);
591 return STATUS_THREAD_IS_TERMINATING;
592 }
593
594 /* Allocate a CSR Thread Structure */
595 CsrThread = CsrAllocateThread(CsrProcess);
596 if (!CsrThread)
597 {
598 DPRINT1("CSRSRV: %s: out of memory!\n", __FUNCTION__);
599 CsrUnlockProcess(CsrProcess);
600 return STATUS_NO_MEMORY;
601 }
602
603 /* Duplicate the Thread Handle */
604 Status = NtDuplicateObject(NtCurrentProcess(),
605 hThread,
606 NtCurrentProcess(),
607 &ThreadHandle,
608 0,
609 0,
610 DUPLICATE_SAME_ACCESS);
611 /* Allow failure */
612 if (!NT_SUCCESS(Status))
613 {
614 DPRINT1("Thread duplication failed: %lx\n", Status);
615 ThreadHandle = hThread;
616 }
617
618 /* Save the data we have */
619 CsrThread->CreateTime = KernelTimes.CreateTime;
620 CsrThread->ClientId = *ClientId;
621 CsrThread->ThreadHandle = ThreadHandle;
622 ProtectHandle(ThreadHandle);
623 CsrThread->Flags = 0;
624
625 /* Insert the Thread into the Process */
626 CsrInsertThread(CsrProcess, CsrThread);
627
628 /* Release the lock and return */
629 CsrUnlockProcess(CsrProcess);
630 return STATUS_SUCCESS;
631 }
632
633 /*++
634 * @name CsrCreateThread
635 * @implemented NT4
636 *
637 * The CsrCreateThread routine creates a CSR Thread object for an NT Thread.
638 *
639 * @param CsrProcess
640 * Pointer to the CSR Process which will contain the CSR Thread.
641 *
642 * @param hThread
643 * Handle to an existing NT Thread to which to associate this
644 * CSR Thread.
645 *
646 * @param ClientId
647 * Pointer to the Client ID structure of the NT Thread to associate
648 * with this CSR Thread.
649 *
650 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
651 *
652 * @remarks None.
653 *
654 *--*/
655 NTSTATUS
656 NTAPI
657 CsrCreateThread(IN PCSR_PROCESS CsrProcess,
658 IN HANDLE hThread,
659 IN PCLIENT_ID ClientId,
660 IN BOOLEAN HaveClient)
661 {
662 NTSTATUS Status;
663 PCSR_THREAD CsrThread, CurrentThread;
664 PCSR_PROCESS CurrentProcess;
665 CLIENT_ID CurrentCid;
666 KERNEL_USER_TIMES KernelTimes;
667
668 if (HaveClient)
669 {
670 /* Get the current thread and CID */
671 CurrentThread = CsrGetClientThread();
672 CurrentCid = CurrentThread->ClientId;
673
674 /* Acquire the Process Lock */
675 CsrAcquireProcessLock();
676
677 /* Get the current Process and make sure the Thread is valid with this CID */
678 CurrentThread = CsrLocateThreadByClientId(&CurrentProcess, &CurrentCid);
679
680 /* Something is wrong if we get an empty thread back */
681 if (!CurrentThread)
682 {
683 DPRINT1("CSRSRV: %s: invalid thread!\n", __FUNCTION__);
684 CsrReleaseProcessLock();
685 return STATUS_THREAD_IS_TERMINATING;
686 }
687 }
688 else
689 {
690 /* Acquire the Process Lock */
691 CsrAcquireProcessLock();
692 }
693
694 /* Get the Thread Create Time */
695 Status = NtQueryInformationThread(hThread,
696 ThreadTimes,
697 (PVOID)&KernelTimes,
698 sizeof(KernelTimes),
699 NULL);
700 if (!NT_SUCCESS(Status))
701 {
702 CsrReleaseProcessLock();
703 return Status;
704 }
705
706 /* Allocate a CSR Thread Structure */
707 CsrThread = CsrAllocateThread(CsrProcess);
708 if (!CsrThread)
709 {
710 DPRINT1("CSRSRV: %s: out of memory!\n", __FUNCTION__);
711 CsrReleaseProcessLock();
712 return STATUS_NO_MEMORY;
713 }
714
715 /* Save the data we have */
716 CsrThread->CreateTime = KernelTimes.CreateTime;
717 CsrThread->ClientId = *ClientId;
718 CsrThread->ThreadHandle = hThread;
719 ProtectHandle(hThread);
720 CsrThread->Flags = 0;
721
722 /* Insert the Thread into the Process */
723 CsrInsertThread(CsrProcess, CsrThread);
724
725 /* Release the lock and return */
726 CsrReleaseProcessLock();
727
728 return STATUS_SUCCESS;
729 }
730
731 /*++
732 * @name CsrDereferenceThread
733 * @implemented NT4
734 *
735 * The CsrDereferenceThread routine removes a reference from a CSR Thread.
736 *
737 * @param CsrThread
738 * Pointer to the CSR Thread to dereference.
739 *
740 * @return None.
741 *
742 * @remarks If the reference count has reached zero (ie: the CSR Thread has
743 * no more active references), it will be deleted.
744 *
745 *--*/
746 VOID
747 NTAPI
748 CsrDereferenceThread(IN PCSR_THREAD CsrThread)
749 {
750 /* Acquire process lock */
751 CsrAcquireProcessLock();
752
753 /* Decrease reference count */
754 ASSERT(CsrThread->ReferenceCount > 0);
755 if ((--CsrThread->ReferenceCount) == 0)
756 {
757 /* Call the generic cleanup code */
758 CsrThreadRefcountZero(CsrThread);
759 }
760 else
761 {
762 /* Just release the lock */
763 CsrReleaseProcessLock();
764 }
765 }
766
767 /*++
768 * @name CsrDestroyThread
769 * @implemented NT4
770 *
771 * The CsrDestroyThread routine destroys the CSR Thread corresponding to
772 * a given Thread ID.
773 *
774 * @param Cid
775 * Pointer to the Client ID Structure corresponding to the CSR
776 * Thread which is about to be destroyed.
777 *
778 * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
779 * if the CSR Thread is already terminating.
780 *
781 * @remarks None.
782 *
783 *--*/
784 NTSTATUS
785 NTAPI
786 CsrDestroyThread(IN PCLIENT_ID Cid)
787 {
788 CLIENT_ID ClientId = *Cid;
789 PCSR_THREAD CsrThread;
790 PCSR_PROCESS CsrProcess;
791
792 /* Acquire lock */
793 CsrAcquireProcessLock();
794
795 /* Find the thread */
796 CsrThread = CsrLocateThreadByClientId(&CsrProcess,
797 &ClientId);
798
799 /* Make sure we got one back, and that it's not already gone */
800 if (!CsrThread || (CsrThread->Flags & CsrThreadTerminated))
801 {
802 /* Release the lock and return failure */
803 CsrReleaseProcessLock();
804 return STATUS_THREAD_IS_TERMINATING;
805 }
806
807 /* Set the terminated flag */
808 CsrThread->Flags |= CsrThreadTerminated;
809
810 /* Acquire the Wait Lock */
811 CsrAcquireWaitLock();
812
813 /* Do we have an active wait block? */
814 if (CsrThread->WaitBlock)
815 {
816 /* Notify waiters of termination */
817 CsrNotifyWaitBlock(CsrThread->WaitBlock,
818 NULL,
819 NULL,
820 NULL,
821 CsrProcessTerminating,
822 TRUE);
823 }
824
825 /* Release the Wait Lock */
826 CsrReleaseWaitLock();
827
828 /* Dereference the thread */
829 CsrLockedDereferenceThread(CsrThread);
830
831 /* Release the Process Lock and return success */
832 CsrReleaseProcessLock();
833 return STATUS_SUCCESS;
834 }
835
836 /*++
837 * @name CsrExecServerThread
838 * @implemented NT4
839 *
840 * The CsrExecServerThread routine creates an NT Thread and then
841 * initializes a CSR Thread for it.
842 *
843 * @param ThreadHandler
844 * Pointer to the thread's startup routine.
845 *
846 * @param Flags
847 * Initial CSR Thread Flags to set to the CSR Thread.
848 *
849 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
850 *
851 * @remarks This routine is similar to CsrAddStaticServerThread, but it
852 * also creates an NT Thread instead of expecting one to already
853 * exist.
854 *
855 *--*/
856 NTSTATUS
857 NTAPI
858 CsrExecServerThread(IN PVOID ThreadHandler,
859 IN ULONG Flags)
860 {
861 PCSR_THREAD CsrThread;
862 HANDLE hThread;
863 CLIENT_ID ClientId;
864 NTSTATUS Status;
865
866 /* Acquire process lock */
867 CsrAcquireProcessLock();
868
869 /* Allocate a CSR Thread in the Root Process */
870 ASSERT(CsrRootProcess != NULL);
871 CsrThread = CsrAllocateThread(CsrRootProcess);
872 if (!CsrThread)
873 {
874 /* Fail */
875 CsrReleaseProcessLock();
876 return STATUS_NO_MEMORY;
877 }
878
879 /* Create the Thread */
880 Status = RtlCreateUserThread(NtCurrentProcess(),
881 NULL,
882 FALSE,
883 0,
884 0,
885 0,
886 ThreadHandler,
887 NULL,
888 &hThread,
889 &ClientId);
890 if (!NT_SUCCESS(Status))
891 {
892 /* Fail */
893 CsrDeallocateThread(CsrThread);
894 CsrReleaseProcessLock();
895 return Status;
896 }
897
898 /* Setup the Thread Object */
899 CsrThread->ThreadHandle = hThread;
900 ProtectHandle(hThread);
901 CsrThread->ClientId = ClientId;
902 CsrThread->Flags = Flags;
903
904 /* Insert it into the Thread List */
905 InsertHeadList(&CsrRootProcess->ThreadList, &CsrThread->Link);
906
907 /* Increase the thread count */
908 CsrRootProcess->ThreadCount++;
909
910 /* Return */
911 CsrReleaseProcessLock();
912 return Status;
913 }
914
915 /*++
916 * @name CsrLockThreadByClientId
917 * @implemented NT4
918 *
919 * The CsrLockThreadByClientId routine locks the CSR Thread corresponding
920 * to the given Thread ID and optionally returns it.
921 *
922 * @param Tid
923 * Thread ID corresponding to the CSR Thread which will be locked.
924 *
925 * @param CsrThread
926 * Optional pointer to a CSR Thread pointer which will hold the
927 * CSR Thread corresponding to the given Thread ID.
928 *
929 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
930 *
931 * @remarks Locking a CSR Thread is defined as acquiring an extra
932 * reference to it and returning with the Process Lock held.
933 *
934 *--*/
935 NTSTATUS
936 NTAPI
937 CsrLockThreadByClientId(IN HANDLE Tid,
938 OUT PCSR_THREAD *CsrThread)
939 {
940 PLIST_ENTRY NextEntry;
941 PCSR_THREAD CurrentThread = NULL;
942 NTSTATUS Status = STATUS_UNSUCCESSFUL;
943 ULONG i;
944
945 /* Acquire the lock */
946 CsrAcquireProcessLock();
947
948 /* Assume failure */
949 ASSERT(CsrThread != NULL);
950 *CsrThread = NULL;
951
952 /* Convert to Hash */
953 i = CsrHashThread(Tid);
954
955 /* Setup the List Pointers */
956 NextEntry = CsrThreadHashTable[i].Flink;
957
958 /* Start Loop */
959 while (NextEntry != &CsrThreadHashTable[i])
960 {
961 /* Get the Process */
962 CurrentThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
963
964 /* Check for PID Match */
965 if ((CurrentThread->ClientId.UniqueThread == Tid) &&
966 (CurrentThread->Flags & CsrThreadTerminated) == 0)
967 {
968 /* Get out of here */
969 break;
970 }
971
972 /* Move to the next entry */
973 NextEntry = NextEntry->Flink;
974 }
975
976 /* Nothing found if we got back to the list */
977 if (NextEntry == &CsrThreadHashTable[i]) CurrentThread = NULL;
978
979 /* Did the loop find something? */
980 if (CurrentThread)
981 {
982 /* Reference the found thread */
983 Status = STATUS_SUCCESS;
984 CsrLockedReferenceThread(CurrentThread);
985 *CsrThread = CurrentThread;
986 }
987 else
988 {
989 /* Nothing found, release the lock */
990 Status = STATUS_UNSUCCESSFUL;
991 CsrReleaseProcessLock();
992 }
993
994 /* Return the status */
995 return Status;
996 }
997
998 /*++
999 * @name CsrReferenceThread
1000 * @implemented NT4
1001 *
1002 * The CsrReferenceThread routine increases the active reference count of
1003 * a CSR Thread.
1004 *
1005 * @param CsrThread
1006 * Pointer to the CSR Thread whose reference count will be increased.
1007 *
1008 * @return None.
1009 *
1010 * @remarks Do not use this routine if the Process Lock is already held.
1011 *
1012 *--*/
1013 VOID
1014 NTAPI
1015 CsrReferenceThread(IN PCSR_THREAD CsrThread)
1016 {
1017 /* Acquire process lock */
1018 CsrAcquireProcessLock();
1019
1020 /* Sanity checks */
1021 ASSERT(CsrThread->Flags & CsrThreadTerminated); // CSR_THREAD_DESTROYED in ASSERT
1022 ASSERT(CsrThread->ReferenceCount != 0);
1023
1024 /* Increment reference count */
1025 CsrThread->ReferenceCount++;
1026
1027 /* Release the lock */
1028 CsrReleaseProcessLock();
1029 }
1030
1031 /*++
1032 * @name CsrUnlockThread
1033 * @implemented NT4
1034 *
1035 * The CsrUnlockThread undoes a previous CsrLockThreadByClientId operation.
1036 *
1037 * @param CsrThread
1038 * Pointer to a previously locked CSR Thread.
1039 *
1040 * @return STATUS_SUCCESS.
1041 *
1042 * @remarks This routine must be called with the Process Lock held.
1043 *
1044 *--*/
1045 NTSTATUS
1046 NTAPI
1047 CsrUnlockThread(IN PCSR_THREAD CsrThread)
1048 {
1049 /* Dereference the Thread */
1050 ASSERT(ProcessStructureListLocked());
1051 CsrLockedDereferenceThread(CsrThread);
1052
1053 /* Release the lock and return */
1054 CsrReleaseProcessLock();
1055 return STATUS_SUCCESS;
1056 }
1057
1058 /* EOF */