An overview of threads, their properties, and states. This guide details user and kernel stacks, stack growth with guard pages, and how user-mode applications interact with the kernel through system calls and the general Windows architecture.

Quick note: This blog leans heavily on the "Windows Kernel Programming" book. Think of it as our foundation, and I'll be adding my own insights on top.
A thread is the actual executing entity in a process. It uses the process’s resources (its virtual memory, handles, etc.) to do work.
things that thread owns:
Every thread has at least one stack in kernel (system) space. this kernel stack is used when the thread executes in kernel mode, during system calls exceptions, our when transcreation from user mode into kernel mode.
A user-mode thread also has a user stack in it's process's user address space. the user stack is where regular functions calls local variables and return address are stored.
The kernel stack is small by default (for example, ~12kb on 32bit windows) it's always resident in RAM when the thread is in running or Ready state. this necessary because kernel code cannot handle incur page faults while executing.
But why the stack can not paged-out and must be in RAM?
Most importantly: kernel stacks are small and have a fixed size. This means that allocating large variables on the stack or creating very deep chains of function calls is extremely risky in kernel mode. Code like device drivers must be written carefully to avoid this, as overflowing the kernel stack will crash the entire system. If you need more memory, you must allocate it from the kernel's heap (the paged or non-paged pool) instead and we will see how later on.
If a thread never enters user mode (for example, a pure kernel worker thread), it may only use its kernel stack and not have a user-mode stack.
When thread is created, the OS reserves a large contiguous address range for the stack in the process virtual address space, but does not commit all of the space right away. instead:
PAGE_GUARD protection) that guard page is committed but marked in a way that triggers an exception on first access. to see more details look here.This "reserved" region is private to the process and can't be used by others. "Uncommitted" simply means it's not backed by physical memory yet, so accessing it will cause a fault.
STATUS_GUARD_PAGE_VIOLATION exception.STATUS_GUARD_PAGE_VIOLATION exception. This isn't a crash; it's a signal to the kernel that something needs attention.1 (Stack grows downwards -->)
2+-------------------------------------------+ High memory addresses
3| Reserved (uncommitted) |
4| (Not usable yet) |
5+-------------------------------------------+
6| Guard Page (Tripwire) | <--- The current boundary
7+-------------------------------------------+
8| Committed stack pages (in use) |
9+-------------------------------------------+
10| Committed initial stack region |
11+-------------------------------------------+
12| (stack base / top) | Low memory addresses
13+-------------------------------------------+
14“Uncommitted” (or “reserved but not committed”) means that the address range is taken (no other allocation can use it in that process), but no physical memory or backing store is assigned yet.
This allows the stack to grow incrementally, one page at a time, rather than committing the entire maximum stack size in advance.Technically, Windows uses 3 guard pages rather than one in most cases.
Applications need to perform various operations that are not purely computational, such as allocating memory, opening files, creating threads, etc. These operations can only be ultimately performed by code running in kernel mode. So how would user-mode code be able to perform such operations?
example,When a user in Notepad chooses File → Open, the Notepad process must open a file — but because it runs in user mode, it cannot access hardware or the filesystem directly. The process goes through several layers before entering kernel mode:
ntdll.dll contains the Native API, the lowest user-mode layer that interfaces directly with the Windows kernel.NtCreateFile) and places it into a CPU register — on x64, this is typically RAX (EAX on x86).syscall on x64sysenter on x86 These instructions trigger a privilege level switch from user mode (ring 3) to kernel mode (ring 0).Next Blog series will talk about Handles and Objects, how they work what they are and more details.
Published Oct 28, 2025
NtCreateFile inside the I/O Manager of the Windows kernel.syscall in ntdll.dll.