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