08a0a10dd02d07fdea2fec9ca433b5de5eb69d0d
[reactos.git] / reactos / 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 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 * Phillip Susi
10 */
11
12 /*
13 * NOTE:
14 *
15 * All of the routines that manipulate the thread queue synchronize on
16 * a single spinlock
17 *
18 */
19
20 /* INCLUDES ****************************************************************/
21
22 #include <ntoskrnl.h>
23 #define NDEBUG
24 #include <internal/debug.h>
25
26 /* TYPES *******************************************************************/
27
28 /* GLOBALS ******************************************************************/
29
30 extern LIST_ENTRY PsActiveProcessHead;
31 extern PEPROCESS PsIdleProcess;
32
33 POBJECT_TYPE EXPORTED PsThreadType = NULL;
34
35 LONG PiNrThreadsAwaitingReaping = 0;
36
37 extern PVOID Ki386InitialStackArray[MAXIMUM_PROCESSORS];
38
39 /*
40 * PURPOSE: List of threads associated with each priority level
41 */
42 static LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY];
43 static ULONG PriorityListMask = 0;
44 static ULONG IdleProcessorMask = 0;
45 static BOOLEAN DoneInitYet = FALSE;
46 static KEVENT PiReaperThreadEvent;
47 static BOOLEAN PiReaperThreadShouldTerminate = FALSE;
48
49 static GENERIC_MAPPING PiThreadMapping = {STANDARD_RIGHTS_READ | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
50 STANDARD_RIGHTS_WRITE | THREAD_TERMINATE | THREAD_SUSPEND_RESUME | THREAD_ALERT |
51 THREAD_SET_INFORMATION | THREAD_SET_CONTEXT,
52 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
53 THREAD_ALL_ACCESS};
54
55 /* FUNCTIONS ***************************************************************/
56
57 /*
58 * @implemented
59 */
60 PKTHREAD STDCALL KeGetCurrentThread(VOID)
61 {
62 #ifdef CONFIG_SMP
63 ULONG Flags;
64 PKTHREAD Thread;
65 Ke386SaveFlags(Flags);
66 Ke386DisableInterrupts();
67 Thread = KeGetCurrentPrcb()->CurrentThread;
68 Ke386RestoreFlags(Flags);
69 return Thread;
70 #else
71 return(KeGetCurrentPrcb()->CurrentThread);
72 #endif
73 }
74
75 /*
76 * @implemented
77 */
78 HANDLE STDCALL PsGetCurrentThreadId(VOID)
79 {
80 return(PsGetCurrentThread()->Cid.UniqueThread);
81 }
82
83 /*
84 * @implemented
85 */
86 ULONG
87 STDCALL
88 PsGetThreadFreezeCount(
89 PETHREAD Thread
90 )
91 {
92 return Thread->Tcb.FreezeCount;
93 }
94
95 /*
96 * @implemented
97 */
98 BOOLEAN
99 STDCALL
100 PsGetThreadHardErrorsAreDisabled(
101 PETHREAD Thread
102 )
103 {
104 return Thread->HardErrorsAreDisabled;
105 }
106
107 /*
108 * @implemented
109 */
110 HANDLE
111 STDCALL
112 PsGetThreadId(
113 PETHREAD Thread
114 )
115 {
116 return Thread->Cid.UniqueThread;
117 }
118
119 /*
120 * @implemented
121 */
122 PEPROCESS
123 STDCALL
124 PsGetThreadProcess(
125 PETHREAD Thread
126 )
127 {
128 return Thread->ThreadsProcess;
129 }
130
131 /*
132 * @implemented
133 */
134 HANDLE
135 STDCALL
136 PsGetThreadProcessId(
137 PETHREAD Thread
138 )
139 {
140 return Thread->Cid.UniqueProcess;
141 }
142
143 /*
144 * @implemented
145 */
146 HANDLE
147 STDCALL
148 PsGetThreadSessionId(
149 PETHREAD Thread
150 )
151 {
152 return (HANDLE)Thread->ThreadsProcess->SessionId;
153 }
154
155 /*
156 * @implemented
157 */
158 PTEB
159 STDCALL
160 PsGetThreadTeb(
161 PETHREAD Thread
162 )
163 {
164 return Thread->Tcb.Teb;
165 }
166
167 /*
168 * @implemented
169 */
170 PVOID
171 STDCALL
172 PsGetThreadWin32Thread(
173 PETHREAD Thread
174 )
175 {
176 return Thread->Tcb.Win32Thread;
177 }
178
179 /*
180 * @implemented
181 */
182 KPROCESSOR_MODE
183 STDCALL
184 PsGetCurrentThreadPreviousMode (
185 VOID
186 )
187 {
188 return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode;
189 }
190
191 /*
192 * @implemented
193 */
194 PVOID
195 STDCALL
196 PsGetCurrentThreadStackBase (
197 VOID
198 )
199 {
200 return PsGetCurrentThread()->Tcb.StackBase;
201 }
202
203 /*
204 * @implemented
205 */
206 PVOID
207 STDCALL
208 PsGetCurrentThreadStackLimit (
209 VOID
210 )
211 {
212 return (PVOID)PsGetCurrentThread()->Tcb.StackLimit;
213 }
214
215 /*
216 * @implemented
217 */
218 BOOLEAN STDCALL
219 PsIsThreadTerminating(IN PETHREAD Thread)
220 {
221 return (Thread->HasTerminated ? TRUE : FALSE);
222 }
223
224 /*
225 * @unimplemented
226 */
227 BOOLEAN
228 STDCALL
229 PsIsSystemThread(
230 PETHREAD Thread
231 )
232 {
233 UNIMPLEMENTED;
234 return FALSE;
235 }
236
237 /*
238 * @implemented
239 */
240 BOOLEAN
241 STDCALL
242 PsIsThreadImpersonating(
243 PETHREAD Thread
244 )
245 {
246 return Thread->ActiveImpersonationInfo;
247 }
248
249 static VOID
250 KiRequestReschedule(CCHAR Processor)
251 {
252 PKPCR Pcr;
253
254 Pcr = (PKPCR)(KPCR_BASE + Processor * PAGE_SIZE);
255 Pcr->Prcb->QuantumEnd = TRUE;
256 KiIpiSendRequest(1 << Processor, IPI_REQUEST_DPC);
257 }
258
259 static VOID
260 PsInsertIntoThreadList(KPRIORITY Priority, PETHREAD Thread)
261 {
262 ASSERT(THREAD_STATE_READY == Thread->Tcb.State);
263 ASSERT(Thread->Tcb.Priority == Priority);
264 if (Priority >= MAXIMUM_PRIORITY || Priority < LOW_PRIORITY)
265 {
266 DPRINT1("Invalid thread priority (%d)\n", Priority);
267 KEBUGCHECK(0);
268 }
269 InsertTailList(&PriorityListHead[Priority], &Thread->Tcb.QueueListEntry);
270 PriorityListMask |= (1 << Priority);
271 }
272
273 static VOID PsRemoveFromThreadList(PETHREAD Thread)
274 {
275 ASSERT(THREAD_STATE_READY == Thread->Tcb.State);
276 RemoveEntryList(&Thread->Tcb.QueueListEntry);
277 if (IsListEmpty(&PriorityListHead[(ULONG)Thread->Tcb.Priority]))
278 {
279 PriorityListMask &= ~(1 << Thread->Tcb.Priority);
280 }
281 }
282
283
284 VOID PsDumpThreads(BOOLEAN IncludeSystem)
285 {
286 PLIST_ENTRY AThread, AProcess;
287 PEPROCESS Process;
288 PETHREAD Thread;
289 ULONG nThreads = 0;
290
291 AProcess = PsActiveProcessHead.Flink;
292 while(AProcess != &PsActiveProcessHead)
293 {
294 Process = CONTAINING_RECORD(AProcess, EPROCESS, ProcessListEntry);
295 /* FIXME - skip suspended, ... processes? */
296 if((Process != PsInitialSystemProcess) ||
297 (Process == PsInitialSystemProcess && IncludeSystem))
298 {
299 AThread = Process->ThreadListHead.Flink;
300 while(AThread != &Process->ThreadListHead)
301 {
302 Thread = CONTAINING_RECORD(AThread, ETHREAD, ThreadListEntry);
303
304 nThreads++;
305 DbgPrint("Thread->Tcb.State %d Affinity %08x Priority %d PID.TID %d.%d Name %.8s Stack: \n",
306 Thread->Tcb.State,
307 Thread->Tcb.Affinity,
308 Thread->Tcb.Priority,
309 Thread->ThreadsProcess->UniqueProcessId,
310 Thread->Cid.UniqueThread,
311 Thread->ThreadsProcess->ImageFileName);
312 if(Thread->Tcb.State == THREAD_STATE_READY ||
313 Thread->Tcb.State == THREAD_STATE_SUSPENDED ||
314 Thread->Tcb.State == THREAD_STATE_BLOCKED)
315 {
316 ULONG i = 0;
317 PULONG Esp = (PULONG)Thread->Tcb.KernelStack;
318 PULONG Ebp = (PULONG)Esp[4];
319 DbgPrint("Ebp 0x%.8X\n", Ebp);
320 while(Ebp != 0 && Ebp >= (PULONG)Thread->Tcb.StackLimit)
321 {
322 DbgPrint("%.8X %.8X%s", Ebp[0], Ebp[1], (i % 8) == 7 ? "\n" : " ");
323 Ebp = (PULONG)Ebp[0];
324 i++;
325 }
326 if((i % 8) != 0)
327 {
328 DbgPrint("\n");
329 }
330 }
331 AThread = AThread->Flink;
332 }
333 }
334 AProcess = AProcess->Flink;
335 }
336 }
337
338 static PETHREAD PsScanThreadList(KPRIORITY Priority, ULONG Affinity)
339 {
340 PLIST_ENTRY current_entry;
341 PETHREAD current;
342 ULONG Mask;
343
344 Mask = (1 << Priority);
345 if (PriorityListMask & Mask)
346 {
347 current_entry = PriorityListHead[Priority].Flink;
348 while (current_entry != &PriorityListHead[Priority])
349 {
350 current = CONTAINING_RECORD(current_entry, ETHREAD,
351 Tcb.QueueListEntry);
352 if (current->Tcb.State != THREAD_STATE_READY)
353 {
354 DPRINT1("%d/%d\n", current->Cid.UniqueThread, current->Tcb.State);
355 }
356 ASSERT(current->Tcb.State == THREAD_STATE_READY);
357 DPRINT("current->Tcb.Affinity %x Affinity %x PID %d %d\n",
358 current->Tcb.Affinity, Affinity, current->Cid.UniqueThread,
359 Priority);
360 if (current->Tcb.Affinity & Affinity)
361 {
362 PsRemoveFromThreadList(current);
363 return(current);
364 }
365 current_entry = current_entry->Flink;
366 }
367 }
368 return(NULL);
369 }
370
371 VOID STDCALL
372 PiWakeupReaperThread(VOID)
373 {
374 KeSetEvent(&PiReaperThreadEvent, 0, FALSE);
375 }
376
377 VOID STDCALL
378 PiReaperThreadMain(PVOID Ignored)
379 {
380 for(;;)
381 {
382 KeWaitForSingleObject(&PiReaperThreadEvent,
383 Executive,
384 KernelMode,
385 FALSE,
386 NULL);
387 if (PiReaperThreadShouldTerminate)
388 {
389 PsTerminateSystemThread(0);
390 }
391 PsReapThreads();
392 }
393 }
394
395 VOID PsDispatchThreadNoLock (ULONG NewThreadStatus)
396 {
397 KPRIORITY CurrentPriority;
398 PETHREAD Candidate;
399 ULONG Affinity;
400 PKTHREAD KCurrentThread = KeGetCurrentThread();
401 PETHREAD CurrentThread = CONTAINING_RECORD(KCurrentThread, ETHREAD, Tcb);
402
403 DPRINT("PsDispatchThread() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(),
404 CurrentThread->Cid.UniqueThread, NewThreadStatus, CurrentThread->Tcb.State);
405
406 CurrentThread->Tcb.State = (UCHAR)NewThreadStatus;
407 switch(NewThreadStatus)
408 {
409 case THREAD_STATE_READY:
410 PsInsertIntoThreadList(CurrentThread->Tcb.Priority,
411 CurrentThread);
412 break;
413 case THREAD_STATE_TERMINATED_1:
414 PsQueueThreadReap(CurrentThread);
415 break;
416 }
417
418 Affinity = 1 << KeGetCurrentProcessorNumber();
419 for (CurrentPriority = HIGH_PRIORITY;
420 CurrentPriority >= LOW_PRIORITY;
421 CurrentPriority--)
422 {
423 Candidate = PsScanThreadList(CurrentPriority, Affinity);
424 if (Candidate == CurrentThread)
425 {
426 Candidate->Tcb.State = THREAD_STATE_RUNNING;
427 KeReleaseDispatcherDatabaseLockFromDpcLevel();
428 return;
429 }
430 if (Candidate != NULL)
431 {
432 PETHREAD OldThread;
433 PKTHREAD IdleThread;
434
435 DPRINT("Scheduling %x(%d)\n",Candidate, CurrentPriority);
436
437 Candidate->Tcb.State = THREAD_STATE_RUNNING;
438
439 OldThread = CurrentThread;
440 CurrentThread = Candidate;
441 IdleThread = KeGetCurrentPrcb()->IdleThread;
442
443 if (&OldThread->Tcb == IdleThread)
444 {
445 IdleProcessorMask &= ~Affinity;
446 }
447 else if (&CurrentThread->Tcb == IdleThread)
448 {
449 IdleProcessorMask |= Affinity;
450 }
451
452 MmUpdatePageDir(PsGetCurrentProcess(),(PVOID)CurrentThread->ThreadsProcess, sizeof(EPROCESS));
453
454 KiArchContextSwitch(&CurrentThread->Tcb, &OldThread->Tcb);
455 return;
456 }
457 }
458 CPRINT("CRITICAL: No threads are ready (CPU%d)\n", KeGetCurrentProcessorNumber());
459 PsDumpThreads(TRUE);
460 KEBUGCHECK(0);
461 }
462
463 VOID STDCALL
464 PsDispatchThread(ULONG NewThreadStatus)
465 {
466 KIRQL oldIrql;
467
468 if (!DoneInitYet || KeGetCurrentPrcb()->IdleThread == NULL)
469 {
470 return;
471 }
472 oldIrql = KeAcquireDispatcherDatabaseLock();
473 PsDispatchThreadNoLock(NewThreadStatus);
474 KeLowerIrql(oldIrql);
475 }
476
477 VOID
478 PsUnblockThread(PETHREAD Thread, PNTSTATUS WaitStatus, KPRIORITY Increment)
479 {
480 if (THREAD_STATE_TERMINATED_1 == Thread->Tcb.State ||
481 THREAD_STATE_TERMINATED_2 == Thread->Tcb.State)
482 {
483 DPRINT("Can't unblock thread %d because it's terminating\n",
484 Thread->Cid.UniqueThread);
485 }
486 else if (THREAD_STATE_READY == Thread->Tcb.State ||
487 THREAD_STATE_RUNNING == Thread->Tcb.State)
488 {
489 DPRINT("Can't unblock thread %d because it's ready or running\n",
490 Thread->Cid.UniqueThread);
491 }
492 else
493 {
494 ULONG Processor;
495 KAFFINITY Affinity;
496
497 /* FIXME: This propably isn't the right way to do it... */
498 if (Thread->Tcb.Priority < LOW_REALTIME_PRIORITY &&
499 Thread->Tcb.BasePriority < LOW_REALTIME_PRIORITY - 2)
500 {
501 if (!Thread->Tcb.PriorityDecrement && !Thread->Tcb.DisableBoost)
502 {
503 Thread->Tcb.Priority = Thread->Tcb.BasePriority + Increment;
504 Thread->Tcb.PriorityDecrement = Increment;
505 }
506 }
507 else
508 {
509 Thread->Tcb.Quantum = Thread->Tcb.ApcState.Process->ThreadQuantum;
510 }
511
512 if (WaitStatus != NULL)
513 {
514 Thread->Tcb.WaitStatus = *WaitStatus;
515 }
516 Thread->Tcb.State = THREAD_STATE_READY;
517 PsInsertIntoThreadList(Thread->Tcb.Priority, Thread);
518 Processor = KeGetCurrentProcessorNumber();
519 Affinity = Thread->Tcb.Affinity;
520 if (!(IdleProcessorMask & (1 << Processor) & Affinity) &&
521 (IdleProcessorMask & ~(1 << Processor) & Affinity))
522 {
523 ULONG i;
524 for (i = 0; i < KeNumberProcessors - 1; i++)
525 {
526 Processor++;
527 if (Processor >= KeNumberProcessors)
528 {
529 Processor = 0;
530 }
531 if (IdleProcessorMask & (1 << Processor) & Affinity)
532 {
533 #if 0
534 /* FIXME:
535 * Reschedule the threads on an other processor
536 */
537 KeReleaseDispatcherDatabaseLockFromDpcLevel();
538 KiRequestReschedule(Processor);
539 KeAcquireDispatcherDatabaseLockAtDpcLevel();
540 #endif
541 break;
542 }
543 }
544 }
545 }
546 }
547
548 VOID
549 STDCALL
550 PsBlockThread(PNTSTATUS Status,
551 UCHAR Alertable,
552 ULONG WaitMode,
553 UCHAR WaitReason)
554 {
555 PKTHREAD Thread = KeGetCurrentThread();
556 PKWAIT_BLOCK WaitBlock;
557
558 if (Thread->ApcState.KernelApcPending) {
559
560 DPRINT("Dispatching Thread as ready (APC!)\n");
561
562 /* Remove Waits */
563 WaitBlock = Thread->WaitBlockList;
564 while (WaitBlock) {
565 RemoveEntryList (&WaitBlock->WaitListEntry);
566 WaitBlock = WaitBlock->NextWaitBlock;
567 }
568 Thread->WaitBlockList = NULL;
569
570 /* Dispatch it and return status */
571 PsDispatchThreadNoLock (THREAD_STATE_READY);
572 if (Status != NULL) *Status = STATUS_KERNEL_APC;
573
574 } else {
575
576 /* Set the Thread Data as Requested */
577 DPRINT("Dispatching Thread as blocked\n");
578 Thread->Alertable = Alertable;
579 Thread->WaitMode = (UCHAR)WaitMode;
580 Thread->WaitReason = WaitReason;
581
582 /* Dispatch it and return status */
583 PsDispatchThreadNoLock(THREAD_STATE_BLOCKED);
584 if (Status != NULL) *Status = Thread->WaitStatus;
585 }
586
587 DPRINT("Releasing Dispatcher Lock\n");
588 KfLowerIrql(Thread->WaitIrql);
589 }
590
591 VOID
592 PsFreezeAllThreads(PEPROCESS Process)
593 /*
594 * Used by the debugging code to freeze all the process's threads
595 * while the debugger is examining their state.
596 */
597 {
598 KIRQL oldIrql;
599 PLIST_ENTRY current_entry;
600 PETHREAD current;
601
602 oldIrql = KeAcquireDispatcherDatabaseLock();
603 current_entry = Process->ThreadListHead.Flink;
604 while (current_entry != &Process->ThreadListHead)
605 {
606 current = CONTAINING_RECORD(current_entry, ETHREAD,
607 ThreadListEntry);
608
609 /*
610 * We have to be careful here, we can't just set the freeze the
611 * thread inside kernel mode since it may be holding a lock.
612 */
613
614 current_entry = current_entry->Flink;
615 }
616
617 KeReleaseDispatcherDatabaseLock(oldIrql);
618 }
619
620 ULONG
621 PsEnumThreadsByProcess(PEPROCESS Process)
622 {
623 KIRQL oldIrql;
624 PLIST_ENTRY current_entry;
625 ULONG Count = 0;
626
627 oldIrql = KeAcquireDispatcherDatabaseLock();
628
629 current_entry = Process->ThreadListHead.Flink;
630 while (current_entry != &Process->ThreadListHead)
631 {
632 Count++;
633 current_entry = current_entry->Flink;
634 }
635
636 KeReleaseDispatcherDatabaseLock(oldIrql);
637 return Count;
638 }
639
640 /*
641 * @unimplemented
642 */
643 NTSTATUS
644 STDCALL
645 PsRemoveCreateThreadNotifyRoutine (
646 IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine
647 )
648 {
649 UNIMPLEMENTED;
650 return STATUS_NOT_IMPLEMENTED;
651 }
652
653 /*
654 * @unimplemented
655 */
656 ULONG
657 STDCALL
658 PsSetLegoNotifyRoutine(
659 PVOID LegoNotifyRoutine
660 )
661 {
662 UNIMPLEMENTED;
663 return 0;
664 }
665
666 /*
667 * @implemented
668 */
669 VOID
670 STDCALL
671 PsSetThreadHardErrorsAreDisabled(
672 PETHREAD Thread,
673 BOOLEAN HardErrorsAreDisabled
674 )
675 {
676 Thread->HardErrorsAreDisabled = HardErrorsAreDisabled;
677 }
678
679 /*
680 * @implemented
681 */
682 VOID
683 STDCALL
684 PsSetThreadWin32Thread(
685 PETHREAD Thread,
686 PVOID Win32Thread
687 )
688 {
689 Thread->Tcb.Win32Thread = Win32Thread;
690 }
691
692 VOID
693 PsApplicationProcessorInit(VOID)
694 {
695 KIRQL oldIrql;
696 oldIrql = KeAcquireDispatcherDatabaseLock();
697 IdleProcessorMask |= (1 << KeGetCurrentProcessorNumber());
698 KeReleaseDispatcherDatabaseLock(oldIrql);
699 }
700
701 VOID INIT_FUNCTION
702 PsPrepareForApplicationProcessorInit(ULONG Id)
703 {
704 PETHREAD IdleThread;
705 PKPRCB Prcb = ((PKPCR)((ULONG_PTR)KPCR_BASE + Id * PAGE_SIZE))->Prcb;
706
707 PsInitializeThread(PsIdleProcess,
708 &IdleThread,
709 NULL,
710 KernelMode,
711 FALSE);
712 IdleThread->Tcb.State = THREAD_STATE_RUNNING;
713 IdleThread->Tcb.FreezeCount = 0;
714 IdleThread->Tcb.Affinity = 1 << Id;
715 IdleThread->Tcb.UserAffinity = 1 << Id;
716 IdleThread->Tcb.Priority = LOW_PRIORITY;
717 IdleThread->Tcb.BasePriority = LOW_PRIORITY;
718 Prcb->IdleThread = &IdleThread->Tcb;
719 Prcb->CurrentThread = &IdleThread->Tcb;
720
721 Ki386InitialStackArray[Id] = (PVOID)IdleThread->Tcb.StackLimit;
722
723 DPRINT("IdleThread for Processor %d has PID %d\n",
724 Id, IdleThread->Cid.UniqueThread);
725 }
726
727 VOID INIT_FUNCTION
728 PsInitThreadManagment(VOID)
729 /*
730 * FUNCTION: Initialize thread managment
731 */
732 {
733 PETHREAD FirstThread;
734 ULONG i;
735
736 for (i=0; i < MAXIMUM_PRIORITY; i++)
737 {
738 InitializeListHead(&PriorityListHead[i]);
739 }
740
741 PsThreadType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
742
743 PsThreadType->Tag = TAG('T', 'H', 'R', 'T');
744 PsThreadType->TotalObjects = 0;
745 PsThreadType->TotalHandles = 0;
746 PsThreadType->PeakObjects = 0;
747 PsThreadType->PeakHandles = 0;
748 PsThreadType->PagedPoolCharge = 0;
749 PsThreadType->NonpagedPoolCharge = sizeof(ETHREAD);
750 PsThreadType->Mapping = &PiThreadMapping;
751 PsThreadType->Dump = NULL;
752 PsThreadType->Open = NULL;
753 PsThreadType->Close = NULL;
754 PsThreadType->Delete = PiDeleteThread;
755 PsThreadType->Parse = NULL;
756 PsThreadType->Security = NULL;
757 PsThreadType->QueryName = NULL;
758 PsThreadType->OkayToClose = NULL;
759 PsThreadType->Create = NULL;
760 PsThreadType->DuplicationNotify = NULL;
761
762 RtlInitUnicodeString(&PsThreadType->TypeName, L"Thread");
763
764 ObpCreateTypeObject(PsThreadType);
765
766 PsInitializeThread(NULL, &FirstThread, NULL, KernelMode, TRUE);
767 FirstThread->Tcb.State = THREAD_STATE_RUNNING;
768 FirstThread->Tcb.FreezeCount = 0;
769 FirstThread->Tcb.UserAffinity = (1 << 0); /* Set the affinity of the first thread to the boot processor */
770 FirstThread->Tcb.Affinity = (1 << 0);
771 KeGetCurrentPrcb()->CurrentThread = (PVOID)FirstThread;
772
773 DPRINT("FirstThread %x\n",FirstThread);
774
775 DoneInitYet = TRUE;
776 }
777
778 VOID
779 PsInitReaperThread(VOID)
780 {
781 PETHREAD ReaperThread;
782 KIRQL oldIrql;
783 NTSTATUS Status;
784
785 /*
786 * Create the reaper thread
787 */
788 PsInitializeThreadReaper();
789 KeInitializeEvent(&PiReaperThreadEvent, SynchronizationEvent, FALSE);
790 Status = PsInitializeThread(NULL,
791 &ReaperThread,
792 NULL,
793 KernelMode,
794 FALSE);
795 if (!NT_SUCCESS(Status))
796 {
797 DPRINT1("PS: Failed to create reaper thread.\n");
798 KEBUGCHECK(0);
799 }
800
801 ReaperThread->StartAddress = PiReaperThreadMain;
802 Status = KiArchInitThread(&ReaperThread->Tcb, PiReaperThreadMain, NULL);
803 if (!NT_SUCCESS(Status))
804 {
805 DPRINT1("PS: Failed to initialize reaper thread.\n");
806 KEBUGCHECK(0);
807 }
808
809 oldIrql = KeAcquireDispatcherDatabaseLock ();
810 PsUnblockThread(ReaperThread, NULL, 0);
811 KeReleaseDispatcherDatabaseLock(oldIrql);
812 }
813
814 /*
815 * @implemented
816 */
817 LONG STDCALL
818 KeSetBasePriorityThread (PKTHREAD Thread,
819 LONG Increment)
820 /*
821 * Sets thread's base priority relative to the process' base priority
822 * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h
823 */
824 {
825 KPRIORITY Priority;
826 if (Increment < -2)
827 {
828 Increment = -2;
829 }
830 else if (Increment > 2)
831 {
832 Increment = 2;
833 }
834 Priority = ((PETHREAD)Thread)->ThreadsProcess->Pcb.BasePriority + Increment;
835 if (Priority < LOW_PRIORITY)
836 {
837 Priority = LOW_PRIORITY;
838 }
839 else if (Priority >= MAXIMUM_PRIORITY)
840 {
841 Thread->BasePriority = HIGH_PRIORITY;
842 }
843 KeSetPriorityThread(Thread, Priority);
844 return 1;
845 }
846
847
848 /*
849 * @implemented
850 */
851 KPRIORITY STDCALL
852 KeSetPriorityThread (PKTHREAD Thread, KPRIORITY Priority)
853 {
854 KPRIORITY OldPriority;
855 KIRQL oldIrql;
856 PKTHREAD CurrentThread;
857 ULONG Mask;
858 int i;
859 PKPCR Pcr;
860
861 if (Priority < LOW_PRIORITY || Priority >= MAXIMUM_PRIORITY)
862 {
863 KEBUGCHECK(0);
864 }
865
866 oldIrql = KeAcquireDispatcherDatabaseLock();
867
868 OldPriority = Thread->Priority;
869
870 if (OldPriority != Priority)
871 {
872 CurrentThread = KeGetCurrentThread();
873 if (Thread->State == THREAD_STATE_READY)
874 {
875 PsRemoveFromThreadList((PETHREAD)Thread);
876 Thread->BasePriority = Thread->Priority = (CHAR)Priority;
877 PsInsertIntoThreadList(Priority, (PETHREAD)Thread);
878 if (CurrentThread->Priority < Priority)
879 {
880 PsDispatchThreadNoLock(THREAD_STATE_READY);
881 KeLowerIrql(oldIrql);
882 return (OldPriority);
883 }
884 }
885 else if (Thread->State == THREAD_STATE_RUNNING)
886 {
887 Thread->BasePriority = Thread->Priority = (CHAR)Priority;
888 if (Priority < OldPriority)
889 {
890 /* Check for threads with a higher priority */
891 Mask = ~((1 << (Priority + 1)) - 1);
892 if (PriorityListMask & Mask)
893 {
894 if (Thread == CurrentThread)
895 {
896 PsDispatchThreadNoLock(THREAD_STATE_READY);
897 KeLowerIrql(oldIrql);
898 return (OldPriority);
899 }
900 else
901 {
902 for (i = 0; i < KeNumberProcessors; i++)
903 {
904 Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
905 if (Pcr->Prcb->CurrentThread == Thread)
906 {
907 KeReleaseDispatcherDatabaseLockFromDpcLevel();
908 KiRequestReschedule(i);
909 KeLowerIrql(oldIrql);
910 return (OldPriority);
911 }
912 }
913 }
914 }
915 }
916 }
917 else
918 {
919 Thread->BasePriority = Thread->Priority = (CHAR)Priority;
920 }
921 }
922 KeReleaseDispatcherDatabaseLock(oldIrql);
923 return(OldPriority);
924 }
925
926 /*
927 * @unimplemented
928 */
929 NTSTATUS STDCALL
930 KeSetAffinityThread(PKTHREAD Thread,
931 KAFFINITY Affinity)
932 /*
933 * Sets thread's affinity
934 */
935 {
936 KIRQL oldIrql;
937 ULONG i;
938 PKPCR Pcr;
939 KAFFINITY ProcessorMask;
940
941 DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread, Affinity);
942
943 ASSERT(Affinity & ((1 << KeNumberProcessors) - 1));
944
945 oldIrql = KeAcquireDispatcherDatabaseLock();
946
947 Thread->UserAffinity = Affinity;
948 if (Thread->SystemAffinityActive == FALSE)
949 {
950 Thread->Affinity = Affinity;
951 if (Thread->State == THREAD_STATE_RUNNING)
952 {
953 ProcessorMask = 1 << KeGetCurrentKPCR()->ProcessorNumber;
954 if (Thread == KeGetCurrentThread())
955 {
956 if (!(Affinity & ProcessorMask))
957 {
958 PsDispatchThreadNoLock(THREAD_STATE_READY);
959 KeLowerIrql(oldIrql);
960 return STATUS_SUCCESS;
961 }
962 }
963 else
964 {
965 for (i = 0; i < KeNumberProcessors; i++)
966 {
967 Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE);
968 if (Pcr->Prcb->CurrentThread == Thread)
969 {
970 if (!(Affinity & ProcessorMask))
971 {
972 KeReleaseDispatcherDatabaseLockFromDpcLevel();
973 KiRequestReschedule(i);
974 KeLowerIrql(oldIrql);
975 return STATUS_SUCCESS;
976 }
977 break;
978 }
979 }
980 ASSERT (i < KeNumberProcessors);
981 }
982 }
983 }
984 KeReleaseDispatcherDatabaseLock(oldIrql);
985 return STATUS_SUCCESS;
986 }
987
988
989 /**********************************************************************
990 * NtOpenThread/4
991 *
992 * @implemented
993 */
994 NTSTATUS STDCALL
995 NtOpenThread(OUT PHANDLE ThreadHandle,
996 IN ACCESS_MASK DesiredAccess,
997 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
998 IN PCLIENT_ID ClientId OPTIONAL)
999 {
1000 KPROCESSOR_MODE PreviousMode;
1001 CLIENT_ID SafeClientId;
1002 HANDLE hThread;
1003 NTSTATUS Status = STATUS_SUCCESS;
1004
1005 PAGED_CODE();
1006
1007 PreviousMode = ExGetPreviousMode();
1008
1009 if(PreviousMode != KernelMode)
1010 {
1011 _SEH_TRY
1012 {
1013 ProbeForWrite(ThreadHandle,
1014 sizeof(HANDLE),
1015 sizeof(ULONG));
1016 if(ClientId != NULL)
1017 {
1018 ProbeForRead(ClientId,
1019 sizeof(CLIENT_ID),
1020 sizeof(ULONG));
1021 SafeClientId = *ClientId;
1022 ClientId = &SafeClientId;
1023 }
1024 }
1025 _SEH_HANDLE
1026 {
1027 Status = _SEH_GetExceptionCode();
1028 }
1029 _SEH_END;
1030
1031 if(!NT_SUCCESS(Status))
1032 {
1033 return Status;
1034 }
1035 }
1036
1037 if(!((ObjectAttributes == NULL) ^ (ClientId == NULL)))
1038 {
1039 DPRINT("NtOpenThread should be called with either ObjectAttributes or ClientId!\n");
1040 return STATUS_INVALID_PARAMETER;
1041 }
1042
1043 if(ClientId != NULL)
1044 {
1045 PETHREAD Thread;
1046
1047 Status = PsLookupThreadByThreadId(ClientId->UniqueThread,
1048 &Thread);
1049 if(NT_SUCCESS(Status))
1050 {
1051 Status = ObInsertObject(Thread,
1052 NULL,
1053 DesiredAccess,
1054 0,
1055 NULL,
1056 &hThread);
1057
1058 ObDereferenceObject(Thread);
1059 }
1060 }
1061 else
1062 {
1063 Status = ObOpenObjectByName(ObjectAttributes,
1064 PsThreadType,
1065 NULL,
1066 PreviousMode,
1067 DesiredAccess,
1068 NULL,
1069 &hThread);
1070 }
1071
1072 if(NT_SUCCESS(Status))
1073 {
1074 _SEH_TRY
1075 {
1076 *ThreadHandle = hThread;
1077 }
1078 _SEH_HANDLE
1079 {
1080 Status = _SEH_GetExceptionCode();
1081 }
1082 _SEH_END;
1083 }
1084
1085 return Status;
1086 }
1087
1088 NTSTATUS STDCALL
1089 NtYieldExecution(VOID)
1090 {
1091 PsDispatchThread(THREAD_STATE_READY);
1092 return(STATUS_SUCCESS);
1093 }
1094
1095
1096 /*
1097 * NOT EXPORTED
1098 */
1099 NTSTATUS STDCALL
1100 NtTestAlert(VOID)
1101 {
1102 /* Check and Alert Thread if needed */
1103 return KeTestAlertThread(ExGetPreviousMode()) ? STATUS_ALERTED : STATUS_SUCCESS;
1104 }
1105
1106
1107 /*
1108 * @implemented
1109 */
1110 NTSTATUS STDCALL
1111 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid,
1112 OUT PEPROCESS *Process OPTIONAL,
1113 OUT PETHREAD *Thread)
1114 {
1115 PHANDLE_TABLE_ENTRY CidEntry;
1116 PETHREAD FoundThread;
1117
1118 PAGED_CODE();
1119
1120 ASSERT(Thread);
1121 ASSERT(Cid);
1122
1123 CidEntry = PsLookupCidHandle(Cid->UniqueThread, PsThreadType, (PVOID*)&FoundThread);
1124 if(CidEntry != NULL)
1125 {
1126 ObReferenceObject(FoundThread);
1127
1128 PsUnlockCidHandle(CidEntry);
1129
1130 if(Process != NULL)
1131 {
1132 *Process = FoundThread->ThreadsProcess;
1133 }
1134 *Thread = FoundThread;
1135 return STATUS_SUCCESS;
1136 }
1137
1138 return STATUS_INVALID_PARAMETER;
1139 }
1140
1141
1142 /*
1143 * @implemented
1144 */
1145 NTSTATUS STDCALL
1146 PsLookupThreadByThreadId(IN HANDLE ThreadId,
1147 OUT PETHREAD *Thread)
1148 {
1149 PHANDLE_TABLE_ENTRY CidEntry;
1150 PETHREAD FoundThread;
1151
1152 PAGED_CODE();
1153
1154 ASSERT(Thread);
1155
1156 CidEntry = PsLookupCidHandle(ThreadId, PsThreadType, (PVOID*)&FoundThread);
1157 if(CidEntry != NULL)
1158 {
1159 ObReferenceObject(FoundThread);
1160
1161 PsUnlockCidHandle(CidEntry);
1162
1163 *Thread = FoundThread;
1164 return STATUS_SUCCESS;
1165 }
1166
1167 return STATUS_INVALID_PARAMETER;
1168 }
1169
1170 /* EOF */