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