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