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