[NTDLL]
[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) \
18 (HandleToUlong(t)&(256 - 1))
19
20 /* GLOBALS ********************************************************************/
21
22 LIST_ENTRY CsrThreadHashTable[256];
23
24
25 /* PRIVATE FUNCTIONS **********************************************************/
26
27 /*++
28 * @name ProtectHandle
29 * @implemented NT5.2
30 *
31 * The ProtectHandle routine protects an object handle against closure.
32 *
33 * @return TRUE or FALSE.
34 *
35 * @remarks None.
36 *
37 *--*/
38 BOOLEAN
39 NTAPI
40 ProtectHandle(IN HANDLE ObjectHandle)
41 {
42 NTSTATUS Status;
43 OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo;
44
45 /* Query current state */
46 Status = NtQueryObject(ObjectHandle,
47 ObjectHandleFlagInformation,
48 &HandleInfo,
49 sizeof(HandleInfo),
50 NULL);
51 if (NT_SUCCESS(Status))
52 {
53 /* Enable protect from close */
54 HandleInfo.ProtectFromClose = TRUE;
55 Status = NtSetInformationObject(ObjectHandle,
56 ObjectHandleFlagInformation,
57 &HandleInfo,
58 sizeof(HandleInfo));
59 if (NT_SUCCESS(Status)) return TRUE;
60 }
61
62 /* We failed to or set the state */
63 return FALSE;
64 }
65
66 /*++
67 * @name UnProtectHandle
68 * @implemented NT5.2
69 *
70 * The UnProtectHandle routine unprotects an object handle against closure.
71 *
72 * @return TRUE or FALSE.
73 *
74 * @remarks None.
75 *
76 *--*/
77 BOOLEAN
78 NTAPI
79 UnProtectHandle(IN HANDLE ObjectHandle)
80 {
81 NTSTATUS Status;
82 OBJECT_HANDLE_ATTRIBUTE_INFORMATION HandleInfo;
83
84 /* Query current state */
85 Status = NtQueryObject(ObjectHandle,
86 ObjectHandleFlagInformation,
87 &HandleInfo,
88 sizeof(HandleInfo),
89 NULL);
90 if (NT_SUCCESS(Status))
91 {
92 /* Disable protect from close */
93 HandleInfo.ProtectFromClose = FALSE;
94 Status = NtSetInformationObject(ObjectHandle,
95 ObjectHandleFlagInformation,
96 &HandleInfo,
97 sizeof(HandleInfo));
98 if (NT_SUCCESS(Status)) return TRUE;
99 }
100
101 /* We failed to or set the state */
102 return FALSE;
103 }
104
105 /*++
106 * @name CsrAllocateThread
107 *
108 * The CsrAllocateThread routine allocates a new CSR Thread object.
109 *
110 * @param CsrProcess
111 * Pointer to the CSR Process which will contain this CSR Thread.
112 *
113 * @return Pointer to the newly allocated CSR Thread.
114 *
115 * @remarks None.
116 *
117 *--*/
118 PCSR_THREAD
119 NTAPI
120 CsrAllocateThread(IN PCSR_PROCESS CsrProcess)
121 {
122 PCSR_THREAD CsrThread;
123
124 /* Allocate the structure */
125 CsrThread = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, sizeof(CSR_THREAD));
126 if (!CsrThread) return(NULL);
127
128 /* Reference the Thread and Process */
129 CsrThread->ReferenceCount++;
130 CsrProcess->ReferenceCount++;
131
132 /* Set the Parent Process */
133 CsrThread->Process = CsrProcess;
134
135 /* Return Thread */
136 return CsrThread;
137 }
138
139 /*++
140 * @name CsrLockedReferenceThread
141 *
142 * The CsrLockedReferenceThread references a CSR Thread while the
143 * Process Lock is already being held.
144 *
145 * @param CsrThread
146 * Pointer to the CSR Thread to be referenced.
147 *
148 * @return None.
149 *
150 * @remarks This routine will return with the Process Lock held.
151 *
152 *--*/
153 VOID
154 NTAPI
155 CsrLockedReferenceThread(IN PCSR_THREAD CsrThread)
156 {
157 /* Increment the reference count */
158 ++CsrThread->ReferenceCount;
159 }
160
161 /*++
162 * @name CsrLocateThreadByClientId
163 *
164 * The CsrLocateThreadByClientId routine locates the CSR Thread and,
165 * optionally, its parent CSR Process, corresponding to a Client ID.
166 *
167 * @param Process
168 * Optional pointer to a CSR Process pointer which will contain
169 * the CSR Thread's parent.
170 *
171 * @param ClientId
172 * Pointer to a Client ID structure containing the Unique Thread ID
173 * to look up.
174 *
175 * @return Pointer to the CSR Thread corresponding to this CID, or NULL if
176 * none was found.
177 *
178 * @remarks None.
179 *
180 *--*/
181 PCSR_THREAD
182 NTAPI
183 CsrLocateThreadByClientId(OUT PCSR_PROCESS *Process OPTIONAL,
184 IN PCLIENT_ID ClientId)
185 {
186 ULONG i;
187 PLIST_ENTRY ListHead, NextEntry;
188 PCSR_THREAD FoundThread;
189 // ASSERT(ProcessStructureListLocked());
190
191 /* Hash the Thread */
192 i = CsrHashThread(ClientId->UniqueThread);
193
194 /* Set the list pointers */
195 ListHead = &CsrThreadHashTable[i];
196 NextEntry = ListHead->Flink;
197
198 /* Star the loop */
199 while (NextEntry != ListHead)
200 {
201 /* Get the thread */
202 FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
203
204 /* Compare the CID */
205 // FIXME: if (*(PULONGLONG)&FoundThread->ClientId == *(PULONGLONG)ClientId)
206 if (FoundThread->ClientId.UniqueThread == ClientId->UniqueThread)
207 {
208 /* Match found, return the process */
209 *Process = FoundThread->Process;
210
211 /* Return thread too */
212 // DPRINT1("Found: %p %p\n", FoundThread, FoundThread->Process);
213 return FoundThread;
214 }
215
216 /* Next */
217 NextEntry = NextEntry->Flink;
218 }
219
220 /* Nothing found */
221 return NULL;
222 }
223
224 /*++
225 * @name CsrLocateThreadInProcess
226 *
227 * The CsrLocateThreadInProcess routine locates the CSR Thread
228 * corresponding to a Client ID inside a specific CSR Process.
229 *
230 * @param Process
231 * Optional pointer to the CSR Process which contains the CSR Thread
232 * that will be looked up.
233 *
234 * @param ClientId
235 * Pointer to a Client ID structure containing the Unique Thread ID
236 * to look up.
237 *
238 * @return Pointer to the CSR Thread corresponding to this CID, or NULL if
239 * none was found.
240 *
241 * @remarks If the CsrProcess argument is NULL, the lookup will be done inside
242 * CsrRootProcess.
243 *
244 *--*/
245 PCSR_THREAD
246 NTAPI
247 CsrLocateThreadInProcess(IN PCSR_PROCESS CsrProcess OPTIONAL,
248 IN PCLIENT_ID Cid)
249 {
250 PLIST_ENTRY ListHead, NextEntry;
251 PCSR_THREAD FoundThread = NULL;
252
253 /* Use the Root Process if none was specified */
254 if (!CsrProcess) CsrProcess = CsrRootProcess;
255
256 /* Save the List pointers */
257 // DPRINT1("Searching in: %p %d\n", CsrProcess, CsrProcess->ThreadCount);
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 /* Next entry */
271 NextEntry = NextEntry->Flink;
272 }
273
274 /* Return what we found */
275 // DPRINT1("Found: %p\n", FoundThread);
276 return FoundThread;
277 }
278
279 /*++
280 * @name CsrInsertThread
281 *
282 * The CsrInsertThread routine inserts a CSR Thread into its parent's
283 * Thread List and into the Thread Hash Table.
284 *
285 * @param Process
286 * Pointer to the CSR Process containing this CSR Thread.
287 *
288 * @param Thread
289 * Pointer to the CSR Thread to be inserted.
290 *
291 * @return None.
292 *
293 * @remarks None.
294 *
295 *--*/
296 VOID
297 NTAPI
298 CsrInsertThread(IN PCSR_PROCESS Process,
299 IN PCSR_THREAD Thread)
300 {
301 ULONG i;
302 // ASSERT(ProcessStructureListLocked());
303
304 /* Insert it into the Regular List */
305 InsertTailList(&Process->ThreadList, &Thread->Link);
306
307 /* Increase Thread Count */
308 Process->ThreadCount++;
309
310 /* Hash the Thread */
311 i = CsrHashThread(Thread->ClientId.UniqueThread);
312 // DPRINT1("TID %lx HASH: %lx\n", Thread->ClientId.UniqueThread, i);
313
314 /* Insert it there too */
315 InsertHeadList(&CsrThreadHashTable[i], &Thread->HashLinks);
316 }
317
318 /*++
319 * @name CsrDeallocateThread
320 *
321 * The CsrDeallocateThread frees the memory associated with a CSR Thread.
322 *
323 * @param CsrThread
324 * Pointer to the CSR Thread to be freed.
325 *
326 * @return None.
327 *
328 * @remarks Do not call this routine. It is reserved for the internal
329 * thread management routines when a CSR Thread has been cleanly
330 * dereferenced and killed.
331 *
332 *--*/
333 VOID
334 NTAPI
335 CsrDeallocateThread(IN PCSR_THREAD CsrThread)
336 {
337 /* Free the process object from the heap */
338 // ASSERT(CsrThread->WaitBlock == NULL);
339 RtlFreeHeap(CsrHeap, 0, CsrThread);
340 }
341
342 /*++
343 * @name CsrRemoveThread
344 *
345 * The CsrRemoveThread function undoes a CsrInsertThread operation and
346 * removes the CSR Thread from the the Hash Table and Thread List.
347 *
348 * @param CsrThread
349 * Pointer to the CSR Thread to remove.
350 *
351 * @return None.
352 *
353 * @remarks If this CSR Thread is the last one inside a CSR Process, the
354 * parent will be dereferenced and the CsrProcessLastThreadTerminated
355 * flag will be set.
356 *
357 * After executing this routine, the CSR Thread will have the
358 * CsrThreadInTermination flag set.
359 *
360 *--*/
361 VOID
362 NTAPI
363 CsrRemoveThread(IN PCSR_THREAD CsrThread)
364 {
365 ASSERT(ProcessStructureListLocked());
366
367 /* Remove it from the List */
368 RemoveEntryList(&CsrThread->Link);
369
370 /* Decreate the thread count of the process */
371 CsrThread->Process->ThreadCount--;
372
373 /* Remove it from the Hash List as well */
374 if (CsrThread->HashLinks.Flink) RemoveEntryList(&CsrThread->HashLinks);
375
376 /* Check if this is the last Thread */
377 if (!CsrThread->Process->ThreadCount)
378 {
379 /* Check if it's not already been marked for deletion */
380 if (!(CsrThread->Process->Flags & CsrProcessLastThreadTerminated))
381 {
382 /* Let everyone know this process is about to lose the thread */
383 CsrThread->Process->Flags |= CsrProcessLastThreadTerminated;
384
385 /* Reference the Process */
386 CsrLockedDereferenceProcess(CsrThread->Process);
387 }
388 }
389
390 /* Mark the thread for deletion */
391 CsrThread->Flags |= CsrThreadInTermination;
392 }
393
394 /*++
395 * @name CsrThreadRefcountZero
396 *
397 * The CsrThreadRefcountZero routine is executed when a CSR Thread has lost
398 * all its active references. It removes and de-allocates the CSR Thread.
399 *
400 * @param CsrThread
401 * Pointer to the CSR Thread that is to be deleted.
402 *
403 * @return None.
404 *
405 * @remarks Do not call this routine. It is reserved for the internal
406 * thread management routines when a CSR Thread has lost all
407 * its references.
408 *
409 * This routine is called with the Process Lock held.
410 *
411 *--*/
412 VOID
413 NTAPI
414 CsrThreadRefcountZero(IN PCSR_THREAD CsrThread)
415 {
416 PCSR_PROCESS CsrProcess = CsrThread->Process;
417 NTSTATUS Status;
418 ASSERT(ProcessStructureListLocked());
419
420 /* Remove this thread */
421 CsrRemoveThread(CsrThread);
422
423 /* Release the Process Lock */
424 CsrReleaseProcessLock();
425
426 /* Close the NT Thread Handle */
427 if (CsrThread->ThreadHandle)
428 {
429 UnProtectHandle(CsrThread->ThreadHandle);
430 Status = NtClose(CsrThread->ThreadHandle);
431 ASSERT(NT_SUCCESS(Status));
432 }
433
434 /* De-allocate the CSR Thread Object */
435 CsrDeallocateThread(CsrThread);
436
437 /* Remove a reference from the process */
438 CsrDereferenceProcess(CsrProcess);
439 }
440
441 /*++
442 * @name CsrLockedDereferenceThread
443 *
444 * The CsrLockedDereferenceThread dereferences a CSR Thread while the
445 * Process Lock is already being held.
446 *
447 * @param CsrThread
448 * Pointer to the CSR Thread to be dereferenced.
449 *
450 * @return None.
451 *
452 * @remarks This routine will return with the Process Lock held.
453 *
454 *--*/
455 VOID
456 NTAPI
457 CsrLockedDereferenceThread(IN PCSR_THREAD CsrThread)
458 {
459 LONG LockCount;
460
461 /* Decrease reference count */
462 LockCount = --CsrThread->ReferenceCount;
463 ASSERT(LockCount >= 0);
464 if (!LockCount)
465 {
466 /* Call the generic cleanup code */
467 CsrThreadRefcountZero(CsrThread);
468 CsrAcquireProcessLock();
469 }
470 }
471
472
473 /* PUBLIC FUNCTIONS ***********************************************************/
474
475 /*++
476 * @name CsrAddStaticServerThread
477 * @implemented NT4
478 *
479 * The CsrAddStaticServerThread routine adds a new CSR Thread to the
480 * CSR Server Process (CsrRootProcess).
481 *
482 * @param hThread
483 * Handle to an existing NT Thread to which to associate this
484 * CSR Thread.
485 *
486 * @param ClientId
487 * Pointer to the Client ID structure of the NT Thread to associate
488 * with this CSR Thread.
489 *
490 * @param ThreadFlags
491 * Initial CSR Thread Flags to associate to this CSR Thread. Usually
492 * CsrThreadIsServerThread.
493 *
494 * @return Pointer to the newly allocated CSR Thread.
495 *
496 * @remarks None.
497 *
498 *--*/
499 PCSR_THREAD
500 NTAPI
501 CsrAddStaticServerThread(IN HANDLE hThread,
502 IN PCLIENT_ID ClientId,
503 IN ULONG ThreadFlags)
504 {
505 PCSR_THREAD CsrThread;
506
507 /* Get the Lock */
508 CsrAcquireProcessLock();
509
510 /* Allocate the Server Thread */
511 CsrThread = CsrAllocateThread(CsrRootProcess);
512 if (CsrThread)
513 {
514 /* Setup the Object */
515 CsrThread->ThreadHandle = hThread;
516 ProtectHandle(hThread);
517 CsrThread->ClientId = *ClientId;
518 CsrThread->Flags = ThreadFlags;
519
520 /* Insert it into the Thread List */
521 InsertTailList(&CsrRootProcess->ThreadList, &CsrThread->Link);
522
523 /* Increment the thread count */
524 CsrRootProcess->ThreadCount++;
525 }
526 else
527 {
528 DPRINT1("CsrAddStaticServerThread: alloc failed for thread 0x%x\n", hThread);
529 }
530
531 /* Release the Process Lock and return */
532 CsrReleaseProcessLock();
533 return CsrThread;
534 }
535
536 /*++
537 * @name CsrCreateRemoteThread
538 * @implemented NT4
539 *
540 * The CsrCreateRemoteThread routine creates a CSR Thread object for
541 * an NT Thread which is not part of the current NT Process.
542 *
543 * @param hThread
544 * Handle to an existing NT Thread to which to associate this
545 * CSR Thread.
546 *
547 * @param ClientId
548 * Pointer to the Client ID structure of the NT Thread to associate
549 * with this CSR Thread.
550 *
551 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
552 * otherwise.
553 *
554 * @remarks None.
555 *
556 *--*/
557 NTSTATUS
558 NTAPI
559 CsrCreateRemoteThread(IN HANDLE hThread,
560 IN PCLIENT_ID ClientId)
561 {
562 NTSTATUS Status;
563 HANDLE ThreadHandle;
564 PCSR_THREAD CsrThread;
565 PCSR_PROCESS CsrProcess;
566 KERNEL_USER_TIMES KernelTimes;
567 DPRINT("CSRSRV: %s called\n", __FUNCTION__);
568
569 /* Get the Thread Create Time */
570 Status = NtQueryInformationThread(hThread,
571 ThreadTimes,
572 &KernelTimes,
573 sizeof(KernelTimes),
574 NULL);
575 if (!NT_SUCCESS(Status))
576 {
577 DPRINT1("Failed to query thread times: %lx\n", Status);
578 return Status;
579 }
580
581 /* Lock the Owner Process */
582 Status = CsrLockProcessByClientId(&ClientId->UniqueProcess, &CsrProcess);
583 if (!NT_SUCCESS(Status))
584 {
585 DPRINT1("No known process for %lx\n", ClientId->UniqueProcess);
586 return Status;
587 }
588
589 /* Make sure the thread didn't terminate */
590 if (KernelTimes.ExitTime.QuadPart)
591 {
592 /* Unlock the process and return */
593 CsrUnlockProcess(CsrProcess);
594 DPRINT1("Dead thread: %I64x\n", KernelTimes.ExitTime.QuadPart);
595 return STATUS_THREAD_IS_TERMINATING;
596 }
597
598 /* Allocate a CSR Thread Structure */
599 CsrThread = CsrAllocateThread(CsrProcess);
600 if (!CsrThread)
601 {
602 DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
603 CsrUnlockProcess(CsrProcess);
604 return STATUS_NO_MEMORY;
605 }
606
607 /* Duplicate the Thread Handle */
608 Status = NtDuplicateObject(NtCurrentProcess(),
609 hThread,
610 NtCurrentProcess(),
611 &ThreadHandle,
612 0,
613 0,
614 DUPLICATE_SAME_ACCESS);
615 /* Allow failure */
616 if (!NT_SUCCESS(Status))
617 {
618 DPRINT1("Thread duplication failed: %lx\n", Status);
619 ThreadHandle = hThread;
620 }
621
622 /* Save the data we have */
623 CsrThread->CreateTime = KernelTimes.CreateTime;
624 CsrThread->ClientId = *ClientId;
625 CsrThread->ThreadHandle = ThreadHandle;
626 ProtectHandle(ThreadHandle);
627 CsrThread->Flags = 0;
628
629 /* Insert the Thread into the Process */
630 CsrInsertThread(CsrProcess, CsrThread);
631
632 /* Release the lock and return */
633 CsrUnlockProcess(CsrProcess);
634 return STATUS_SUCCESS;
635 }
636
637 /*++
638 * @name CsrCreateThread
639 * @implemented NT4
640 *
641 * The CsrCreateThread routine creates a CSR Thread object for an NT Thread.
642 *
643 * @param CsrProcess
644 * Pointer to the CSR Process which will contain the CSR Thread.
645 *
646 * @param hThread
647 * Handle to an existing NT Thread to which to associate this
648 * CSR Thread.
649 *
650 * @param ClientId
651 * Pointer to the Client ID structure of the NT Thread to associate
652 * with this CSR Thread.
653 *
654 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
655 * otherwise.
656 *
657 * @remarks None.
658 *
659 *--*/
660 NTSTATUS
661 NTAPI
662 CsrCreateThread(IN PCSR_PROCESS CsrProcess,
663 IN HANDLE hThread,
664 IN PCLIENT_ID ClientId,
665 IN BOOLEAN HaveClient)
666 {
667 NTSTATUS Status;
668 PCSR_THREAD CsrThread, CurrentThread;
669 PCSR_PROCESS CurrentProcess;
670 CLIENT_ID CurrentCid;
671 KERNEL_USER_TIMES KernelTimes;
672
673 DPRINT("CSRSRV: %s called\n", __FUNCTION__);
674
675 if (HaveClient)
676 {
677 /* Get the current thread and CID */
678 CurrentThread = CsrGetClientThread();
679 CurrentCid = CurrentThread->ClientId;
680
681 /* Acquire the Process Lock */
682 CsrAcquireProcessLock();
683
684 /* Get the current Process and make sure the Thread is valid with this CID */
685 CurrentThread = CsrLocateThreadByClientId(&CurrentProcess, &CurrentCid);
686
687 /* Something is wrong if we get an empty thread back */
688 if (!CurrentThread)
689 {
690 DPRINT1("CSRSRV:%s: invalid thread!\n", __FUNCTION__);
691 CsrReleaseProcessLock();
692 return STATUS_THREAD_IS_TERMINATING;
693 }
694 }
695 else
696 {
697 /* Acquire the Process Lock */
698 CsrAcquireProcessLock();
699 }
700
701 /* Get the Thread Create Time */
702 Status = NtQueryInformationThread(hThread,
703 ThreadTimes,
704 (PVOID)&KernelTimes,
705 sizeof(KernelTimes),
706 NULL);
707 if (!NT_SUCCESS(Status))
708 {
709 CsrReleaseProcessLock();
710 return Status;
711 }
712
713 /* Allocate a CSR Thread Structure */
714 CsrThread = CsrAllocateThread(CsrProcess);
715 if (!CsrThread)
716 {
717 DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
718 CsrReleaseProcessLock();
719 return STATUS_NO_MEMORY;
720 }
721
722 /* Save the data we have */
723 CsrThread->CreateTime = KernelTimes.CreateTime;
724 CsrThread->ClientId = *ClientId;
725 CsrThread->ThreadHandle = hThread;
726 ProtectHandle(hThread);
727 CsrThread->Flags = 0;
728
729 /* Insert the Thread into the Process */
730 CsrInsertThread(CsrProcess, CsrThread);
731
732 /* Release the lock and return */
733 CsrReleaseProcessLock();
734
735 return STATUS_SUCCESS;
736 }
737
738 /*++
739 * @name CsrDereferenceThread
740 * @implemented NT4
741 *
742 * The CsrDereferenceThread routine removes a reference from a CSR Thread.
743 *
744 * @param CsrThread
745 * Pointer to the CSR Thread to dereference.
746 *
747 * @return None.
748 *
749 * @remarks If the reference count has reached zero (ie: the CSR Thread has
750 * no more active references), it will be deleted.
751 *
752 *--*/
753 VOID
754 NTAPI
755 CsrDereferenceThread(IN PCSR_THREAD CsrThread)
756 {
757 /* Acquire process lock */
758 CsrAcquireProcessLock();
759
760 /* Decrease reference count */
761 ASSERT(CsrThread->ReferenceCount > 0);
762 if (!(--CsrThread->ReferenceCount))
763 {
764 /* Call the generic cleanup code */
765 CsrThreadRefcountZero(CsrThread);
766 }
767 else
768 {
769 /* Just release the lock */
770 CsrReleaseProcessLock();
771 }
772 }
773
774 /*++
775 * @name CsrDestroyThread
776 * @implemented NT4
777 *
778 * The CsrDestroyThread routine destroys the CSR Thread corresponding to
779 * a given Thread ID.
780 *
781 * @param Cid
782 * Pointer to the Client ID Structure corresponding to the CSR
783 * Thread which is about to be destroyed.
784 *
785 * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
786 * if the CSR Thread is already terminating.
787 *
788 * @remarks None.
789 *
790 *--*/
791 NTSTATUS
792 NTAPI
793 CsrDestroyThread(IN PCLIENT_ID Cid)
794 {
795 CLIENT_ID ClientId = *Cid;
796 PCSR_THREAD CsrThread;
797 PCSR_PROCESS CsrProcess;
798
799 /* Acquire lock */
800 CsrAcquireProcessLock();
801
802 /* Find the thread */
803 CsrThread = CsrLocateThreadByClientId(&CsrProcess,
804 &ClientId);
805
806 /* Make sure we got one back, and that it's not already gone */
807 if (!CsrThread || CsrThread->Flags & CsrThreadTerminated)
808 {
809 /* Release the lock and return failure */
810 CsrReleaseProcessLock();
811 return STATUS_THREAD_IS_TERMINATING;
812 }
813
814 /* Set the terminated flag */
815 CsrThread->Flags |= CsrThreadTerminated;
816
817 /* Acquire the Wait Lock */
818 CsrAcquireWaitLock();
819
820 /* Do we have an active wait block? */
821 if (CsrThread->WaitBlock)
822 {
823 /* Notify waiters of termination */
824 CsrNotifyWaitBlock(CsrThread->WaitBlock,
825 NULL,
826 NULL,
827 NULL,
828 CsrProcessTerminating,
829 TRUE);
830 }
831
832 /* Release the Wait Lock */
833 CsrReleaseWaitLock();
834
835 /* Dereference the thread */
836 CsrLockedDereferenceThread(CsrThread);
837
838 /* Release the Process Lock and return success */
839 CsrReleaseProcessLock();
840 return STATUS_SUCCESS;
841 }
842
843 /*++
844 * @name CsrExecServerThread
845 * @implemented NT4
846 *
847 * The CsrExecServerThread routine creates an NT Thread and then
848 * initializes a CSR Thread for it.
849 *
850 * @param ThreadHandler
851 * Pointer to the thread's startup routine.
852 *
853 * @param Flags
854 * Initial CSR Thread Flags to set to the CSR Thread.
855 *
856 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
857 * otherwise.
858 *
859 * @remarks This routine is similar to CsrAddStaticServerThread, but it
860 * also creates an NT Thread instead of expecting one to already
861 * exist.
862 *
863 *--*/
864 NTSTATUS
865 NTAPI
866 CsrExecServerThread(IN PVOID ThreadHandler,
867 IN ULONG Flags)
868 {
869 PCSR_THREAD CsrThread;
870 HANDLE hThread;
871 CLIENT_ID ClientId;
872 NTSTATUS Status;
873
874 /* Acquire process lock */
875 CsrAcquireProcessLock();
876
877 /* Allocate a CSR Thread in the Root Process */
878 ASSERT(CsrRootProcess != NULL);
879 CsrThread = CsrAllocateThread(CsrRootProcess);
880 if (!CsrThread)
881 {
882 /* Fail */
883 CsrReleaseProcessLock();
884 return STATUS_NO_MEMORY;
885 }
886
887 /* Create the Thread */
888 Status = RtlCreateUserThread(NtCurrentProcess(),
889 NULL,
890 FALSE,
891 0,
892 0,
893 0,
894 ThreadHandler,
895 NULL,
896 &hThread,
897 &ClientId);
898 if (!NT_SUCCESS(Status))
899 {
900 /* Fail */
901 CsrDeallocateThread(CsrThread);
902 CsrReleaseProcessLock();
903 return Status;
904 }
905
906 /* Setup the Thread Object */
907 CsrThread->ThreadHandle = hThread;
908 ProtectHandle(hThread);
909 CsrThread->ClientId = ClientId;
910 CsrThread->Flags = Flags;
911
912 /* Insert it into the Thread List */
913 InsertHeadList(&CsrRootProcess->ThreadList, &CsrThread->Link);
914
915 /* Increase the thread count */
916 CsrRootProcess->ThreadCount++;
917
918 /* Return */
919 CsrReleaseProcessLock();
920 return Status;
921 }
922
923 /*++
924 * @name CsrLockThreadByClientId
925 * @implemented NT4
926 *
927 * The CsrLockThreadByClientId routine locks the CSR Thread corresponding
928 * to the given Thread ID and optionally returns it.
929 *
930 * @param Tid
931 * Thread ID corresponding to the CSR Thread which will be locked.
932 *
933 * @param CsrThread
934 * Optional pointer to a CSR Thread pointer which will hold the
935 * CSR Thread corresponding to the given Thread ID.
936 *
937 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
938 * otherwise.
939 *
940 * @remarks Locking a CSR Thread is defined as acquiring an extra
941 * reference to it and returning with the Process Lock held.
942 *
943 *--*/
944 NTSTATUS
945 NTAPI
946 CsrLockThreadByClientId(IN HANDLE Tid,
947 OUT PCSR_THREAD *CsrThread)
948 {
949 PLIST_ENTRY NextEntry;
950 PCSR_THREAD CurrentThread = NULL;
951 NTSTATUS Status = STATUS_UNSUCCESSFUL;
952 ULONG i;
953
954 /* Acquire the lock */
955 CsrAcquireProcessLock();
956
957 /* Assume failure */
958 ASSERT(CsrThread != NULL);
959 *CsrThread = NULL;
960
961 /* Convert to Hash */
962 i = CsrHashThread(Tid);
963
964 /* Setup the List Pointers */
965 NextEntry = CsrThreadHashTable[i].Flink;
966
967 /* Start Loop */
968 while (NextEntry != &CsrThreadHashTable[i])
969 {
970 /* Get the Process */
971 CurrentThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
972
973 /* Check for PID Match */
974 if ((CurrentThread->ClientId.UniqueThread == Tid) &&
975 !(CurrentThread->Flags & CsrThreadTerminated))
976 {
977 /* Get out of here */
978 break;
979 }
980
981 /* Next entry */
982 NextEntry = NextEntry->Flink;
983 }
984
985 /* Nothing found if we got back to the list */
986 if (NextEntry == &CsrThreadHashTable[i]) CurrentThread = NULL;
987
988 /* Did the loop find something? */
989 if (CurrentThread)
990 {
991 /* Reference the found thread */
992 Status = STATUS_SUCCESS;
993 CurrentThread->ReferenceCount++;
994 *CsrThread = CurrentThread;
995 }
996 else
997 {
998 /* Nothing found, release the lock */
999 Status = STATUS_UNSUCCESSFUL;
1000 CsrReleaseProcessLock();
1001 }
1002
1003 /* Return the status */
1004 return Status;
1005 }
1006
1007 /*++
1008 * @name CsrReferenceThread
1009 * @implemented NT4
1010 *
1011 * The CsrReferenceThread routine increases the active reference count of
1012 * a CSR Thread.
1013 *
1014 * @param CsrThread
1015 * Pointer to the CSR Thread whose reference count will be increased.
1016 *
1017 * @return None.
1018 *
1019 * @remarks Do not use this routine if the Process Lock is already held.
1020 *
1021 *--*/
1022 VOID
1023 NTAPI
1024 CsrReferenceThread(IN PCSR_THREAD CsrThread)
1025 {
1026 /* Acquire process lock */
1027 CsrAcquireProcessLock();
1028
1029 /* Sanity checks */
1030 ASSERT(CsrThread->Flags & CsrThreadTerminated); // CSR_THREAD_DESTROYED in ASSERT
1031 ASSERT(CsrThread->ReferenceCount != 0);
1032
1033 /* Increment reference count */
1034 CsrThread->ReferenceCount++;
1035
1036 /* Release the lock */
1037 CsrReleaseProcessLock();
1038 }
1039
1040 /*++
1041 * @name CsrUnlockThread
1042 * @implemented NT4
1043 *
1044 * The CsrUnlockThread undoes a previous CsrLockThreadByClientId operation.
1045 *
1046 * @param CsrThread
1047 * Pointer to a previously locked CSR Thread.
1048 *
1049 * @return STATUS_SUCCESS.
1050 *
1051 * @remarks This routine must be called with the Process Lock held.
1052 *
1053 *--*/
1054 NTSTATUS
1055 NTAPI
1056 CsrUnlockThread(IN PCSR_THREAD CsrThread)
1057 {
1058 /* Dereference the Thread */
1059 ASSERT(ProcessStructureListLocked());
1060 CsrLockedDereferenceThread(CsrThread);
1061
1062 /* Release the lock and return */
1063 CsrReleaseProcessLock();
1064 return STATUS_SUCCESS;
1065 }
1066
1067 /* EOF */