Skip to content

Process Management

Enrico Fraccaroli (Galfurian) edited this page Jan 29, 2026 · 2 revisions

A guided, code-backed overview of process management in MentOS.

What is a process in MentOS?

A process is the unit of execution in MentOS. It owns:

  • A virtual address space (its mm_struct_t)
  • A stack and registers (thread_struct_t)
  • Open file descriptors
  • Identity and group information (PID/PPID/PGID/SID, UID/GID)
  • Scheduling metadata

From user space, you interact with processes mainly through the POSIX-style APIs in unistd.h and sys/wait.h.

Lifecycle: init → fork → exec → exit

1) The init process (PID 1)

The kernel creates the init process at boot and loads /bin/init. It also wires standard I/O to /proc/video so user programs can read and write to the screen and keyboard:

  • The init process is created in process_create_init().
  • STDIN/STDOUT/STDERR are attached to /proc/video.

Relevant code paths:

  • kernel/src/process/process.c
  • kernel/inc/process/process.h

2) Fork: duplicate the caller

fork() creates a new process by cloning the current process state and address space. In MentOS:

  • The child gets a cloned memory map (mm_clone).
  • File descriptors are duplicated (vfs_dup_task).
  • The child sees a return value of 0.
  • The parent receives the child PID.

User-side API:

#include <unistd.h>

pid_t pid = fork();
if (pid == 0) {
    // child
} else if (pid > 0) {
    // parent
}

3) Exec: replace the process image

execve() replaces the current process image with a new executable. In MentOS:

  • The old address space is destroyed and rebuilt (mm_destroy, mm_create_blank).
  • ELF binaries are loaded by the kernel ELF loader.
  • Shebang (#!) scripts are supported.
  • A NULL envp is accepted and replaced with a default environment:
    • PATH=/bin:/usr/bin
    • HOME=/

User-side API:

#include <unistd.h>

char *argv[] = {"/bin/echo", "hello", NULL};
char *envp[] = {"PATH=/bin:/usr/bin", "HOME=/", NULL};
execve(argv[0], argv, envp);

4) Exit and wait

exit() marks a process as a zombie and notifies the parent with SIGCHLD. The parent should collect the exit status with waitpid().

User-side API:

#include <sys/wait.h>
#include <unistd.h>

pid_t pid = fork();
if (pid == 0) {
    // child
    _exit(42);
}

int status = 0;
pid_t done = waitpid(pid, &status, 0);
if (done > 0 && WIFEXITED(status)) {
    int code = WEXITSTATUS(status);
}

Process identifiers and groups

MentOS tracks the usual UNIX identifiers:

  • PID: process ID
  • PPID: parent process ID
  • PGID: process group ID
  • SID: session ID
  • UID/GID: user and group IDs (real and effective)

User-side APIs (subset):

#include <unistd.h>

pid_t pid  = getpid();
pid_t ppid = getppid();
pid_t pgid = getpgid(0);
pid_t sid  = getsid(0);
setpgid(0, pgid);
setsid();

Notes about waitpid() in MentOS:

  • pid == -1 (any child) and pid > 0 (specific child) are supported.
  • pid == 0 or pid < -1 are not supported.
  • Only WNOHANG and WUNTRACED are accepted; other options return -EINVAL.

Scheduling and process states

Processes are scheduled from a run queue (runqueue_t) and can be in these states:

  • TASK_RUNNING
  • TASK_INTERRUPTIBLE
  • TASK_UNINTERRUPTIBLE
  • TASK_STOPPED
  • TASK_TRACED
  • EXIT_ZOMBIE
  • EXIT_DEAD

MentOS supports multiple scheduling algorithms (configured at build time). See Scheduling for a full overview.

Signals (process-level events)

Processes can receive POSIX-like signals. When a process exits, the kernel sends SIGCHLD to the parent.

User-side APIs are defined in <signal.h> and <sys/wait.h> (for exit status macros). See IPC and System Calls for details.

Teaching examples

Example 1: Spawn a child, wait, and print its PID

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main(void)
{
    pid_t pid = fork();
    if (pid == 0) {
        printf("child pid=%d\n", getpid());
        _exit(0);
    }

    int status = 0;
    waitpid(pid, &status, 0);
    printf("parent saw child exit\n");
    return 0;
}

Example 2: Replace the child image with another program

#include <unistd.h>

int main(void)
{
    pid_t pid = fork();
    if (pid == 0) {
        char *argv[] = {"/bin/ls", "/", NULL};
        execve(argv[0], argv, NULL); // NULL envp is allowed in MentOS
        _exit(127);
    }

    waitpid(pid, NULL, 0);
    return 0;
}

Developer notes (kernel-side)

Key data structures

  • task_struct describes a process (IDs, state, file descriptors, memory, signals)
  • thread_struct stores register state
  • sched_entity stores scheduling metadata

Important code paths

  • Process creation and exec: kernel/src/process/process.c
  • Scheduler and syscalls like getpid, setpgid, waitpid, exit: kernel/src/process/scheduler.c
  • Wait queues and sleep primitives: kernel/src/process/wait.c

Behaviors worth knowing

  • fork() uses mm_clone() and duplicates the parent file table.
  • execve() enforces executable permission and supports shebangs.
  • sys_exit() shifts the exit code by 8 bits before storing it (mirrors UNIX wait status encoding).
  • Exiting processes become zombies until the parent calls waitpid().

Related pages

Clone this wiki locally