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