update for HEAD-2003091401
[reactos.git] / ntoskrnl / ps / thread.c
1 /* $Id$
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 BOOL 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         KeAcquireDispatcherDatabaseLock(FALSE);
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     KeReleaseDispatcherDatabaseLockAtDpcLevel(FALSE);
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           KeReleaseDispatcherDatabaseLockAtDpcLevel(FALSE);
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
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 
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    RtlInitUnicodeStringFromLiteral(&PsThreadType->TypeName, L"Thread");
466    
467    PsThreadType->Tag = TAG('T', 'H', 'R', 'T');
468    PsThreadType->TotalObjects = 0;
469    PsThreadType->TotalHandles = 0;
470    PsThreadType->MaxObjects = 0;
471    PsThreadType->MaxHandles = 0;
472    PsThreadType->PagedPoolCharge = 0;
473    PsThreadType->NonpagedPoolCharge = sizeof(ETHREAD);
474    PsThreadType->Mapping = &PiThreadMapping;
475    PsThreadType->Dump = NULL;
476    PsThreadType->Open = NULL;
477    PsThreadType->Close = NULL;
478    PsThreadType->Delete = PiDeleteThread;
479    PsThreadType->Parse = NULL;
480    PsThreadType->Security = NULL;
481    PsThreadType->QueryName = NULL;
482    PsThreadType->OkayToClose = NULL;
483    PsThreadType->Create = NULL;
484    PsThreadType->DuplicationNotify = NULL;
485    
486    PsInitializeThread(NULL,&FirstThread,&FirstThreadHandle,
487                       THREAD_ALL_ACCESS,NULL, TRUE);
488    FirstThread->Tcb.State = THREAD_STATE_RUNNING;
489    FirstThread->Tcb.FreezeCount = 0;
490    ((PIKPCR) KeGetCurrentKPCR())->CurrentThread = (PVOID)FirstThread;
491    NtClose(FirstThreadHandle);
492    
493    DPRINT("FirstThread %x\n",FirstThread);
494       
495    DoneInitYet = TRUE;
496
497    /*
498     * Create the reaper thread
499     */
500    KeInitializeEvent(&PiReaperThreadEvent, SynchronizationEvent, FALSE);
501    Status = PsCreateSystemThread(&PiReaperThreadHandle,
502                                  THREAD_ALL_ACCESS,
503                                  NULL,
504                                  NULL,
505                                  NULL,
506                                  (PKSTART_ROUTINE) PiReaperThreadMain,
507                                  NULL);
508    if (!NT_SUCCESS(Status))
509      {
510        DPRINT1("PS: Failed to create reaper thread.\n");
511        KEBUGCHECK(0);
512      }
513 }
514
515 /*
516  * @implemented
517  */
518 LONG STDCALL
519 KeSetBasePriorityThread (PKTHREAD       Thread,
520                          LONG           Increment)
521 /*
522  * Sets thread's base priority relative to the process' base priority
523  * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h
524  */
525 {
526    KPRIORITY Priority;
527    if (Increment < -2)
528      {
529        Increment = -2;
530      }
531    else if (Increment > 2)
532      {
533        Increment = 2;
534      }
535    Priority = ((PETHREAD)Thread)->ThreadsProcess->Pcb.BasePriority + Increment;
536    if (Priority < LOW_PRIORITY)
537    {
538      Priority = LOW_PRIORITY;
539    }
540    else if (Priority >= MAXIMUM_PRIORITY)
541      {
542        Thread->BasePriority = HIGH_PRIORITY;
543      }
544    KeSetPriorityThread(Thread, Priority);
545    return 1;
546 }
547
548
549 /*
550  * @implemented
551  */
552 KPRIORITY STDCALL
553 KeSetPriorityThread (PKTHREAD Thread, KPRIORITY Priority)
554 {
555    KPRIORITY OldPriority;
556    KIRQL oldIrql;
557    PKTHREAD CurrentThread;
558    ULONG Mask;
559    
560    if (Priority < LOW_PRIORITY || Priority >= MAXIMUM_PRIORITY)
561      {
562         KEBUGCHECK(0);
563      }
564    
565    KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
566
567    OldPriority = Thread->Priority;
568    Thread->BasePriority = Thread->Priority = (CHAR)Priority;
569
570    if (OldPriority != Priority)
571      {
572        if (Thread->State == THREAD_STATE_READY)
573          {
574            PsRemoveFromThreadList((PETHREAD)Thread);
575            PsInsertIntoThreadList(Priority, (PETHREAD)Thread);
576            CurrentThread = ((PIKPCR) KeGetCurrentKPCR())->CurrentThread;
577            if (CurrentThread->Priority < Priority)
578              {
579                PsDispatchThreadNoLock(THREAD_STATE_READY);
580                KeLowerIrql(oldIrql);
581                return (OldPriority);
582              }
583          }
584        else if (Thread->State == THREAD_STATE_RUNNING)
585          {
586            if (Priority < OldPriority)
587              {
588                /* Check for threads with a higher priority */
589                Mask = ~((1 << (Priority + 1)) - 1);
590                if (PriorityListMask & Mask)
591                  {
592                    PsDispatchThreadNoLock(THREAD_STATE_READY);
593                    KeLowerIrql(oldIrql);
594                    return (OldPriority);
595                  }
596              }
597          }
598      }
599    KeReleaseSpinLock(&PiThreadListLock, oldIrql);
600    return(OldPriority);
601 }
602
603 /*
604  * @unimplemented
605  */
606 NTSTATUS STDCALL
607 KeSetAffinityThread(PKTHREAD    Thread,
608                     PVOID       AfMask)
609 /*
610  * Sets thread's affinity
611  */
612 {
613         DPRINT1("KeSetAffinityThread() is a stub returning STATUS_SUCCESS");
614         return STATUS_SUCCESS; // FIXME: Use function below
615         //return ZwSetInformationThread(handle, ThreadAffinityMask,<pointer to affinity mask>,sizeof(KAFFINITY));
616 }
617
618
619 NTSTATUS STDCALL 
620 NtAlertResumeThread(IN  HANDLE ThreadHandle,
621                     OUT PULONG  SuspendCount)
622 {
623    UNIMPLEMENTED;
624 }
625
626
627 NTSTATUS STDCALL NtAlertThread (IN HANDLE ThreadHandle)
628 {
629    PETHREAD Thread;
630    NTSTATUS Status;
631    NTSTATUS ThreadStatus;
632    
633    Status = ObReferenceObjectByHandle(ThreadHandle,
634                                       THREAD_SUSPEND_RESUME,
635                                       PsThreadType,
636                                       UserMode,
637                                       (PVOID*)&Thread,
638                                       NULL);
639    if (Status != STATUS_SUCCESS)
640      {
641         return(Status);
642      }
643    
644    ThreadStatus = STATUS_ALERTED;
645    (VOID)PsUnblockThread(Thread, &ThreadStatus);
646    
647    ObDereferenceObject(Thread);
648    return(STATUS_SUCCESS);
649 }
650
651 /**********************************************************************
652  *      NtOpenThread/4
653  *
654  *      @implemented
655  */
656 NTSTATUS STDCALL 
657 NtOpenThread(OUT PHANDLE ThreadHandle,
658              IN ACCESS_MASK DesiredAccess,
659              IN POBJECT_ATTRIBUTES ObjectAttributes,
660              IN PCLIENT_ID ClientId)
661 {
662    NTSTATUS Status = STATUS_INVALID_PARAMETER;
663
664    if((NULL != ThreadHandle)&&(NULL != ObjectAttributes))
665    {
666       PETHREAD EThread = NULL;
667
668       if((ClientId)
669         && (ClientId->UniqueProcess)
670         && (ClientId->UniqueThread))
671       {
672          // It is an error to specify both
673          // ObjectAttributes.ObjectName
674          // and ClientId.
675          if((ObjectAttributes)
676            && (ObjectAttributes->ObjectName)
677            && (0 < ObjectAttributes->ObjectName->Length))
678          {
679             return(STATUS_INVALID_PARAMETER_MIX);
680          }
681          // Parameters mix OK
682          Status = PsLookupProcessThreadByCid(ClientId,
683                      NULL,
684                      & EThread);
685       }
686       else if((ObjectAttributes)
687              && (ObjectAttributes->ObjectName)
688              && (0 < ObjectAttributes->ObjectName->Length))
689       {
690          // Three Ob attributes are forbidden
691          if(!(ObjectAttributes->Attributes &
692             (OBJ_PERMANENT | OBJ_EXCLUSIVE | OBJ_OPENIF)))
693          {
694             Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
695                         ObjectAttributes->Attributes,
696                         NULL,
697                         DesiredAccess,
698                         PsThreadType,
699                         UserMode,
700                         NULL,
701                         (PVOID*) & EThread);
702          }
703       }
704       // EThread may be OK...
705       if(STATUS_SUCCESS == Status)
706       {
707          Status = ObCreateHandle(PsGetCurrentProcess(),
708                      EThread,
709                      DesiredAccess,
710                      FALSE,
711                      ThreadHandle);
712          ObDereferenceObject(EThread); 
713       }
714    }
715    return(Status);  
716 }
717
718 NTSTATUS STDCALL 
719 NtContinue(IN PCONTEXT  Context,
720            IN BOOLEAN TestAlert)
721 {
722    PKTRAP_FRAME TrapFrame;
723    
724    /*
725     * Copy the supplied context over the register information that was saved
726     * on entry to kernel mode, it will then be restored on exit
727     * FIXME: Validate the context
728     */
729    TrapFrame = KeGetCurrentThread()->TrapFrame;
730    if (TrapFrame == NULL)
731      {
732         CPRINT("NtContinue called but TrapFrame was NULL\n");
733         KEBUGCHECK(0);
734      }
735    KeContextToTrapFrame(Context, TrapFrame);
736    return(STATUS_SUCCESS);
737 }
738
739
740 NTSTATUS STDCALL
741 NtYieldExecution(VOID)
742 {
743   PsDispatchThread(THREAD_STATE_READY);
744   return(STATUS_SUCCESS);
745 }
746
747
748 /*
749  * @implemented
750  */
751 NTSTATUS STDCALL
752 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid,
753                            OUT PEPROCESS *Process OPTIONAL,
754                            OUT PETHREAD *Thread)
755 {
756   KIRQL oldIrql;
757   PLIST_ENTRY current_entry;
758   PETHREAD current;
759
760   KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
761
762   current_entry = PiThreadListHead.Flink;
763   while (current_entry != &PiThreadListHead)
764     {
765       current = CONTAINING_RECORD(current_entry,
766                                   ETHREAD,
767                                   Tcb.ThreadListEntry);
768       if (current->Cid.UniqueThread == Cid->UniqueThread &&
769           current->Cid.UniqueProcess == Cid->UniqueProcess)
770         {
771           if (Process != NULL)
772           {
773             *Process = current->ThreadsProcess;
774             ObReferenceObject(current->ThreadsProcess);
775           }
776
777           *Thread = current;
778           ObReferenceObject(current);
779
780           KeReleaseSpinLock(&PiThreadListLock, oldIrql);
781           return(STATUS_SUCCESS);
782         }
783
784       current_entry = current_entry->Flink;
785     }
786
787   KeReleaseSpinLock(&PiThreadListLock, oldIrql);
788
789   return(STATUS_INVALID_PARAMETER);
790 }
791
792
793 /*
794  * @implemented
795  */
796 NTSTATUS STDCALL
797 PsLookupThreadByThreadId(IN PVOID ThreadId,
798                          OUT PETHREAD *Thread)
799 {
800   KIRQL oldIrql;
801   PLIST_ENTRY current_entry;
802   PETHREAD current;
803
804   KeAcquireSpinLock(&PiThreadListLock, &oldIrql);
805
806   current_entry = PiThreadListHead.Flink;
807   while (current_entry != &PiThreadListHead)
808     {
809       current = CONTAINING_RECORD(current_entry,
810                                   ETHREAD,
811                                   Tcb.ThreadListEntry);
812       if (current->Cid.UniqueThread == (HANDLE)ThreadId)
813         {
814           *Thread = current;
815           ObReferenceObject(current);
816           KeReleaseSpinLock(&PiThreadListLock, oldIrql);
817           return(STATUS_SUCCESS);
818         }
819
820       current_entry = current_entry->Flink;
821     }
822
823   KeReleaseSpinLock(&PiThreadListLock, oldIrql);
824
825   return(STATUS_INVALID_PARAMETER);
826 }
827
828 /* EOF */