Inside Microsoft® Windows® 2000, Third Edition
David A. Solomon and Mark E. Russinovich
1 Companion CD(s)
To see this book's discounted price, select a reseller below.
Chapter 6: Processes, Threads, and Jobs (continued)
Flow of CreateProcess
So far in this chapter, you've seen the structures that are part
of a process and the API functions with which you (and the operating
system) can manipulate processes. You've also found out how you can
use tools to view how processes interact with your system. But how did
those processes come into being, and how do they exit once they've
fulfilled their purpose? In the following sections, you'll discover
how a Win32 process comes to life.
A Win32 process is created when an application calls one of the
process creation functions, such as CreateProcess,
CreateProcessAsUser, or CreateProcessWithLogonW.
Creating a Win32 process consists of several stages carried out in
three parts of the operating system: the Win32 client-side library
Kernel32.dll, the Windows 2000 executive, and the Win32 subsystem
process (Csrss). Because of the multiple environment subsystem
architecture of Windows 2000, creating a Windows 2000 executive process
object (which other subsystems can use) is separated from the work
involved in creating a Win32 process. So, although the following
description of the flow of the Win32 CreateProcess function is
complicated, keep in mind that part of the work is specific to the
semantics added by the Win32 subsystem as opposed to the core work
needed to create a Windows 2000 executive process object.
The following list summarizes the main stages of creating a process
with the Win32 CreateProcess function. The operations performed
in each stage are described in detail in the subsequent sections.
- Open the image file (.exe) to be executed inside the
- Create the Windows 2000 executive process object.
- Create the initial thread (stack, context, and Windows 2000 executive thread object).
- Notify the Win32 subsystem of the new process so that it can set
up for the new process and thread.
- Start execution of the initial thread (unless the CREATE_SUSPENDED flag was specified).
- In the context of the new process and thread, complete the
initialization of the address space (such as load required DLLs) and
begin execution of the program.
Figure 6-5 shows an overview of the stages Windows 2000 follows to
create a process.
Click to view graphic
Figure 6-5 The main stages of process creation
Before describing these stages in more detail, we should mention a
few notes that pertain to all the stages.
- In CreateProcess, the priority class for the new process
is specified as independent bits in the CreationFlags parameter.
Thus, you can specify more than one priority class for a single
CreateProcess call. Windows 2000 resolves the question of which
priority class to assign to the process by choosing the lowest-priority
- If no priority class is specified for the new process, the
priority class defaults to Normal unless the priority class of the
process that created it is Idle or Below Normal, in which case the
priority class of the new process will have the same priority as the
- If a Real-time priority class is specified for the new process
and the process's caller doesn't have the Increase Scheduling
Priority privilege, the High priority class is used instead. In other
words, CreateProcess doesn't fail just because the caller
has insufficient privileges to create the process in the Real-time
priority class; the new process just won't have as high a priority
- All windows are associated with desktops, the graphical
representation of a workspace. If no desktop is specified in
CreateProcess, the process is associated with the caller's
Enough background. The steps of CreateProcess are described
in detail in the following sections.
Many steps of CreateProcess are related
to the setup of the process virtual address space and hence refer to
many memory management terms and structures, which are defined in
Stage 1: Opening the Image to Be Executed
As illustrated in Figure 6-6, the first stage in
CreateProcess is to find the appropriate Win32 image that will run
the executable file specified by the caller and to create a section
object to later map it into the address space of the new process. If no
image name is specified, the first token of the command line (defined
to be the first part of the command-line string ending with a space or
tab that is a valid file specification) is used as the image
Click to view graphic
Figure 6-6 Choosing a Win32 image to activate
If the executable file specified is a Win32 .exe, it is used
directly. If it's not a Win32 .exe (for example, if it's an
MS-DOS, a Win16, a POSIX, or an OS/2 application), CreateProcess
goes through a series of steps to find a Win32 support image to
run it. This process is necessary because non-Win32 applications
aren't run directlyWindows 2000 instead uses one of a few
special support images that in turn are responsible for actually
running the non-Win32 program. For example, if you attempt to run a
POSIX application, CreateProcess identifies it as such and
changes the image to be run on the Win32 executable file Posix.exe. If
you attempt to run an MS-DOS or a Win16 executable, the image to be run
becomes the Win32 executable Ntvdm.exe. In short, you can't
directly create a process that is not a Win32 process. If
Windows 2000 can't find a way to resolve the activated image as a
Win32 process (as shown in Table 6-6), CreateProcess fails.
Table 6-6 Decision Tree for Stage 1 of CreateProcess
|If the image is a/an
||This image will run
||And this will happen
|POSIX executable file
||CreateProcess restarts Stage 1|
|OS/2 1.x image
||CreateProcess restarts Stage 1|
|MS-DOS application with an .exe, a .com, or a .pif extension
||CreateProcess restarts Stage 1|
||CreateProcess restarts Stage 1|
|Command procedure MS-DOS application with a .bat or a .cmd extension
||CreateProcess restarts Stage 1|
Specifically, the decision tree that CreateProcess goes
through to run an image is as follows:
- If the image is an OS/2 1.x application, the image to be run
changes to Os2.exe and CreateProcess restarts at Stage 1.
- If the image is an MS-DOS application with an .exe, a .com, or a
.pif extension, a message is sent to the Win32 subsystem to check
whether an MS-DOS support process (Ntvdm.exe, specified in the registry
value HKLM\SYSTEM\CurrentControlSet\Control\WOW\cmdline) has already been created for this session. If a support
process has been created, it is used to run the MS-DOS application (the
Win32 subsystem sends the message to the VDM [Virtual DOS Machine] process to run the new image) and CreateProcess
returns. If a support process hasn't been created, the image to be
run changes to Ntvdm.exe and CreateProcess restarts at Stage 1.
- If the file to run has a .bat or a .cmd extension, the image to
be run becomes Cmd.exe, the Windows 2000 command prompt, and
CreateProcess restarts at Stage 1. (The name of the batch file is
passed as the first parameter to Cmd.exe.)
- If the image is a Win16 (Windows 3.1) executable, CreateProcess must decide whether a new VDM process must be created
to run it or whether it should use the default systemwide shared VDM
process (which might not yet have been created). The CreateProcess flags CREATE_SEPARATE_WOW_VDM and CREATE_SHARED_WOW_VDM control this decision. If these flags aren't specified,
the registry value HKLM\SYSTEM\CurrentControlSet\Control\WOW\DefaultSeparateVDM dictates the default behavior. If the
application is to be run in a separate VDM, the image to be run changes
to the value of HKLM\SYSTEM\CurrentControlSet\Control\WOW\wowcmdline and CreateProcess restarts at Stage 1. Otherwise,
the Win32 subsystem sends a message to see whether the systemwide VDM
process exists and can be used. (If the VDM process is running on a
different desktop or isn't running under the same security as the
caller, it can't be used and a new VDM process must be created.) If
a systemwide VDM process can be used, the Win32 subsystem sends a
message to it to run the new image and CreateProcess returns. If
the VDM process hasn't yet been created (or if it exists but
can't be used), the image to be run changes to the VDM support
image and CreateProcess restarts at Stage 1.
At this point, CreateProcess has successfully opened a valid
Windows 2000 executable file and created a section object for it. The
object isn't mapped into memory yet, but it is open. Just because a
section object has been successfully created doesn't mean that the
file is a valid Win32 image, however; it could be a DLL or a POSIX
executable. If the file is a POSIX executable, the image to be run
changes to Posix.exe and CreateProcess restarts from the
beginning of Stage 1. If the file is a DLL, CreateProcess
Now that CreateProcess has found a valid Win32 executable, it
looks in the registry under HKLM\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Image File Execution Options to see whether a subkey with the filename
and extension of the executable image (but without the directory and
path informationfor example, Image.exe) exists there. If it does,
CreateProcess looks for a value named Debugger for that key. If
the value isn't null, the image to be run becomes the string in
that value and CreateProcess restarts at Stage 1.
You can take advantage of this CreateProcess behavior and debug the startup code of Windows 2000
service processes before they start rather than attach the debugger
after starting the service, which doesn't allow you to debug the
startup code. If you're feeling mischievous, you can also exploit
this behavior to confuse people by causing another file to be run
rather than the one they specified.
Stage 2: Creating the Windows 2000 Executive Process Object
At this point, CreateProcess has opened a valid Win32
executable file and created a section object to map it into the new
process address space. Next it creates a Windows 2000 executive process
object to run the image by calling the internal system function
NtCreateProcess. Creating the executive process object (which is
done by the creating thread) involves the following substages:
- Setting up the EPROCESS block
- Creating the initial process address space
- Creating the kernel process block
- Concluding the setup of the process address space
- Setting up the PEB
- Completing the setup of the executive process object
The only time there won't be a parent
process is during system initialization. After that point, a parent
process is always required in order to provide a security context for
the new process.
Stage 2A: Setting Up the EPROCESS Block
This substage involves five steps:
- Allocate and initialize the Windows 2000 EPROCESS block.
- Set the new process's quota block to the address of its
parent process's quota block, and increment the reference count for
the parent's quota block.
- Store the parent process's process ID and session ID (if
applicable) in the InheritedFromUniqueProcessId field in the new
- Set the new process's exit status to STATUS_PENDING.
- Create the process's primary access token (a duplicate of
its parent's primary token). New processes inherit the security
profile of their parent. If the CreateProcessAsUser function is
being used to specify a different access token for the new process, the
token is then changed appropriately.
Stage 2B: Creating the Initial Process Address Space
The initial process address space consists of three pages:
- Page directory
- Hyperspace page
- Working set list
To create these three pages, the following steps are taken:
- Page table entries are created in the appropriate page tables to
map the three initial pages.
- To account for these new pages, the value 3 is deducted from the
kernel variable MmTotalCommittedPages and added to
- The systemwide default process minimum working set size (PsMinimumWorkingSet) is deducted from MmResident-AvailablePages.
- The page table pages for the nonpaged portion of system space
and the system cache are mapped into the process.
- The process minimum and maximum working set size are set to the values of PsMinimumWorkingSet and PsMaximumWorkingSet, respectively.
Stage 2C: Creating the Kernel Process Block
The next stage of CreateProcess is the initialization of the
KPROCESS block, which contains a pointer to a list of kernel threads.
(The kernel has no knowledge of handles, so it bypasses the object
table.) The kernel process block also points to the process's page
table directory (used to keep track of the process's virtual
address space), the total time the process's threads have executed,
the process's default base-scheduling priority (which starts as
Normal, or 8, unless the parent process was set to Idle or Below
Normal, in which case the setting is inherited), the default processor
affinity for the threads in the process, and the initial value of the
process default quantum, which is taken from the value of
PspForegroundQuantum, the first entry in the systemwide quantum
The default initial quantum differs between
Windows 2000 Professional and Windows 2000 Server. For more information
on thread quantums, turn to their discussion in the section
Stage 2D: Concluding the Setup of the Process Address Space
Setting up the address space for a new process is somewhat
complicated, so let's look at what's involved one step at a
time. To get the most out of this section, you should have some
familiarity with the internals of the Windows 2000 memory manager,
which are described in Chapter 7.
- The virtual memory manager sets the value of the process's
last trim time to the current time. The working set manager (which runs
in the context of the balance set manager system thread) uses this
value to determine when to initiate working set trimming.
- The page frame number (PFN) database for the page directory as
well as the page directory entry, which maps hyperspace, are
- The memory manager initializes the process's working set
listpage faults can now be taken.
- The major and minor version numbers are copied from the
executable file to the EPROCESS block.
- The section (created when the image file was opened) is now
mapped into the new process's address space, and the process
section base address is set to the base address of the image.
- Ntdll.dll is mapped into the process.
- The systemwide national language support (NLS) tables are mapped
into the process's address space.
POSIX processes clone the address space of their
parents, so they don't have to go through these steps to create a
new address space. In the case of POSIX applications, the new
process's section base address is set to that of its parent process
and the parent's PEB is cloned for the new process.
- If the parent process was contained in a job, the new process is
added to the job. (Jobs are described at the end of this chapter.)
- CreateProcess inserts the new process block at the end of
the Windows 2000 list of active processes
Stage 2E: Setting Up the PEB
CreateProcess allocates a page for the PEB and initializes a
number of fields, which are described in Table 6-7.
Table 6-7 Initial Values of the Fields of the PEB
||Base address of section|
||KeNumberProcessors kernel variable|
||NtGlobalFlag kernel variable|
||MmCriticalSectionTimeout kernel variable|
||MmHeapSegmentReserve kernel variable|
||MmHeapSegmentCommit kernel variable|
||MmHeapDeCommitTotalFreeThreshold kernel variable|
||MmHeapDeCommitFreeBlockThreshold kernel variable|
||(Size of a page - size of a PEB) / 4|
||First byte after PEB|
||NtMajorVersion kernel variable|
||NtMinorVersion kernel variable|
||NtBuildNumber kernel variable & 0x3FFF|
If the image file specifies explicit Win32 version values, this
information replaces the initial values shown in Table 6-7. The mapping
from image version information fields to PEB fields is described in
Table 6-8 Win32 Replacements for Initial PEB Values
||Value Taken from Image Header
||OptionalHeader.Win32VersionValue & 0xFF|
||(OptionalHeader.Win32VersionValue >> 8) & 0xFF|
||(OptionalHeader.Win32VersionValue >> 16) & 0x3FFF|
||(OptionalHeader.Win32VersionValue >> 30) ^ 0x2|
Stage 2F: Completing the Setup of the Executive Process Object
Before the handle to the new process can be returned, a few final
setup steps must be completed:
- The process handle table is initialized; if the inherit handles
flag is set for the parent process, any inheritable handles are copied
from the parent's object handle table into the new process. (For
more information about object handle tables, see Chapter 3.)
- If you're running Windows 2000 Professional and the image
header specifies IMAGE_FILE_AGGRESIVE_WS_TRIM, the PS_WS_TRIM_FROM_EXE_HEADER flag is set in the process block. This causes
the working set manager to aggressively steal pages from the process.
If you're running Windows 2000 Professional on a small-memory x86
system, the PS_WS_TRIM_BACKGROUND_ONLY_APP flag is set in the process block, which limits the aggressive
trimming to processes that aren't associated with the foreground
window. These working set flags are not set for processes created on
systems running Windows 2000 Server.
- If the image header characteristics IMAGE_FILE_UP_SYSTEM_ONLY flag is set (indicating that the image can run only on a uniprocessor system), a single CPU is chosen for all the threads in
this new process to run on. This choosing process is done by simply
cycling through the available processorseach time this type of
image is run, the next processor is used. In this way, these types of
images are spread out across the processors evenly.
- If the image specifies an explicit processor affinity mask (for
example, a field in the configuration header), this value is copied to
the PEB and later set as the default process affinity mask.
- If the parent process had an Event Log section in its PEB, the
Event Log is copied to the new process and a handle is duplicated to
the section for the new process.
- If systemwide auditing of processes is enabled (which is
accomplished through the Group Policy snap-in), the process's
creation is written to the Audit Log.
- The process's creation time is set, the handle to the new
process is returned to the caller (CreateProcess in
Kernel32.dll), and execution returns to the original caller of
Stage 3: Creating the Initial Thread and Its Stack and Context
At this point, the Windows 2000 executive process object is
completely set up. It still has no thread, however, so it can't do
anything yet. Before the thread can be created, it needs a stack and a
context in which to run, so these are set up now. The stack size for
the initial thread is taken from the imagethere's no way to
specify another size.
Now the initial thread can be created, which is done by calling
NtCreateThread. (For a detailed description of how a thread is
created, see the section "Flow of CreateThread.") The thread parameter (which can't be specified in
CreateProcess but can be specified in CreateThread) is the
address of the PEB. This parameter will be used by the initialization
code that runs in the context of this new thread (as described in Stage
6). However, the thread won't do anything yetit is created in
a suspended state and isn't resumed until the process is completely
initialized (as described in Stage 5).
Stage 4: Notifying the Win32 Subsystem About the New Process
After all the necessary executive process and thread objects have
been created, Kernel32.dll sends a message to the Win32 subsystem so
that it can set up for the new process and thread. The message includes
the following information:
- Process and thread handles
- Entries in the creation flags
- ID of the process's creator
- Flag indicating whether the process belongs to a Win32
application (so that Csrss can determine whether or not to show the
The Win32 subsystem performs the following steps when it receives
- CreateProcess duplicates a handle for the process and
thread. In this step, the usage count of the process and the thread is
incremented from 1 (set at creation time) to 2.
- If a process priority class isn't specified, CreateProcess sets it according to the algorithm described below.
- The Csrss process block is allocated.
- The new process's exception port is set to be the general
function port for the Win32 subsystem so that the Win32 subsystem
will receive a message when an exception occurs in the process. (For
further information on exception handling, see Chapter 3.)
- If the process is being debugged (that is, if it is attached to
a debugger process), the process debug port is set to the Win32
subsystem's general function port. This setting ensures that
Windows 2000 will send debug events that occur in the new process (such
as thread creation and deletion, exceptions, and so on) as messages to
the Win32 subsystem so that it can then dispatch the events to the
process that is acting as the new process's debugger.
- The Csrss thread block is allocated and initialized.
- CreateProcess inserts the thread in the list of threads
for the process.
- The count of processes in this session is incremented.
- The process shutdown level is set to x280 (the default process
shutdown levelsee SetProcessShutdownParameters in the MSDN
Library documentation for more information).
- The new process block is inserted into the list of Win32
- The per-process data structure used by the kernel-mode part
of the Win32 subsystem (W32PROCESS structure) is allocated and
- The application start cursor is displayed. This cursor is the
familiar arrow with an hourglass attachedthe way that Windows
2000 says to the user, "I'm starting something, but you can use the cursor in the meantime." If the process doesn't make a
GUI call after 2 seconds, the cursor reverts to the standard pointer.
If the process does make a GUI call in the allotted time,
CreateProcess waits 5 seconds for the application to show a window.
After that time, CreateProcess will reset the cursor again.
Stage 5: Starting Execution of the Initial Thread
At this point, the process environment has been determined,
resources for its threads to use have been allocated, the process has a
thread, and the Win32 subsystem knows about the new process. Unless the
caller specified the CREATE_SUSPENDED flag, the initial thread is now resumed so that it can start
running and perform the remainder of the process initialization work
that occurs in the context of the new process (Stage 6).
Stage 6: Performing Process Initialization in the Context of the New Process
KiInitializeContextThread, which is called by
KeInitializeThread, builds the initial context of the thread and
the thread's kernel stack. The new thread begins life running the
kernel-mode thread startup routine KiThreadStartup. (For a more
detailed description of the thread startup steps leading to this, see
the section "Flow of CreateThread.") The
KiThreadStartup routine performs the following steps:
- Lowers the IRQL level from DPC/dispatch level to APC (asynchronous procedure call) level.
- Enables working set expansion.
- Queues a user-mode APC to the new thread to execute the
user-mode thread startup routine LdrInitializeThunk inside
- Lowers the IRQL level to 0, causing the APC to fire and LdrInitializeThunk to be called. The LdrInitializeThunk routine initializes the loader, heap manager,
NLS tables, thread-local storage (TLS) array, and critical section
structures. It then loads any required DLLs and calls the DLL entry
points with the DLL_PROCESS_ATTACH function code.
- If the process being created is a debuggee, all threads in the
process are suspended. (Threads might have been created during step 3.)
A create process message is then sent to the process's debug port
(the Win32 subsystem function port because this is a Win32 process) so
that the subsystem can deliver the process startup debug event (CREATE_PROCESS_DEBUG_INFO) to the appropriate debugger process.
KiThreadStartup then waits for the Win32 subsystem to get the
reply from the debugger (via the ContinueDebugEvent function).
When the Win32 subsystem replies, all the threads are resumed.
- Finally, the image begins execution in user mode. This is done
by creating a trap frame that specifies the previous mode as user and
the address to return to as the main entry point of the image. Thus,
when the trap that caused the thread to start execution in kernel mode
is dismissed, the program begins running in user mode at the right
Previous | Table of Contents | Next
Last Updated: Friday, July 6, 2001