test: procobj.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# procobj.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     procobj.c
    00008
    00009 Abstract:
    00010
    00011     This module implements the machine independent functions to manipulate
    00012     the kernel process object. Functions are provided to initialize, attach,
    00013     detach, exclude, include, and set the base priority of process objects.
    00014
    00015 Author:
    00016
    00017     David N. Cutler (davec) 7-Mar-1989
    00018
    00019 Environment:
    00020
    00021     Kernel mode only.
    00022
    00023 Revision History:
    00024
    00025 --*/
    00026
    00027 #include "ki.h"
    00028
    00029 #ifdef ALLOC_PRAGMA
    00030 #pragma alloc_text(PAGE, KeInitializeProcess)
    00031 #endif
    00032
    00033
    00034 //
    00035 // Define forward referenced function prototypes.
    00036 //
    00037
    00038 VOID
    00039 KiAttachProcess (
    00040     IN PRKTHREAD Thread,
    00041     IN PRKPROCESS Process,
    00042     IN KIRQL OldIrql,
    00043     OUT PRKAPC_STATE SavedApcState
    00044     );
    00045
    00046 VOID
    00047 KiMoveApcState (
    00048     IN PKAPC_STATE Source,
    00049     OUT PKAPC_STATE Destination
    00050     );
    00051
    00052 //
    00053 // The following assert macro is used to check that an input process is
    00054 // really a kprocess and not something else, like deallocated pool.
    00055 //
    00056
    00057 #define ASSERT_PROCESS(E) {             \
    00058     ASSERT((E)->Header.Type == ProcessObject); \
    00059 }
    00060
    00061
    00062 VOID
    00063 KeInitializeProcess (
    00064     IN PRKPROCESS Process,
    00065     IN KPRIORITY BasePriority,
    00066     IN KAFFINITY Affinity,
    00067     IN ULONG_PTR DirectoryTableBase[2],
    00068     IN BOOLEAN Enable
    00069     )
    00070
    00071 /*++
    00072
    00073 Routine Description:
    00074
    00075     This function initializes a kernel process object. The base priority,
    00076     affinity, and page frame numbers for the process page table directory
    00077     and hyper space are stored in the process object.
    00078
    00079     N.B. It is assumed that the process object is zeroed.
    00080
    00081 Arguments:
    00082
    00083     Process - Supplies a pointer to a dispatcher object of type process.
    00084
    00085     BasePriority - Supplies the base priority of the process.
    00086
    00087     Affinity - Supplies the set of processors on which children threads
    00088         of the process can execute.
    00089
    00090     DirectoryTableBase - Supplies a pointer to an array whose fist element
    00091         is the value that is to be loaded into the Directory Table Base
    00092         register when a child thread is dispatched for execution and whose
    00093         second element contains the page table entry that maps hyper space.
    00094
    00095     Enable - Supplies a boolean value that determines the default
    00096         handling of data alignment exceptions for child threads. A value
    00097         of TRUE causes all data alignment exceptions to be automatically
    00098         handled by the kernel. A value of FALSE causes all data alignment
    00099         exceptions to be actually raised as exceptions.
    00100
    00101 Return Value:
    00102
    00103     None.
    00104
    00105 --*/
    00106
    00107 {
    00108
    00109     //
    00110     // Initialize the standard dispatcher object header and set the initial
    00111     // signal state of the process object.
    00112     //
    00113
    00114     Process->Header.Type = ProcessObject;
    00115     Process->Header.Size = sizeof(KPROCESS) / sizeof(LONG);
    00116     InitializeListHead(&Process->Header.WaitListHead);
    00117
    00118     //
    00119     // Initialize the base priority, affinity, directory table base values,
    00120     // autoalignment, and stack count.
    00121     //
    00122     // N.B. The distinguished value MAXSHORT is used to signify that no
    00123     //      threads have been created for the process.
    00124     //
    00125
    00126     Process->BasePriority = (SCHAR)BasePriority;
    00127     Process->Affinity = Affinity;
    00128     Process->AutoAlignment = Enable;
    00129     Process->DirectoryTableBase[0] = DirectoryTableBase[0];
    00130     Process->DirectoryTableBase[1] = DirectoryTableBase[1];
    00131     Process->StackCount = MAXSHORT;
    00132
    00133     //
    00134     // Initialize the stack count, profile listhead, ready queue list head,
    00135     // accumulated runtime, process quantum, thread quantum, and thread list
    00136     // head.
    00137     //
    00138
    00139     InitializeListHead(&Process->ProfileListHead);
    00140     InitializeListHead(&Process->ReadyListHead);
    00141     InitializeListHead(&Process->ThreadListHead);
    00142     Process->ThreadQuantum = THREAD_QUANTUM;
    00143
    00144     //
    00145     // Initialize the process state and set the thread processor selection
    00146     // seed.
    00147     //
    00148
    00149     Process->State = ProcessInMemory;
    00150     Process->ThreadSeed = (UCHAR)KiQueryLowTickCount();
    00151
    00152     //
    00153     // Initialize IopmBase and Iopl flag for this process (i386 only)
    00154     //
    00155
    00156 #ifdef i386
    00157
    00158     Process->IopmOffset = KiComputeIopmOffset(IO_ACCESS_MAP_NONE);
    00159
    00160 #endif
    00161
    00162     return;
    00163 }
    00164
    00165 VOID
    00166 KeAttachProcess (
    00167     IN PRKPROCESS Process
    00168     )
    00169
    00170 /*++
    00171
    00172 Routine Description:
    00173
    00174     This function attaches a thread to a target process' address space
    00175     if, and only if, there is not already a process attached.
    00176
    00177 Arguments:
    00178
    00179     Process - Supplies a pointer to a dispatcher object of type process.
    00180
    00181 Return Value:
    00182
    00183     None.
    00184
    00185 --*/
    00186
    00187 {
    00188
    00189     KIRQL OldIrql;
    00190     PRKTHREAD Thread;
    00191
    00192     ASSERT_PROCESS(Process);
    00193     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00194
    00195     //
    00196     // Raise IRQL to dispatcher level and lock dispatcher database.
    00197     //
    00198
    00199     Thread = KeGetCurrentThread();
    00200     KiLockDispatcherDatabase(&OldIrql);
    00201
    00202     //
    00203     // If the target process is the current process, then return immediately.
    00204     // Otherwise, check whether there is a process address space attached or
    00205     // the thread is executing a DPC. If either condition is true, then call
    00206     // bug check. Otherwise, attach the target process.
    00207     //
    00208
    00209     if (Thread->ApcState.Process == Process) {
    00210         KiUnlockDispatcherDatabase(OldIrql);
    00211
    00212     } else if ((Thread->ApcStateIndex != 0) ||
    00213                (KeIsExecutingDpc() != FALSE)) {
    00214         KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
    00215                      (ULONG_PTR)Process,
    00216                      (ULONG_PTR)Thread->ApcState.Process,
    00217                      (ULONG)Thread->ApcStateIndex,
    00218                      (ULONG)KeIsExecutingDpc());
    00219
    00220     } else {
    00221         KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
    00222     }
    00223
    00224     return;
    00225 }
    00226
    00227 LOGICAL
    00228 KeForceAttachProcess (
    00229     IN PRKPROCESS Process
    00230     )
    00231
    00232 /*++
    00233
    00234 Routine Description:
    00235
    00236     This function forces an attach of a thread to a target process' address
    00237     space if the process is not current being swapped into or out of memory.
    00238
    00239     N.B. This function is for use by memory management ONLY.
    00240
    00241 Arguments:
    00242
    00243     Process - Supplies a pointer to a dispatcher object of type process.
    00244
    00245 Return Value:
    00246
    00247     None.
    00248
    00249 --*/
    00250
    00251 {
    00252
    00253     KIRQL OldIrql;
    00254     PRKTHREAD Thread;
    00255
    00256     ASSERT_PROCESS(Process);
    00257     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00258
    00259     //
    00260     // Raise IRQL to dispatcher level and lock dispatcher database.
    00261     //
    00262
    00263     Thread = KeGetCurrentThread();
    00264     KiLockDispatcherDatabase(&OldIrql);
    00265
    00266     //
    00267     // Check whether there is already a process address space attached or
    00268     // the thread is executing a DPC. If either condition is true, then call
    00269     // bug check.
    00270     //
    00271
    00272     if ((Thread->ApcStateIndex != 0) ||
    00273         (KeIsExecutingDpc() != FALSE)) {
    00274         KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
    00275                      (ULONG_PTR)Process,
    00276                      (ULONG_PTR)Thread->ApcState.Process,
    00277                      (ULONG)Thread->ApcStateIndex,
    00278                      (ULONG)KeIsExecutingDpc());
    00279     }
    00280
    00281     //
    00282     // If the target process is not the current process, then attach the target
    00283     // process if the process is not currently being swapped in or out of memory.
    00284     //
    00285
    00286     if (Thread->ApcState.Process == Process) {
    00287         KiUnlockDispatcherDatabase(OldIrql);
    00288
    00289     } else {
    00290
    00291         //
    00292         // If the target process is currently being swapped into or out of memory,
    00293         // then return a value of FALSE. Otherwise, force the process to be inswapped.
    00294         //
    00295
    00296         if ((Process->State == ProcessInSwap) || Process->State == ProcessOutSwap) {
    00297             KiUnlockDispatcherDatabase(OldIrql);
    00298             return FALSE;
    00299
    00300         } else {
    00301
    00302             //
    00303             // If the target process is in transition, then remove it from its
    00304             // transition list.
    00305             //
    00306
    00307             if (Process->State == ProcessInTransition) {
    00308                 RemoveEntryList(&Process->SwapListEntry);
    00309             }
    00310
    00311             //
    00312             // Force the process state to in memory and attach the target process.
    00313             //
    00314
    00315             Process->State = ProcessInMemory;
    00316             KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
    00317         }
    00318     }
    00319
    00320     return TRUE;
    00321 }
    00322
    00323 VOID
    00324 KeStackAttachProcess (
    00325     IN PRKPROCESS Process,
    00326     OUT PRKAPC_STATE ApcState
    00327     )
    00328
    00329 /*++
    00330
    00331 Routine Description:
    00332
    00333     This function attaches a thread to a target process' address space
    00334     and returns information about a previous attached process.
    00335
    00336 Arguments:
    00337
    00338     Process - Supplies a pointer to a dispatcher object of type process.
    00339
    00340 Return Value:
    00341
    00342     None.
    00343
    00344 --*/
    00345
    00346 {
    00347
    00348     KIRQL OldIrql;
    00349     PRKTHREAD Thread;
    00350
    00351     ASSERT_PROCESS(Process);
    00352     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00353
    00354     //
    00355     // Raise IRQL to dispatcher level and lock dispatcher database.
    00356     //
    00357
    00358     Thread = KeGetCurrentThread();
    00359     KiLockDispatcherDatabase(&OldIrql);
    00360
    00361     //
    00362     // If the current thread is executing a DPC, then bug check.
    00363     //
    00364
    00365     if (KeIsExecutingDpc() != FALSE) {
    00366         KeBugCheckEx(INVALID_PROCESS_ATTACH_ATTEMPT,
    00367                      (ULONG_PTR)Process,
    00368                      (ULONG_PTR)Thread->ApcState.Process,
    00369                      (ULONG)Thread->ApcStateIndex,
    00370                      (ULONG)KeIsExecutingDpc());
    00371     }
    00372
    00373     //
    00374     // If the target process is not the current process, then attach the target
    00375     // process. Otherwise, return a distinguished process value to indicate that
    00376     // an attach was not performed.
    00377     //
    00378
    00379     if (Thread->ApcState.Process == Process) {
    00380         KiUnlockDispatcherDatabase(OldIrql);
    00381         ApcState->Process = (PRKPROCESS)1;
    00382
    00383     } else {
    00384
    00385         //
    00386         // If the current thread is attached to a process, then save the current
    00387         // APC state in the callers APC state structure. Otherwise, save the
    00388         // current APC state in the saved APC state structure, and return a NULL
    00389         // process pointer.
    00390         //
    00391
    00392         if (Thread->ApcStateIndex != 0) {
    00393             KiAttachProcess(Thread, Process, OldIrql, ApcState);
    00394
    00395         } else {
    00396             KiAttachProcess(Thread, Process, OldIrql, &Thread->SavedApcState);
    00397             ApcState->Process = NULL;
    00398         }
    00399     }
    00400
    00401     return;
    00402 }
    00403
    00404 VOID
    00405 KeDetachProcess (
    00406     VOID
    00407     )
    00408
    00409 /*++
    00410
    00411 Routine Description:
    00412
    00413     This function detaches a thread from another process' address space.
    00414
    00415 Arguments:
    00416
    00417     None.
    00418
    00419 Return Value:
    00420
    00421     None.
    00422
    00423 --*/
    00424
    00425 {
    00426
    00427     KIRQL OldIrql;
    00428     PKPROCESS Process;
    00429     PKTHREAD Thread;
    00430
    00431     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00432
    00433     //
    00434     // Raise IRQL to dispatcher level and lock dispatcher database.
    00435     //
    00436
    00437     Thread = KeGetCurrentThread();
    00438     KiLockDispatcherDatabase(&OldIrql);
    00439
    00440     //
    00441     // If the current thread is attached to another process, then detach
    00442     // it.
    00443     //
    00444
    00445     if (Thread->ApcStateIndex != 0) {
    00446
    00447         //
    00448         // Check if a kernel APC is in progress, the kernel APC queue is
    00449         // not empty, or the user APC queue is not empty. If any of these
    00450         // conditions are true, then call bug check.
    00451         //
    00452
    00453 #if DBG
    00454
    00455         if ((Thread->ApcState.KernelApcInProgress) ||
    00456             (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) ||
    00457             (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]) == FALSE)) {
    00458             KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT);
    00459         }
    00460
    00461 #endif
    00462
    00463         //
    00464         // Unbias current process stack count and check if the process should
    00465         // be swapped out of memory.
    00466         //
    00467
    00468         Process = Thread->ApcState.Process;
    00469         Process->StackCount -= 1;
    00470         if ((Process->StackCount == 0) &&
    00471             (IsListEmpty(&Process->ThreadListHead) == FALSE)) {
    00472             Process->State = ProcessInTransition;
    00473             InsertTailList(&KiProcessOutSwapListHead, &Process->SwapListEntry);
    00474             KiSwapEvent.Header.SignalState = 1;
    00475             if (IsListEmpty(&KiSwapEvent.Header.WaitListHead) == FALSE) {
    00476                 KiWaitTest(&KiSwapEvent, BALANCE_INCREMENT);
    00477             }
    00478         }
    00479
    00480         //
    00481         // Restore APC state and check whether the kernel APC queue contains
    00482         // an entry. If the kernel APC queue contains an entry then set kernel
    00483         // APC pending and request a software interrupt at APC_LEVEL.
    00484         //
    00485
    00486         KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
    00487         Thread->SavedApcState.Process = (PKPROCESS)NULL;
    00488         Thread->ApcStatePointer[0] = &Thread->ApcState;
    00489         Thread->ApcStatePointer[1] = &Thread->SavedApcState;
    00490         Thread->ApcStateIndex = 0;
    00491         if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) {
    00492             Thread->ApcState.KernelApcPending = TRUE;
    00493             KiRequestSoftwareInterrupt(APC_LEVEL);
    00494         }
    00495
    00496         //
    00497         // Swap the address space back to the parent process.
    00498         //
    00499
    00500         KiSwapProcess(Thread->ApcState.Process, Process);
    00501     }
    00502
    00503     //
    00504     // Lower IRQL to its previous value and return.
    00505     //
    00506
    00507     KiUnlockDispatcherDatabase(OldIrql);
    00508     return;
    00509 }
    00510
    00511 VOID
    00512 KeUnstackDetachProcess (
    00513     IN PRKAPC_STATE ApcState
    00514     )
    00515
    00516 /*++
    00517
    00518 Routine Description:
    00519
    00520     This function detaches a thread from another process' address space
    00521     and restores previous attach state.
    00522
    00523 Arguments:
    00524
    00525     ApcState - Supplies a pointer to an APC state structure that was returned
    00526         from a previous call to stack attach process.
    00527
    00528 Return Value:
    00529
    00530     None.
    00531
    00532 --*/
    00533
    00534 {
    00535
    00536     KIRQL OldIrql;
    00537     PKPROCESS Process;
    00538     PKTHREAD Thread;
    00539
    00540     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00541
    00542     //
    00543     // Raise IRQL to dispatcher level and lock dispatcher database.
    00544     //
    00545
    00546     Thread = KeGetCurrentThread();
    00547     KiLockDispatcherDatabase(&OldIrql);
    00548
    00549     //
    00550     // If the APC state has a distinguished process pointer value, then no
    00551     // attach was performed on the paired call to stack attach process.
    00552     //
    00553
    00554     if (ApcState->Process != (PRKPROCESS)1) {
    00555
    00556         //
    00557         // If the current thread is not attached to another process, a kernel
    00558         // APC is in progress, or either the kernel or user mode APC queues
    00559         // are not empty, then call bug check.
    00560         //
    00561
    00562         if ((Thread->ApcStateIndex == 0) ||
    00563              (Thread->ApcState.KernelApcInProgress) ||
    00564              (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) ||
    00565              (IsListEmpty(&Thread->ApcState.ApcListHead[UserMode]) == FALSE)) {
    00566             KeBugCheck(INVALID_PROCESS_DETACH_ATTEMPT);
    00567         }
    00568
    00569         //
    00570         // Unbias current process stack count and check if the process should
    00571         // be swapped out of memory.
    00572         //
    00573
    00574         Process = Thread->ApcState.Process;
    00575         Process->StackCount -= 1;
    00576         if ((Process->StackCount == 0) &&
    00577             (IsListEmpty(&Process->ThreadListHead) == FALSE)) {
    00578             Process->State = ProcessInTransition;
    00579             InsertTailList(&KiProcessOutSwapListHead, &Process->SwapListEntry);
    00580             KiSwapEvent.Header.SignalState = 1;
    00581             if (IsListEmpty(&KiSwapEvent.Header.WaitListHead) == FALSE) {
    00582                 KiWaitTest(&KiSwapEvent, BALANCE_INCREMENT);
    00583             }
    00584         }
    00585
    00586         //
    00587         // Restore APC state and check whether the kernel APC queue contains
    00588         // an entry. If the kernel APC queue contains an entry then set kernel
    00589         // APC pending and request a software interrupt at APC_LEVEL.
    00590         //
    00591
    00592         if (ApcState->Process != NULL) {
    00593             KiMoveApcState(ApcState, &Thread->ApcState);
    00594
    00595         } else {
    00596             KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
    00597             Thread->SavedApcState.Process = (PKPROCESS)NULL;
    00598             Thread->ApcStatePointer[0] = &Thread->ApcState;
    00599             Thread->ApcStatePointer[1] = &Thread->SavedApcState;
    00600             Thread->ApcStateIndex = 0;
    00601         }
    00602
    00603         if (IsListEmpty(&Thread->ApcState.ApcListHead[KernelMode]) == FALSE) {
    00604             Thread->ApcState.KernelApcPending = TRUE;
    00605             KiRequestSoftwareInterrupt(APC_LEVEL);
    00606         }
    00607
    00608         //
    00609         // Swap the address space back to the parent process.
    00610         //
    00611
    00612         KiSwapProcess(Thread->ApcState.Process, Process);
    00613     }
    00614
    00615     //
    00616     // Lower IRQL to its previous value and return.
    00617     //
    00618
    00619     KiUnlockDispatcherDatabase(OldIrql);
    00620     return;
    00621 }
    00622
    00623 LONG
    00624 KeReadStateProcess (
    00625     IN PRKPROCESS Process
    00626     )
    00627
    00628 /*++
    00629
    00630 Routine Description:
    00631
    00632     This function reads the current signal state of a process object.
    00633
    00634 Arguments:
    00635
    00636     Process - Supplies a pointer to a dispatcher object of type process.
    00637
    00638 Return Value:
    00639
    00640     The current signal state of the process object.
    00641
    00642 --*/
    00643
    00644 {
    00645
    00646     ASSERT_PROCESS(Process);
    00647
    00648     //
    00649     // Return current signal state of process object.
    00650     //
    00651
    00652     return Process->Header.SignalState;
    00653 }
    00654
    00655 LONG
    00656 KeSetProcess (
    00657     IN PRKPROCESS Process,
    00658     IN KPRIORITY Increment,
    00659     IN BOOLEAN Wait
    00660     )
    00661
    00662 /*++
    00663
    00664 Routine Description:
    00665
    00666     This function sets the signal state of a proces object to Signaled
    00667     and attempts to satisfy as many Waits as possible. The previous
    00668     signal state of the process object is returned as the function value.
    00669
    00670 Arguments:
    00671
    00672     Process - Supplies a pointer to a dispatcher object of type process.
    00673
    00674     Increment - Supplies the priority increment that is to be applied
    00675        if setting the process causes a Wait to be satisfied.
    00676
    00677     Wait - Supplies a boolean value that signifies whether the call to
    00678        KeSetProcess will be immediately followed by a call to one of the
    00679        kernel Wait functions.
    00680
    00681 Return Value:
    00682
    00683     The previous signal state of the process object.
    00684
    00685 --*/
    00686
    00687 {
    00688
    00689     KIRQL OldIrql;
    00690     LONG OldState;
    00691     PRKTHREAD Thread;
    00692
    00693     ASSERT_PROCESS(Process);
    00694     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00695
    00696     //
    00697     // Raise IRQL to dispatcher level and lock dispatcher database.
    00698     //
    00699
    00700     KiLockDispatcherDatabase(&OldIrql);
    00701
    00702     //
    00703     // If the previous state of the process object is Not-Signaled and
    00704     // the wait queue is not empty, then satisfy as many Waits as
    00705     // possible.
    00706     //
    00707
    00708     OldState = Process->Header.SignalState;
    00709     Process->Header.SignalState = 1;
    00710     if ((OldState == 0) && (!IsListEmpty(&Process->Header.WaitListHead))) {
    00711         KiWaitTest(Process, Increment);
    00712     }
    00713
    00714     //
    00715     // If the value of the Wait argument is TRUE, then return to the
    00716     // caller with IRQL raised and the dispatcher database locked. Else
    00717     // release the dispatcher database lock and lower IRQL to its
    00718     // previous value.
    00719     //
    00720
    00721     if (Wait) {
    00722         Thread = KeGetCurrentThread();
    00723         Thread->WaitNext = Wait;
    00724         Thread->WaitIrql = OldIrql;
    00725
    00726     } else {
    00727         KiUnlockDispatcherDatabase(OldIrql);
    00728     }
    00729
    00730     //
    00731     // Return previous signal state of process object.
    00732     //
    00733
    00734     return OldState;
    00735 }
    00736
    00737 KPRIORITY
    00738 KeSetPriorityProcess (
    00739     IN PKPROCESS Process,
    00740     IN KPRIORITY NewBase
    00741     )
    00742
    00743 /*++
    00744
    00745 Routine Description:
    00746
    00747     This function set the base priority of a process to a new value
    00748     and adjusts the priority and base priority of all child threads
    00749     as appropriate.
    00750
    00751 Arguments:
    00752
    00753     Process - Supplies a pointer to a dispatcher object of type process.
    00754
    00755     NewBase - Supplies the new base priority of the process.
    00756
    00757 Return Value:
    00758
    00759     The previous base priority of the process.
    00760
    00761 --*/
    00762
    00763 {
    00764
    00765     KPRIORITY Adjustment;
    00766     PLIST_ENTRY NextEntry;
    00767     KPRIORITY NewPriority;
    00768     KIRQL OldIrql;
    00769     KPRIORITY OldBase;
    00770     PKTHREAD Thread;
    00771
    00772     ASSERT_PROCESS(Process);
    00773     ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
    00774
    00775     //
    00776     // Raise IRQL to dispatcher level and lock dispatcher database.
    00777     //
    00778
    00779     KiLockDispatcherDatabase(&OldIrql);
    00780
    00781     //
    00782     // Save the current process base priority, set the new process base
    00783     // priority, compute the adjustment value, and adjust the priority
    00784     // and base priority of all child threads as appropriate.
    00785     //
    00786
    00787     OldBase = Process->BasePriority;
    00788     Process->BasePriority = (SCHAR)NewBase;
    00789     Adjustment = NewBase - OldBase;
    00790     NextEntry = Process->ThreadListHead.Flink;
    00791     if (NewBase >= LOW_REALTIME_PRIORITY) {
    00792         while (NextEntry != &Process->ThreadListHead) {
    00793             Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
    00794
    00795             //
    00796             // Compute the new base priority of the thread.
    00797             //
    00798
    00799             NewPriority = Thread->BasePriority + Adjustment;
    00800
    00801             //
    00802             // If the new base priority is outside the realtime class,
    00803             // then limit the change to the realtime class.
    00804             //
    00805
    00806             if (NewPriority < LOW_REALTIME_PRIORITY) {
    00807                 NewPriority = LOW_REALTIME_PRIORITY;
    00808
    00809             } else if (NewPriority > HIGH_PRIORITY) {
    00810                 NewPriority = HIGH_PRIORITY;
    00811             }
    00812
    00813             //
    00814             // Set the base priority and the current priority of the
    00815             // thread to the appropriate value.
    00816             //
    00817             // N.B. If priority saturation occured the last time the thread
    00818             //      base priority was set and the new process base priority
    00819             //      is not crossing from variable to realtime, then it is not
    00820             //      necessary to change the thread priority.
    00821             //
    00822
    00823             if ((Thread->Saturation == 0) || (OldBase < LOW_REALTIME_PRIORITY)) {
    00824                 if (Thread->Saturation > 0) {
    00825                     NewPriority = HIGH_PRIORITY;
    00826
    00827                 } else if (Thread->Saturation < 0) {
    00828                     NewPriority = LOW_REALTIME_PRIORITY;
    00829                 }
    00830
    00831                 Thread->BasePriority = (SCHAR)NewPriority;
    00832                 Thread->Quantum = Process->ThreadQuantum;
    00833                 Thread->DecrementCount = 0;
    00834                 Thread->PriorityDecrement = 0;
    00835                 KiSetPriorityThread(Thread, NewPriority);
    00836             }
    00837
    00838             NextEntry = NextEntry->Flink;
    00839         }
    00840
    00841     } else {
    00842         while (NextEntry != &Process->ThreadListHead) {
    00843             Thread = CONTAINING_RECORD(NextEntry, KTHREAD, ThreadListEntry);
    00844
    00845             //
    00846             // Compute the new base priority of the thread.
    00847             //
    00848
    00849             NewPriority = Thread->BasePriority + Adjustment;
    00850
    00851             //
    00852             // If the new base priority is outside the variable class,
    00853             // then limit the change to the variable class.
    00854             //
    00855
    00856             if (NewPriority >= LOW_REALTIME_PRIORITY) {
    00857                 NewPriority = LOW_REALTIME_PRIORITY - 1;
    00858
    00859             } else if (NewPriority <= LOW_PRIORITY) {
    00860                 NewPriority = 1;
    00861             }
    00862
    00863             //
    00864             // Set the base priority and the current priority of the
    00865             // thread to the computed value and reset the thread quantum.
    00866             //
    00867             // N.B. If priority saturation occured the last time the thread
    00868             //      base priority was set and the new process base priority
    00869             //      is not crossing from realtime to variable, then it is not
    00870             //      necessary to change the thread priority.
    00871             //
    00872
    00873             if ((Thread->Saturation == 0) || (OldBase >= LOW_REALTIME_PRIORITY)) {
    00874                 if (Thread->Saturation > 0) {
    00875                     NewPriority = LOW_REALTIME_PRIORITY - 1;
    00876
    00877                 } else if (Thread->Saturation < 0) {
    00878                     NewPriority = 1;
    00879                 }
    00880
    00881                 Thread->BasePriority = (SCHAR)NewPriority;
    00882                 Thread->Quantum = Process->ThreadQuantum;
    00883                 Thread->DecrementCount = 0;
    00884                 Thread->PriorityDecrement = 0;
    00885                 KiSetPriorityThread(Thread, NewPriority);
    00886             }
    00887
    00888             NextEntry = NextEntry->Flink;
    00889         }
    00890     }
    00891
    00892     //
    00893     // Unlock dispatcher database and lower IRQL to its previous
    00894     // value.
    00895     //
    00896
    00897     KiUnlockDispatcherDatabase(OldIrql);
    00898
    00899     //
    00900     // Return previous process base priority
    00901     //
    00902
    00903     return OldBase;
    00904 }
    00905
    00906 LOGICAL
    00907 KeSetDisableQuantumProcess (
    00908     IN PKPROCESS Process,
    00909     IN LOGICAL Disable
    00910     )
    00911
    00912 /*++
    00913
    00914 Routine Description:
    00915
    00916     This function disables quantum runout for realtime threads in the
    00917     specified process.
    00918
    00919 Arguments:
    00920
    00921     Process  - Supplies a pointer to a dispatcher object of type process.
    00922
    00923     Disable - Supplies a logical value that determines whether quantum
    00924         runout for realtime threads in the specified process are disabled
    00925         or enabled.
    00926
    00927 Return Value:
    00928
    00929     The previous value of the disable quantum state variable.
    00930
    00931 --*/
    00932
    00933 {
    00934
    00935     LOGICAL DisableQuantum;
    00936
    00937     ASSERT_PROCESS(Process);
    00938
    00939     //
    00940     // Capture the current state of the disable boost variable and set its
    00941     // state to TRUE.
    00942     //
    00943
    00944     DisableQuantum = Process->DisableQuantum;
    00945     Process->DisableQuantum = (BOOLEAN)Disable;
    00946
    00947     //
    00948     // Return the previous disable quantum state.
    00949     //
    00950
    00951     return DisableQuantum;
    00952 }
    00953
    00954 VOID
    00955 KiAttachProcess (
    00956     IN PRKTHREAD Thread,
    00957     IN PKPROCESS Process,
    00958     IN KIRQL OldIrql,
    00959     OUT PRKAPC_STATE SavedApcState
    00960     )
    00961
    00962 /*++
    00963
    00964 Routine Description:
    00965
    00966     This function attaches a thread to a target process' address space.
    00967
    00968     N.B. The dispatcher database lock must be held when this routine is
    00969         called.
    00970
    00971 Arguments:
    00972
    00973     Thread - Supplies a pointer to a dispatcher object of type thread.
    00974
    00975     Process - Supplies a pointer to a dispatcher object of type process.
    00976
    00977     OldIrql - Supplies the previous IRQL.
    00978
    00979     SavedApcState - Supplies a pointer to the APC state structure that receives
    00980         the saved APC state.
    00981
    00982 Return Value:
    00983
    00984     None.
    00985
    00986 --*/
    00987
    00988 {
    00989
    00990     PRKTHREAD OutThread;
    00991     KAFFINITY Processor;
    00992     PLIST_ENTRY NextEntry;
    00993     KIRQL HighIrql;
    00994
    00995     ASSERT(Process != Thread->ApcState.Process);
    00996
    00997     //
    00998     // Bias the stack count of the target process to signify that a
    00999     // thread exists in that process with a stack that is resident.
    01000     //
    01001
    01002     Process->StackCount += 1;
    01003
    01004     //
    01005     // Save current APC state and initialize a new APC state.
    01006     //
    01007
    01008     KiMoveApcState(&Thread->ApcState, SavedApcState);
    01009     InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]);
    01010     InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]);
    01011     Thread->ApcState.Process = Process;
    01012     Thread->ApcState.KernelApcInProgress = FALSE;
    01013     Thread->ApcState.KernelApcPending = FALSE;
    01014     Thread->ApcState.UserApcPending = FALSE;
    01015     if (SavedApcState == &Thread->SavedApcState) {
    01016         Thread->ApcStatePointer[0] = &Thread->SavedApcState;
    01017         Thread->ApcStatePointer[1] = &Thread->ApcState;
    01018         Thread->ApcStateIndex = 1;
    01019     }
    01020
    01021     //
    01022     // If the target process is in memory, then immediately enter the
    01023     // new address space by loading a new Directory Table Base. Otherwise,
    01024     // insert the current thread in the target process ready list, inswap
    01025     // the target process if necessary, select a new thread to run on the
    01026     // the current processor and context switch to the new thread.
    01027     //
    01028
    01029     if (Process->State == ProcessInMemory) {
    01030
    01031         //
    01032         // It is possible that the process is in memory, but there exist
    01033         // threads in the process ready list. This can happen when memory
    01034         // management forces a process attach.
    01035         //
    01036
    01037         NextEntry = Process->ReadyListHead.Flink;
    01038         while (NextEntry != &Process->ReadyListHead) {
    01039             OutThread = CONTAINING_RECORD(NextEntry, KTHREAD, WaitListEntry);
    01040             RemoveEntryList(NextEntry);
    01041             OutThread->ProcessReadyQueue = FALSE;
    01042             KiReadyThread(OutThread);
    01043             NextEntry = Process->ReadyListHead.Flink;
    01044         }
    01045
    01046         KiSwapProcess(Process, SavedApcState->Process);
    01047         KiUnlockDispatcherDatabase(OldIrql);
    01048
    01049     } else {
    01050         Thread->State = Ready;
    01051         Thread->ProcessReadyQueue = TRUE;
    01052         InsertTailList(&Process->ReadyListHead, &Thread->WaitListEntry);
    01053         if (Process->State == ProcessOutOfMemory) {
    01054             Process->State = ProcessInTransition;
    01055             InsertTailList(&KiProcessInSwapListHead, &Process->SwapListEntry);
    01056             KiSwapEvent.Header.SignalState = 1;
    01057             if (IsListEmpty(&KiSwapEvent.Header.WaitListHead) == FALSE) {
    01058                 KiWaitTest(&KiSwapEvent, BALANCE_INCREMENT);
    01059             }
    01060         }
    01061
    01062         //
    01063         // Clear the active processor bit in the previous process and
    01064         // set active processor bit in the process being attached to.
    01065         //
    01066
    01067 #if !defined(NT_UP)
    01068
    01069         KiLockContextSwap(&HighIrql);
    01070         Processor = KeGetCurrentPrcb()->SetMember;
    01071         SavedApcState->Process->ActiveProcessors &= ~Processor;
    01072         Process->ActiveProcessors |= Processor;
    01073
    01074 #if defined(_ALPHA_)
    01075
    01076         Process->RunOnProcessors |= Processor;
    01077
    01078 #endif
    01079
    01080         KiUnlockContextSwap(HighIrql);
    01081
    01082 #endif
    01083
    01084         Thread->WaitIrql = OldIrql;
    01085         KiSwapThread();
    01086     }
    01087
    01088     return;
    01089 }
    01090
    01091 VOID
    01092 KiMoveApcState (
    01093     IN PKAPC_STATE Source,
    01094     OUT PKAPC_STATE Destination
    01095     )
    01096
    01097 /*++
    01098
    01099 Routine Description:
    01100
    01101     This function moves the APC state from the source structure to the
    01102     destination structure and reinitializes list headers as appropriate.
    01103
    01104 Arguments:
    01105
    01106     Source - Supplies a pointer to the source APC state structure.
    01107
    01108     Destination - Supplies a pointer to the destination APC state structure.
    01109
    01110
    01111 Return Value:
    01112
    01113     None.
    01114
    01115 --*/
    01116
    01117 {
    01118
    01119     PLIST_ENTRY First;
    01120     PLIST_ENTRY Last;
    01121
    01122     //
    01123     // Copy the APC state from the source to the destination.
    01124     //
    01125
    01126     *Destination = *Source;
    01127     if (IsListEmpty(&Source->ApcListHead[KernelMode]) != FALSE) {
    01128         InitializeListHead(&Destination->ApcListHead[KernelMode]);
    01129
    01130     } else {
    01131         First = Source->ApcListHead[KernelMode].Flink;
    01132         Last = Source->ApcListHead[KernelMode].Blink;
    01133         Destination->ApcListHead[KernelMode].Flink = First;
    01134         Destination->ApcListHead[KernelMode].Blink = Last;
    01135         First->Blink = &Destination->ApcListHead[KernelMode];
    01136         Last->Flink = &Destination->ApcListHead[KernelMode];
    01137     }
    01138
    01139     if (IsListEmpty(&Source->ApcListHead[UserMode]) != FALSE) {
    01140         InitializeListHead(&Destination->ApcListHead[UserMode]);
    01141
    01142     } else {
    01143         First = Source->ApcListHead[UserMode].Flink;
    01144         Last = Source->ApcListHead[UserMode].Blink;
    01145         Destination->ApcListHead[UserMode].Flink = First;
    01146         Destination->ApcListHead[UserMode].Blink = Last;
    01147         First->Blink = &Destination->ApcListHead[UserMode];
    01148         Last->Flink = &Destination->ApcListHead[UserMode];
    01149     }
    01150
    01151     return;
    01152 }
    01153