Synchronize with trunk's revision r57629.
[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 #if 0
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 DPRINT("CSRSRV: %s called\n", __FUNCTION__);
674
675 if (HaveClient)
676 {
677 /* Get the current thread and CID */
678 CurrentThread = NtCurrentTeb()->CsrClientThread;
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 if (!CurrentThread)
687 {
688 DPRINT1("CSRSRV:%s: invalid thread!\n", __FUNCTION__);
689 CsrReleaseProcessLock();
690 return STATUS_THREAD_IS_TERMINATING;
691 }
692 }
693 else
694 {
695 /* Acquire the Process Lock */
696 CsrAcquireProcessLock();
697 }
698
699 /* Get the Thread Create Time */
700 Status = NtQueryInformationThread(hThread,
701 ThreadTimes,
702 (PVOID)&KernelTimes,
703 sizeof(KernelTimes),
704 NULL);
705 if (!NT_SUCCESS(Status))
706 {
707 CsrReleaseProcessLock();
708 return Status;
709 }
710
711 /* Allocate a CSR Thread Structure */
712 CsrThread = CsrAllocateThread(CsrProcess);
713 if (!CsrThread)
714 {
715 DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
716 CsrReleaseProcessLock();
717 return STATUS_NO_MEMORY;
718 }
719
720 /* Save the data we have */
721 CsrThread->CreateTime = KernelTimes.CreateTime;
722 CsrThread->ClientId = *ClientId;
723 CsrThread->ThreadHandle = hThread;
724 ProtectHandle(hThread);
725 CsrThread->Flags = 0;
726
727 /* Insert the Thread into the Process */
728 CsrInsertThread(CsrProcess, CsrThread);
729
730 /* Release the lock and return */
731 CsrReleaseProcessLock();
732 return STATUS_SUCCESS;
733 }
734 #else
735 CsrCreateThread(IN PCSR_PROCESS CsrProcess,
736 IN HANDLE hThread,
737 IN PCLIENT_ID ClientId)
738 {
739 PCSR_THREAD CsrThread;
740 PCSR_PROCESS CurrentProcess;
741 PCSR_THREAD CurrentThread = CsrGetClientThread();
742 CLIENT_ID CurrentCid;
743 KERNEL_USER_TIMES KernelTimes;
744
745 /* Get the current thread and CID */
746 CurrentCid = CurrentThread->ClientId;
747
748 /* Acquire the Process Lock */
749 CsrAcquireProcessLock();
750
751 /* Get the current Process and make sure the Thread is valid with this CID */
752 CurrentThread = CsrLocateThreadByClientId(&CurrentProcess,
753 &CurrentCid);
754
755 /* Something is wrong if we get an empty thread back */
756 if (!CurrentThread)
757 {
758 DPRINT1("CSRSRV:%s: invalid thread!\n", __FUNCTION__);
759 CsrReleaseProcessLock();
760 return STATUS_THREAD_IS_TERMINATING;
761 }
762
763 /* Get the Thread Create Time */
764 NtQueryInformationThread(hThread,
765 ThreadTimes,
766 (PVOID)&KernelTimes,
767 sizeof(KernelTimes),
768 NULL);
769
770 /* Allocate a CSR Thread Structure */
771 if (!(CsrThread = CsrAllocateThread(CsrProcess)))
772 {
773 DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
774 CsrReleaseProcessLock();
775 return STATUS_NO_MEMORY;
776 }
777
778 /* Save the data we have */
779 CsrThread->CreateTime = KernelTimes.CreateTime;
780 CsrThread->ClientId = *ClientId;
781 CsrThread->ThreadHandle = hThread;
782 CsrThread->Flags = 0;
783
784 /* Insert the Thread into the Process */
785 CsrInsertThread(CsrProcess, CsrThread);
786
787 /* Release the lock and return */
788 CsrReleaseProcessLock();
789 return STATUS_SUCCESS;
790 }
791 #endif
792
793 /*++
794 * @name CsrDereferenceThread
795 * @implemented NT4
796 *
797 * The CsrDereferenceThread routine removes a reference from a CSR Thread.
798 *
799 * @param CsrThread
800 * Pointer to the CSR Thread to dereference.
801 *
802 * @return None.
803 *
804 * @remarks If the reference count has reached zero (ie: the CSR Thread has
805 * no more active references), it will be deleted.
806 *
807 *--*/
808 VOID
809 NTAPI
810 CsrDereferenceThread(IN PCSR_THREAD CsrThread)
811 {
812 /* Acquire process lock */
813 CsrAcquireProcessLock();
814
815 /* Decrease reference count */
816 ASSERT(CsrThread->ReferenceCount > 0);
817 if (!(--CsrThread->ReferenceCount))
818 {
819 /* Call the generic cleanup code */
820 CsrThreadRefcountZero(CsrThread);
821 }
822 else
823 {
824 /* Just release the lock */
825 CsrReleaseProcessLock();
826 }
827 }
828
829 /*++
830 * @name CsrDestroyThread
831 * @implemented NT4
832 *
833 * The CsrDestroyThread routine destroys the CSR Thread corresponding to
834 * a given Thread ID.
835 *
836 * @param Cid
837 * Pointer to the Client ID Structure corresponding to the CSR
838 * Thread which is about to be destroyed.
839 *
840 * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
841 * if the CSR Thread is already terminating.
842 *
843 * @remarks None.
844 *
845 *--*/
846 NTSTATUS
847 NTAPI
848 CsrDestroyThread(IN PCLIENT_ID Cid)
849 {
850 CLIENT_ID ClientId = *Cid;
851 PCSR_THREAD CsrThread;
852 PCSR_PROCESS CsrProcess;
853
854 /* Acquire lock */
855 CsrAcquireProcessLock();
856
857 /* Find the thread */
858 CsrThread = CsrLocateThreadByClientId(&CsrProcess,
859 &ClientId);
860
861 /* Make sure we got one back, and that it's not already gone */
862 if (!CsrThread || CsrThread->Flags & CsrThreadTerminated)
863 {
864 /* Release the lock and return failure */
865 CsrReleaseProcessLock();
866 return STATUS_THREAD_IS_TERMINATING;
867 }
868
869 /* Set the terminated flag */
870 CsrThread->Flags |= CsrThreadTerminated;
871
872 /* Acquire the Wait Lock */
873 CsrAcquireWaitLock();
874
875 /* Do we have an active wait block? */
876 if (CsrThread->WaitBlock)
877 {
878 /* Notify waiters of termination */
879 CsrNotifyWaitBlock(CsrThread->WaitBlock,
880 NULL,
881 NULL,
882 NULL,
883 CsrProcessTerminating,
884 TRUE);
885 }
886
887 /* Release the Wait Lock */
888 CsrReleaseWaitLock();
889
890 /* Dereference the thread */
891 CsrLockedDereferenceThread(CsrThread);
892
893 /* Release the Process Lock and return success */
894 CsrReleaseProcessLock();
895 return STATUS_SUCCESS;
896 }
897
898 /*++
899 * @name CsrExecServerThread
900 * @implemented NT4
901 *
902 * The CsrExecServerThread routine creates an NT Thread and then
903 * initializes a CSR Thread for it.
904 *
905 * @param ThreadHandler
906 * Pointer to the thread's startup routine.
907 *
908 * @param Flags
909 * Initial CSR Thread Flags to set to the CSR Thread.
910 *
911 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
912 * otherwise.
913 *
914 * @remarks This routine is similar to CsrAddStaticServerThread, but it
915 * also creates an NT Thread instead of expecting one to already
916 * exist.
917 *
918 *--*/
919 NTSTATUS
920 NTAPI
921 CsrExecServerThread(IN PVOID ThreadHandler,
922 IN ULONG Flags)
923 {
924 PCSR_THREAD CsrThread;
925 HANDLE hThread;
926 CLIENT_ID ClientId;
927 NTSTATUS Status;
928
929 /* Acquire process lock */
930 CsrAcquireProcessLock();
931
932 /* Allocate a CSR Thread in the Root Process */
933 ASSERT(CsrRootProcess != NULL);
934 CsrThread = CsrAllocateThread(CsrRootProcess);
935 if (!CsrThread)
936 {
937 /* Fail */
938 CsrReleaseProcessLock();
939 return STATUS_NO_MEMORY;
940 }
941
942 /* Create the Thread */
943 Status = RtlCreateUserThread(NtCurrentProcess(),
944 NULL,
945 FALSE,
946 0,
947 0,
948 0,
949 ThreadHandler,
950 NULL,
951 &hThread,
952 &ClientId);
953 if (!NT_SUCCESS(Status))
954 {
955 /* Fail */
956 CsrDeallocateThread(CsrThread);
957 CsrReleaseProcessLock();
958 return Status;
959 }
960
961 /* Setup the Thread Object */
962 CsrThread->ThreadHandle = hThread;
963 ProtectHandle(hThread);
964 CsrThread->ClientId = ClientId;
965 CsrThread->Flags = Flags;
966
967 /* Insert it into the Thread List */
968 InsertHeadList(&CsrRootProcess->ThreadList, &CsrThread->Link);
969
970 /* Increase the thread count */
971 CsrRootProcess->ThreadCount++;
972
973 /* Return */
974 CsrReleaseProcessLock();
975 return Status;
976 }
977
978 /*++
979 * @name CsrLockThreadByClientId
980 * @implemented NT4
981 *
982 * The CsrLockThreadByClientId routine locks the CSR Thread corresponding
983 * to the given Thread ID and optionally returns it.
984 *
985 * @param Tid
986 * Thread ID corresponding to the CSR Thread which will be locked.
987 *
988 * @param CsrThread
989 * Optional pointer to a CSR Thread pointer which will hold the
990 * CSR Thread corresponding to the given Thread ID.
991 *
992 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
993 * otherwise.
994 *
995 * @remarks Locking a CSR Thread is defined as acquiring an extra
996 * reference to it and returning with the Process Lock held.
997 *
998 *--*/
999 NTSTATUS
1000 NTAPI
1001 CsrLockThreadByClientId(IN HANDLE Tid,
1002 OUT PCSR_THREAD *CsrThread)
1003 {
1004 PLIST_ENTRY NextEntry;
1005 PCSR_THREAD CurrentThread = NULL;
1006 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1007 ULONG i;
1008
1009 /* Acquire the lock */
1010 CsrAcquireProcessLock();
1011
1012 /* Assume failure */
1013 ASSERT(CsrThread != NULL);
1014 *CsrThread = NULL;
1015
1016 /* Convert to Hash */
1017 i = CsrHashThread(Tid);
1018
1019 /* Setup the List Pointers */
1020 NextEntry = CsrThreadHashTable[i].Flink;
1021
1022 /* Start Loop */
1023 while (NextEntry != &CsrThreadHashTable[i])
1024 {
1025 /* Get the Process */
1026 CurrentThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
1027
1028 /* Check for PID Match */
1029 if ((CurrentThread->ClientId.UniqueThread == Tid) &&
1030 !(CurrentThread->Flags & CsrThreadTerminated))
1031 {
1032 /* Get out of here */
1033 break;
1034 }
1035
1036 /* Next entry */
1037 NextEntry = NextEntry->Flink;
1038 }
1039
1040 /* Nothing found if we got back to the list */
1041 if (NextEntry == &CsrThreadHashTable[i]) CurrentThread = NULL;
1042
1043 /* Did the loop find something? */
1044 if (CurrentThread)
1045 {
1046 /* Reference the found thread */
1047 Status = STATUS_SUCCESS;
1048 CurrentThread->ReferenceCount++;
1049 *CsrThread = CurrentThread;
1050 }
1051 else
1052 {
1053 /* Nothing found, release the lock */
1054 Status = STATUS_UNSUCCESSFUL;
1055 CsrReleaseProcessLock();
1056 }
1057
1058 /* Return the status */
1059 return Status;
1060 }
1061
1062 /*++
1063 * @name CsrReferenceThread
1064 * @implemented NT4
1065 *
1066 * The CsrReferenceThread routine increases the active reference count of
1067 * a CSR Thread.
1068 *
1069 * @param CsrThread
1070 * Pointer to the CSR Thread whose reference count will be increased.
1071 *
1072 * @return None.
1073 *
1074 * @remarks Do not use this routine if the Process Lock is already held.
1075 *
1076 *--*/
1077 VOID
1078 NTAPI
1079 CsrReferenceThread(IN PCSR_THREAD CsrThread)
1080 {
1081 /* Acquire process lock */
1082 CsrAcquireProcessLock();
1083
1084 /* Sanity checks */
1085 ASSERT(CsrThread->Flags & CsrThreadTerminated); // CSR_THREAD_DESTROYED in ASSERT
1086 ASSERT(CsrThread->ReferenceCount != 0);
1087
1088 /* Increment reference count */
1089 CsrThread->ReferenceCount++;
1090
1091 /* Release the lock */
1092 CsrReleaseProcessLock();
1093 }
1094
1095 /*++
1096 * @name CsrUnlockThread
1097 * @implemented NT4
1098 *
1099 * The CsrUnlockThread undoes a previous CsrLockThreadByClientId operation.
1100 *
1101 * @param CsrThread
1102 * Pointer to a previously locked CSR Thread.
1103 *
1104 * @return STATUS_SUCCESS.
1105 *
1106 * @remarks This routine must be called with the Process Lock held.
1107 *
1108 *--*/
1109 NTSTATUS
1110 NTAPI
1111 CsrUnlockThread(IN PCSR_THREAD CsrThread)
1112 {
1113 /* Dereference the Thread */
1114 ASSERT(ProcessStructureListLocked());
1115 CsrLockedDereferenceThread(CsrThread);
1116
1117 /* Release the lock and return */
1118 CsrReleaseProcessLock();
1119 return STATUS_SUCCESS;
1120 }
1121
1122 /* EOF */