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