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