Repository navigation
Processes and Threads (PaT)
A thread is a kernel-scheduled execution context: a saved register state, a kernel stack, an address space reference, an optional owning process, and a name.
thread_t *thread_create(entry, arg, name)
thread_t *thread_create_ex(entry, arg, name, space)
void thread_exit(void)
thread_t *thread_current(void)
thread_create uses the current address space; thread_create_ex
binds the thread to a specific vmm_space_t and takes a reference
on it.
Kernel threads run in ring 0. User threads are entered via
arch_enter_user_mode(entry, rsp), which performs the iretq into
ring 3.
A process is an address space plus a handle table plus lifecycle state. It has at least one thread (the main thread), but a process can outlive its main thread if some other thread still references it or the parent still holds a process handle.
process_t *process_create_from_elf(name, elf, size)
process_t *process_spawn(name, elf, size, argc, argv, envc, envp)
process_t *process_spawn_init(name, elf, size, initrd, ir_size, ...)
void process_ref(process_t *)
void process_unref(process_t *)
void process_exit(process_t *, int code)
process_create_from_elf builds a fresh address space and loads the
ELF's PT_LOAD segments into it. It does not create a thread. It
does not map a stack.
process_spawn is process_create_from_elf plus: map a user stack
at USER_STACK_TOP_INIT, build the SysV initial stack layout, and
create the main thread with thread_create_ex. The thread enters
ring 3 at p->entry.
process_spawn_init adds one more step: map the initrd archive
read-only at INITRD_VA before creating the thread. Only used for
the bootstrap init.
A process_t has a refcount. The initial reference belongs to the
kernel-side creator. Other references can be added:
- A thread owned by the process holds a reference (dropped when the thread is reaped).
- A
HANDLE_KIND_PROCESShandle in a parent's handle table holds a reference (dropped when the handle is closed).
When the refcount hits zero, process_destroy runs: the handle
table is destroyed (releasing channels and child process refs), the
address space is unreffed, the name copy is freed, and the
process_t itself is freed.
thread_exit does not free the thread_t immediately. It puts the
thread on a zombie list. sched_schedule reaps zombies after
thread_switch — from a different stack than the dying thread's —
which is safe.
process_exit records the exit code, sets exited = 1, and wakes
anyone blocked in SYS_WAIT on the process. It does not free
anything. Freeing is left to the refcount machinery.
WAIT(proc_handle) -> exit_code
Blocks the calling thread until the child's process_exit is
called. Wakeups go through a waitq_t on the child.
A process may be spawned with a bootstrap handle (a channel). The
parent passes it to SPAWN_ELF; the kernel duplicates it into the
child's handle table. The child retrieves it with
GET_BOOTSTRAP. This is how a service and its manager share a
channel without the child needing any filesystem access to find it.
If no bootstrap was supplied, GET_BOOTSTRAP returns -ENOENT.