Reimplemented dispatcher database lock and synchronization primitives.
[reactos.git] / reactos / ntoskrnl / ps / thread.c
1 /* $Id: thread.c,v 1.121 2003/11/02 01:16:21 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/thread.c
6 * PURPOSE: Thread managment
7 * PROGRAMMER: David Welch (welch@mcmail.com)
8 * REVISION HISTORY:
9 * 23/06/98: Created
10 * 12/10/99: Phillip Susi: Thread priorities, and APC work
11 */
12
13 /*
14 * NOTE:
15 *
16 * All of the routines that manipulate the thread queue synchronize on
17 * a single spinlock
18 *
19 */
20
21 /* INCLUDES ****************************************************************/
22
23 #include <ddk/ntddk.h>
24 #include <internal/ke.h>
25 #include <internal/ob.h>
26 #include <internal/ps.h>
27 #include <internal/ob.h>
28 #include <internal/pool.h>
29 #include <ntos/minmax.h>
30 #include <internal/ldr.h>
31
32 #define NDEBUG
33 #include <internal/debug.h>
34
35 /* TYPES *******************************************************************/
36
37 /* GLOBALS ******************************************************************/
38
39 POBJECT_TYPE EXPORTED PsThreadType = NULL;
40
41 KSPIN_LOCK PiThreadListLock;
42
43 /*
44 * PURPOSE: List of threads associated with each priority level
45 */
46 LIST_ENTRY PiThreadListHead;
47 static LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY];
48 static ULONG PriorityListMask = 0;
49 static BOOLEAN DoneInitYet = FALSE;
50 static PETHREAD IdleThreads[MAXIMUM_PROCESSORS];
51 ULONG PiNrThreads = 0;
52 ULONG PiNrReadyThreads = 0;
53 static HANDLE PiReaperThreadHandle;
54 static KEVENT PiReaperThreadEvent;
55 static BOOLEAN PiReaperThreadShouldTerminate = FALSE;
56 ULONG PiNrThreadsAwaitingReaping = 0;
57
58 static GENERIC_MAPPING PiThreadMapping = {THREAD_READ,
59 THREAD_WRITE,
60 THREAD_EXECUTE,
61 THREAD_ALL_ACCESS};
62
63 /* FUNCTIONS ***************************************************************/
64
65 /*
66 * @implemented
67 */
68 PKTHREAD STDCALL KeGetCurrentThread(VOID)
69 {
70 return(((PIKPCR) KeGetCurrentKPCR())->CurrentThread);
71 }
72
73 /*
74 * @implemented
75 */
76 HANDLE STDCALL PsGetCurrentThreadId(VOID)
77 {
78 return(PsGetCurrentThread()->Cid.UniqueThread);
79 }
80
81 static VOID
82 PsInsertIntoThreadList(KPRIORITY Priority, PETHREAD Thread)
83 {
84 assert(THREAD_STATE_READY == Thread->Tcb.State);
85 if (Priority >= MAXIMUM_PRIORITY || Priority < LOW_PRIORITY)
86 {
87 DPRINT1("Invalid thread priority (%d)\n", Priority);
88 KEBUGCHECK(0);
89 }
90 InsertTailList(&PriorityListHead[Priority], &Thread->Tcb.QueueListEntry);
91 PriorityListMask |= (1 << Priority);
92 PiNrReadyThreads++;
93 }
94
95 static VOID PsRemoveFromThreadList(PETHREAD Thread)
96 {
97 assert(THREAD_STATE_READY == Thread->Tcb.State);
98 RemoveEntryList(&Thread->Tcb.QueueListEntry);
99 if (IsListEmpty(&PriorityListHead[(ULONG)Thread->Tcb.Priority]))
100 {
101 PriorityListMask &= ~(1 << Thread->Tcb.Priority);
102 }
103 PiNrReadyThreads--;
104 }
105
106
107 VOID PsDumpThreads(BOOLEAN IncludeSystem)
108 {
109 PLIST_ENTRY current_entry;
110 PETHREAD current;
111 ULONG t;
112 ULONG i;
113
114 current_entry = PiThreadListHead.Flink;
115 t = 0;
116
117 while (current_entry != &PiThreadListHead)
118 {
119 PULONG Ebp;
120 PULONG Esp;
121
122 current = CONTAINING_RECORD(current_entry, ETHREAD,
123 Tcb.ThreadListEntry);
124 t++;
125 if (t > PiNrThreads)
126 {
127 DbgPrint("Too many threads on list\n");
128 return;
129 }
130 if (IncludeSystem || current->ThreadsProcess->UniqueProcessId >= 6)
131 {
132 DbgPrint("current->Tcb.State %d PID.TID %d.%d Name %.8s Stack: \n",
133 current->Tcb.State,
134 current->ThreadsProcess->UniqueProcessId,
135 current->Cid.UniqueThread,
136 current->ThreadsProcess->ImageFileName);
137 if (current->Tcb.State == THREAD_STATE_READY ||
138 current->Tcb.State == THREAD_STATE_SUSPENDED ||
139 current->Tcb.State == THREAD_STATE_BLOCKED)
140 {
141 Esp = (PULONG)current->Tcb.KernelStack;
142 Ebp = (PULONG)Esp[3];
143 DbgPrint("Ebp 0x%.8X\n", Ebp);
144 i = 0;
145 while (Ebp != 0 && Ebp >= (PULONG)current->Tcb.StackLimit)
146 {
147 DbgPrint("%.8X %.8X%s", Ebp[0], Ebp[1],
148 (i % 8) == 7 ? "\n" : " ");
149 Ebp = (PULONG)Ebp[0];
150 i++;
151 }
152 if ((i % 8) != 7)
153 {
154 DbgPrint("\n");
155 }
156 }
157 }
158 current_entry = current_entry->Flink;
159 }
160 }
161
162 static PETHREAD PsScanThreadList (KPRIORITY Priority, ULONG Affinity)
163 {
164 PLIST_ENTRY current_entry;
165 PETHREAD current;
166 ULONG Mask;
167
168 Mask = (1 << Priority);
169 if (PriorityListMask & Mask)
170 {
171 current_entry = PriorityListHead[Priority].Flink;
172 while (current_entry != &PriorityListHead[Priority])
173 {
174 current = CONTAINING_RECORD(current_entry, ETHREAD,
175 Tcb.QueueListEntry);
176 if (current->Tcb.State != THREAD_STATE_READY)
177 {
178 DPRINT1("%d/%d\n", current->Cid.UniqueThread, current->Tcb.State);
179 }
180 assert(current->Tcb.State == THREAD_STATE_READY);
181 DPRINT("current->Tcb.UserAffinity %x Affinity %x PID %d %d\n",
182 current->Tcb.UserAffinity, Affinity, current->Cid.UniqueThread,
183 Priority);
184 if (current->Tcb.UserAffinity & Affinity)
185 {
186 PsRemoveFromThreadList(current);
187 return(current);
188 }
189 current_entry = current_entry->Flink;
190 }
191 }
192 return(NULL);
193 }
194
195 VOID STDCALL
196 PiWakeupReaperThread(VOID)
197 {
198 KeSetEvent(&PiReaperThreadEvent, 0, FALSE);
199 }
200
201 NTSTATUS STDCALL
202 PiReaperThreadMain(PVOID Ignored)
203 {
204 while (1)
205 {
206 KeWaitForSingleObject(&PiReaperThreadEvent,
207 Executive,
208 KernelMode,
209 FALSE,
210 NULL);
211 if (PiReaperThreadShouldTerminate)
212 {
213 PsTerminateSystemThread(0);
214 }
215 PsReapThreads();
216 }
217 }
218
219 VOID PsDispatchThreadNoLock (ULONG NewThreadStatus)
220 {
221 KPRIORITY CurrentPriority;
222 PETHREAD Candidate;
223 ULONG Affinity;
224 PKTHREAD KCurrentThread = ((PIKPCR) KeGetCurrentKPCR())->CurrentThread;
225 PETHREAD CurrentThread = CONTAINING_RECORD(KCurrentThread, ETHREAD, Tcb);
226
227 DPRINT("PsDispatchThread() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(),
228 CurrentThread->Cid.UniqueThread, NewThreadStatus, CurrentThread->Tcb.State);
229
230 CurrentThread->Tcb.State = NewThreadStatus;
231 if (CurrentThread->Tcb.State == THREAD_STATE_READY)
232 {
233 PsInsertIntoThreadList(CurrentThread->Tcb.Priority,
234 CurrentThread);
235 }
236 if (CurrentThread->Tcb.State == THREAD_STATE_TERMINATED_1)
237 {
238 PiNrThreadsAwaitingReaping++;
239 }
240
241 Affinity = 1 << KeGetCurrentProcessorNumber();
242 for (CurrentPriority = HIGH_PRIORITY;
243 CurrentPriority >= LOW_PRIORITY;
244 CurrentPriority--)
245 {
246 Candidate = PsScanThreadList(CurrentPriority, Affinity);
247 if (Candidate == CurrentThread)
248 {
249 Candidate->Tcb.State = THREAD_STATE_RUNNING;
250 KeReleaseSpinLockFromDpcLevel(&PiThreadListLock);
251 return;
252 }
253 if (Candidate != NULL)
254 {
255 PETHREAD OldThread;
256
257 DPRINT("Scheduling %x(%d)\n",Candidate, CurrentPriority);
258
259 Candidate->Tcb.State = THREAD_STATE_RUNNING;
260
261 OldThread = CurrentThread;
262 CurrentThread = Candidate;
263 #if 0
264 /*
265 * This code is moved to the end of KiArchContextSwitch.
266 * It should be execute after the context switch.
267 */
268 KeReleaseSpinLockFromDpcLevel(&PiThreadListLock);
269 if (PiNrThreadsAwaitingReaping > 0)
270 {
271 PiWakeupReaperThread();
272 }
273 #endif
274 KiArchContextSwitch(&CurrentThread->Tcb, &OldThread->Tcb);
275 return;
276 }
277 }
278 CPRINT("CRITICAL: No threads are ready\n");
279 KEBUGCHECK(0);
280 }
281
282 VOID STDCALL
283 PsDispatchThread(ULONG NewThreadStatus)
284 {
285 KIRQL oldIrql;
286
287 if (!DoneInitYet)
288 {
289 return;
290 }
291
292 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
293 /*
294 * Save wait IRQL
295 */
296 ((PIKPCR) KeGetCurrentKPCR())->CurrentThread->WaitIrql = oldIrql;
297 PsDispatchThreadNoLock(NewThreadStatus);
298 KeLowerIrql(oldIrql);
299 }
300
301 VOID
302 PsUnblockThread(PETHREAD Thread, PNTSTATUS WaitStatus)
303 {
304 KIRQL oldIrql;
305
306 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
307 if (THREAD_STATE_TERMINATED_1 == Thread->Tcb.State ||
308 THREAD_STATE_TERMINATED_2 == Thread->Tcb.State)
309 {
310 DPRINT("Can't unblock thread %d because it's terminating\n",
311 Thread->Cid.UniqueThread);
312 }
313 else if (THREAD_STATE_READY == Thread->Tcb.State ||
314 THREAD_STATE_RUNNING == Thread->Tcb.State)
315 {
316 DPRINT("Can't unblock thread %d because it's ready or running\n",
317 Thread->Cid.UniqueThread);
318 }
319 else
320 {
321 if (WaitStatus != NULL)
322 {
323 Thread->Tcb.WaitStatus = *WaitStatus;
324 }
325 Thread->Tcb.State = THREAD_STATE_READY;
326 PsInsertIntoThreadList(Thread->Tcb.Priority, Thread);
327 }
328 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
329 }
330
331 VOID
332 PsBlockThread(PNTSTATUS Status, UCHAR Alertable, ULONG WaitMode,
333 BOOLEAN DispatcherLock, KIRQL WaitIrql, UCHAR WaitReason)
334 {
335 KIRQL oldIrql;
336 PKTHREAD KThread;
337 PETHREAD Thread;
338 PKWAIT_BLOCK WaitBlock;
339
340 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
341
342 KThread = ((PIKPCR) KeGetCurrentKPCR())->CurrentThread;
343 Thread = CONTAINING_RECORD (KThread, ETHREAD, Tcb);
344 if (KThread->ApcState.KernelApcPending)
345 {
346 if (!DispatcherLock)
347 {
348 KeAcquireDispatcherDatabaseLockAtDpcLevel();
349 }
350 WaitBlock = (PKWAIT_BLOCK)Thread->Tcb.WaitBlockList;
351 while (WaitBlock)
352 {
353 RemoveEntryList (&WaitBlock->WaitListEntry);
354 WaitBlock = WaitBlock->NextWaitBlock;
355 }
356 Thread->Tcb.WaitBlockList = NULL;
357 KeReleaseDispatcherDatabaseLockFromDpcLevel();
358 PsDispatchThreadNoLock (THREAD_STATE_READY);
359 if (Status != NULL)
360 {
361 *Status = STATUS_KERNEL_APC;
362 }
363 }
364 else
365 {
366 if (DispatcherLock)
367 {
368 KeReleaseDispatcherDatabaseLockFromDpcLevel();
369 }
370 Thread->Tcb.Alertable = Alertable;
371 Thread->Tcb.WaitMode = WaitMode;
372 Thread->Tcb.WaitIrql = WaitIrql;
373 Thread->Tcb.WaitReason = WaitReason;
374 PsDispatchThreadNoLock(THREAD_STATE_BLOCKED);
375
376 if (Status != NULL)
377 {
378 *Status = Thread->Tcb.WaitStatus;
379 }
380 }
381 KeLowerIrql(WaitIrql);
382 }
383
384 VOID
385 PsFreezeAllThreads(PEPROCESS Process)
386 /*
387 * Used by the debugging code to freeze all the process's threads
388 * while the debugger is examining their state.
389 */
390 {
391 KIRQL oldIrql;
392 PLIST_ENTRY current_entry;
393 PETHREAD current;
394
395 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
396
397 current_entry = Process->ThreadListHead.Flink;
398 while (current_entry != &Process->ThreadListHead)
399 {
400 current = CONTAINING_RECORD(current_entry, ETHREAD,
401 Tcb.ProcessThreadListEntry);
402
403 /*
404 * We have to be careful here, we can't just set the freeze the
405 * thread inside kernel mode since it may be holding a lock.
406 */
407
408 current_entry = current_entry->Flink;
409 }
410
411 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
412 }
413
414 VOID
415 PsApplicationProcessorInit(VOID)
416 {
417 ((PIKPCR) KeGetCurrentKPCR())->CurrentThread =
418 (PVOID)IdleThreads[KeGetCurrentProcessorNumber()];
419 }
420
421 VOID INIT_FUNCTION
422 PsPrepareForApplicationProcessorInit(ULONG Id)
423 {
424 PETHREAD IdleThread;
425 HANDLE IdleThreadHandle;
426
427 PsInitializeThread(NULL,
428 &IdleThread,
429 &IdleThreadHandle,
430 THREAD_ALL_ACCESS,
431 NULL,
432 TRUE);
433 IdleThread->Tcb.State = THREAD_STATE_RUNNING;
434 IdleThread->Tcb.FreezeCount = 0;
435 IdleThread->Tcb.UserAffinity = 1 << Id;
436 IdleThread->Tcb.Priority = LOW_PRIORITY;
437 IdleThreads[Id] = IdleThread;
438
439 NtClose(IdleThreadHandle);
440 DPRINT("IdleThread for Processor %d has PID %d\n",
441 Id, IdleThread->Cid.UniqueThread);
442 }
443
444 VOID INIT_FUNCTION
445 PsInitThreadManagment(VOID)
446 /*
447 * FUNCTION: Initialize thread managment
448 */
449 {
450 PETHREAD FirstThread;
451 ULONG i;
452 HANDLE FirstThreadHandle;
453 NTSTATUS Status;
454
455 KeInitializeSpinLock(&PiThreadListLock);
456 for (i=0; i < MAXIMUM_PRIORITY; i++)
457 {
458 InitializeListHead(&PriorityListHead[i]);
459 }
460
461 InitializeListHead(&PiThreadListHead);
462
463 PsThreadType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
464
465 PsThreadType->Tag = TAG('T', 'H', 'R', 'T');
466 PsThreadType->TotalObjects = 0;
467 PsThreadType->TotalHandles = 0;
468 PsThreadType->MaxObjects = 0;
469 PsThreadType->MaxHandles = 0;
470 PsThreadType->PagedPoolCharge = 0;
471 PsThreadType->NonpagedPoolCharge = sizeof(ETHREAD);
472 PsThreadType->Mapping = &PiThreadMapping;
473 PsThreadType->Dump = NULL;
474 PsThreadType->Open = NULL;
475 PsThreadType->Close = NULL;
476 PsThreadType->Delete = PiDeleteThread;
477 PsThreadType->Parse = NULL;
478 PsThreadType->Security = NULL;
479 PsThreadType->QueryName = NULL;
480 PsThreadType->OkayToClose = NULL;
481 PsThreadType->Create = NULL;
482 PsThreadType->DuplicationNotify = NULL;
483
484 RtlInitUnicodeStringFromLiteral(&PsThreadType->TypeName, L"Thread");
485
486 ObpCreateTypeObject(PsThreadType);
487
488 PsInitializeThread(NULL,&FirstThread,&FirstThreadHandle,
489 THREAD_ALL_ACCESS,NULL, TRUE);
490 FirstThread->Tcb.State = THREAD_STATE_RUNNING;
491 FirstThread->Tcb.FreezeCount = 0;
492 ((PIKPCR) KeGetCurrentKPCR())->CurrentThread = (PVOID)FirstThread;
493 NtClose(FirstThreadHandle);
494
495 DPRINT("FirstThread %x\n",FirstThread);
496
497 DoneInitYet = TRUE;
498
499 /*
500 * Create the reaper thread
501 */
502 KeInitializeEvent(&PiReaperThreadEvent, SynchronizationEvent, FALSE);
503 Status = PsCreateSystemThread(&PiReaperThreadHandle,
504 THREAD_ALL_ACCESS,
505 NULL,
506 NULL,
507 NULL,
508 (PKSTART_ROUTINE) PiReaperThreadMain,
509 NULL);
510 if (!NT_SUCCESS(Status))
511 {
512 DPRINT1("PS: Failed to create reaper thread.\n");
513 KEBUGCHECK(0);
514 }
515 }
516
517 /*
518 * @implemented
519 */
520 LONG STDCALL
521 KeSetBasePriorityThread (PKTHREAD Thread,
522 LONG Increment)
523 /*
524 * Sets thread's base priority relative to the process' base priority
525 * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h
526 */
527 {
528 KPRIORITY Priority;
529 if (Increment < -2)
530 {
531 Increment = -2;
532 }
533 else if (Increment > 2)
534 {
535 Increment = 2;
536 }
537 Priority = ((PETHREAD)Thread)->ThreadsProcess->Pcb.BasePriority + Increment;
538 if (Priority < LOW_PRIORITY)
539 {
540 Priority = LOW_PRIORITY;
541 }
542 else if (Priority >= MAXIMUM_PRIORITY)
543 {
544 Thread->BasePriority = HIGH_PRIORITY;
545 }
546 KeSetPriorityThread(Thread, Priority);
547 return 1;
548 }
549
550
551 /*
552 * @implemented
553 */
554 KPRIORITY STDCALL
555 KeSetPriorityThread (PKTHREAD Thread, KPRIORITY Priority)
556 {
557 KPRIORITY OldPriority;
558 KIRQL oldIrql;
559 PKTHREAD CurrentThread;
560 ULONG Mask;
561
562 if (Priority < LOW_PRIORITY || Priority >= MAXIMUM_PRIORITY)
563 {
564 KEBUGCHECK(0);
565 }
566
567 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
568
569 OldPriority = Thread->Priority;
570 Thread->BasePriority = Thread->Priority = (CHAR)Priority;
571
572 if (OldPriority != Priority)
573 {
574 if (Thread->State == THREAD_STATE_READY)
575 {
576 PsRemoveFromThreadList((PETHREAD)Thread);
577 PsInsertIntoThreadList(Priority, (PETHREAD)Thread);
578 CurrentThread = ((PIKPCR) KeGetCurrentKPCR())->CurrentThread;
579 if (CurrentThread->Priority < Priority)
580 {
581 PsDispatchThreadNoLock(THREAD_STATE_READY);
582 KeLowerIrql(oldIrql);
583 return (OldPriority);
584 }
585 }
586 else if (Thread->State == THREAD_STATE_RUNNING)
587 {
588 if (Priority < OldPriority)
589 {
590 /* Check for threads with a higher priority */
591 Mask = ~((1 << (Priority + 1)) - 1);
592 if (PriorityListMask & Mask)
593 {
594 PsDispatchThreadNoLock(THREAD_STATE_READY);
595 KeLowerIrql(oldIrql);
596 return (OldPriority);
597 }
598 }
599 }
600 }
601 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
602 return(OldPriority);
603 }
604
605 /*
606 * @unimplemented
607 */
608 NTSTATUS STDCALL
609 KeSetAffinityThread(PKTHREAD Thread,
610 PVOID AfMask)
611 /*
612 * Sets thread's affinity
613 */
614 {
615 DPRINT1("KeSetAffinityThread() is a stub returning STATUS_SUCCESS");
616 return STATUS_SUCCESS; // FIXME: Use function below
617 //return ZwSetInformationThread(handle, ThreadAffinityMask,<pointer to affinity mask>,sizeof(KAFFINITY));
618 }
619
620
621 NTSTATUS STDCALL
622 NtAlertResumeThread(IN HANDLE ThreadHandle,
623 OUT PULONG SuspendCount)
624 {
625 UNIMPLEMENTED;
626 }
627
628
629 NTSTATUS STDCALL
630 NtAlertThread (IN HANDLE ThreadHandle)
631 {
632 PETHREAD Thread;
633 NTSTATUS Status;
634 NTSTATUS ThreadStatus;
635
636 Status = ObReferenceObjectByHandle(ThreadHandle,
637 THREAD_SUSPEND_RESUME,
638 PsThreadType,
639 UserMode,
640 (PVOID*)&Thread,
641 NULL);
642 if (Status != STATUS_SUCCESS)
643 {
644 return(Status);
645 }
646
647 ThreadStatus = STATUS_ALERTED;
648 (VOID)PsUnblockThread(Thread, &ThreadStatus);
649
650 ObDereferenceObject(Thread);
651 return(STATUS_SUCCESS);
652 }
653
654 /**********************************************************************
655 * NtOpenThread/4
656 *
657 * @implemented
658 */
659 NTSTATUS STDCALL
660 NtOpenThread(OUT PHANDLE ThreadHandle,
661 IN ACCESS_MASK DesiredAccess,
662 IN POBJECT_ATTRIBUTES ObjectAttributes,
663 IN PCLIENT_ID ClientId)
664 {
665 NTSTATUS Status = STATUS_INVALID_PARAMETER;
666
667 if((NULL != ThreadHandle)&&(NULL != ObjectAttributes))
668 {
669 PETHREAD EThread = NULL;
670
671 if((ClientId)
672 && (ClientId->UniqueProcess)
673 && (ClientId->UniqueThread))
674 {
675 // It is an error to specify both
676 // ObjectAttributes.ObjectName
677 // and ClientId.
678 if((ObjectAttributes)
679 && (ObjectAttributes->ObjectName)
680 && (0 < ObjectAttributes->ObjectName->Length))
681 {
682 return(STATUS_INVALID_PARAMETER_MIX);
683 }
684 // Parameters mix OK
685 Status = PsLookupProcessThreadByCid(ClientId,
686 NULL,
687 & EThread);
688 }
689 else if((ObjectAttributes)
690 && (ObjectAttributes->ObjectName)
691 && (0 < ObjectAttributes->ObjectName->Length))
692 {
693 // Three Ob attributes are forbidden
694 if(!(ObjectAttributes->Attributes &
695 (OBJ_PERMANENT | OBJ_EXCLUSIVE | OBJ_OPENIF)))
696 {
697 Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
698 ObjectAttributes->Attributes,
699 NULL,
700 DesiredAccess,
701 PsThreadType,
702 UserMode,
703 NULL,
704 (PVOID*) & EThread);
705 }
706 }
707 // EThread may be OK...
708 if(STATUS_SUCCESS == Status)
709 {
710 Status = ObCreateHandle(PsGetCurrentProcess(),
711 EThread,
712 DesiredAccess,
713 FALSE,
714 ThreadHandle);
715 ObDereferenceObject(EThread);
716 }
717 }
718 return(Status);
719 }
720
721 NTSTATUS STDCALL
722 NtContinue(IN PCONTEXT Context,
723 IN BOOLEAN TestAlert)
724 {
725 PKTRAP_FRAME TrapFrame;
726
727 /*
728 * Copy the supplied context over the register information that was saved
729 * on entry to kernel mode, it will then be restored on exit
730 * FIXME: Validate the context
731 */
732 TrapFrame = KeGetCurrentThread()->TrapFrame;
733 if (TrapFrame == NULL)
734 {
735 CPRINT("NtContinue called but TrapFrame was NULL\n");
736 KEBUGCHECK(0);
737 }
738 KeContextToTrapFrame(Context, TrapFrame);
739 return(STATUS_SUCCESS);
740 }
741
742
743 NTSTATUS STDCALL
744 NtYieldExecution(VOID)
745 {
746 PsDispatchThread(THREAD_STATE_READY);
747 return(STATUS_SUCCESS);
748 }
749
750
751 /*
752 * @implemented
753 */
754 NTSTATUS STDCALL
755 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid,
756 OUT PEPROCESS *Process OPTIONAL,
757 OUT PETHREAD *Thread)
758 {
759 KIRQL oldIrql;
760 PLIST_ENTRY current_entry;
761 PETHREAD current;
762
763 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
764
765 current_entry = PiThreadListHead.Flink;
766 while (current_entry != &PiThreadListHead)
767 {
768 current = CONTAINING_RECORD(current_entry,
769 ETHREAD,
770 Tcb.ThreadListEntry);
771 if (current->Cid.UniqueThread == Cid->UniqueThread &&
772 current->Cid.UniqueProcess == Cid->UniqueProcess)
773 {
774 if (Process != NULL)
775 {
776 *Process = current->ThreadsProcess;
777 ObReferenceObject(current->ThreadsProcess);
778 }
779
780 *Thread = current;
781 ObReferenceObject(current);
782
783 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
784 return(STATUS_SUCCESS);
785 }
786
787 current_entry = current_entry->Flink;
788 }
789
790 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
791
792 return(STATUS_INVALID_PARAMETER);
793 }
794
795
796 /*
797 * @implemented
798 */
799 NTSTATUS STDCALL
800 PsLookupThreadByThreadId(IN PVOID ThreadId,
801 OUT PETHREAD *Thread)
802 {
803 KIRQL oldIrql;
804 PLIST_ENTRY current_entry;
805 PETHREAD current;
806
807 KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
808
809 current_entry = PiThreadListHead.Flink;
810 while (current_entry != &PiThreadListHead)
811 {
812 current = CONTAINING_RECORD(current_entry,
813 ETHREAD,
814 Tcb.ThreadListEntry);
815 if (current->Cid.UniqueThread == (HANDLE)ThreadId)
816 {
817 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
818 *Thread = current;
819 ObReferenceObject(current);
820 return(STATUS_SUCCESS);
821 }
822
823 current_entry = current_entry->Flink;
824 }
825
826 KeReleaseSpinLock(&PiThreadListLock, oldIrql);
827
828 return(STATUS_INVALID_PARAMETER);
829 }
830
831 /* EOF */