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