Processes and Threads (PaT) - MirSiv/exyde GitHub Wiki

Processes and Threads

Threads

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.

Processes

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.

Refcounting

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_PROCESS handle 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.

Zombies and the reaper

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.

Waiting for a child

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.

Bootstrap handle

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.