Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Multithreaded Process Manager

A simulated operating-system process table in C: worker threads concurrently fork, exit, wait and kill simulated processes, while a monitor thread records a consistent snapshot after every change. It's built on POSIX threads, with mutexes and condition variables and no busy-waiting.

Processes here are Process Control Block (PCB) entries, not real OS processes. The interesting part is keeping one shared table correct while many threads mutate it at once.

Highlights

  • Unix-style lifecycle: RUNNING → BLOCKED → ZOMBIE → TERMINATED, with wait reaping zombies and returning exit codes.
  • wait(-1): waits for whichever child exits first.
  • Orphan adoption: when a parent exits, its children are re-parented to init (PID 1) so they can still be reaped, as in Unix.
  • Kill-safe waiting: killing a process that is blocked in wait wakes it up instead of leaving it hung.
  • Event-driven monitor: a dedicated thread sleeps on a condition variable and prints a table snapshot per change. It never polls.
  • Race-checked: every scenario runs clean under ThreadSanitizer, including a 6-thread stress test.

Process lifecycle

stateDiagram-v2
    [*] --> RUNNING: pm_fork(parent)
    RUNNING --> BLOCKED: pm_wait, no zombie child yet
    BLOCKED --> RUNNING: child exits, zombie reaped
    RUNNING --> ZOMBIE: pm_exit / pm_kill
    BLOCKED --> ZOMBIE: pm_kill while waiting
    ZOMBIE --> TERMINATED: parent's pm_wait reaps it
    TERMINATED --> [*]
Loading
State Meaning
RUNNING Exists and is active; the first state after pm_fork
BLOCKED Inside pm_wait, sleeping until a matching child exits
ZOMBIE Has exited; exit status kept until the parent reaps it
TERMINATED Reaped and removed from the table (not shown in snapshots)

Design

Concern Mechanism
Shared process table (64 slots) One pthread_mutex_t table_lock guards every read and write of the table
Parent waiting for a child Each PCB owns a pthread_cond_t; pm_wait sleeps on it with table_lock released
Waking the right waiter pm_exit broadcasts to the parent's condition (and its own, for kill-while-blocked)
Monitor notifications A pending flag plus two condition variables form a handshake. A mutating thread hands the monitor a message and waits until it's written, so every snapshot is taken while the table is still consistent.
Per-thread command labels A __thread buffer holds each worker's current command text

API

Function Behaviour
pm_fork(ppid) Allocates the next PID, creates the PCB and links it to the parent. Rejects zombie parents.
pm_exit(pid, status) Marks the process ZOMBIE, records the status, re-parents its children to init and wakes waiters
pm_wait(ppid, cpid) Reaps child cpid, or the first child to exit if cpid = -1. Blocks if none has exited yet and returns immediately if there's no such child.
pm_kill(pid) Termination request, recorded as exit status -1
pm_ps() Prints a tabular snapshot of all non-terminated processes

Script format

Each worker thread runs one script file, one command per line:

fork 1          # create a child of PID 1
exit 2 10       # PID 2 exits with status 10
wait 1 -1       # PID 1 waits for any child (or: wait 1 3)
kill 4          # termination request to PID 4
sleep 200       # this worker pauses for 200 ms

Getting started

Requirements: GCC (or Clang) with POSIX threads, and make. That means Linux or macOS; on Windows, use WSL.

git clone https://github.com/aksaN000/process-manager.git
cd process-manager
make                 # builds ./pm_sim
make run             # runs the two-thread example and prints snapshots.txt
make test            # every scenario under ThreadSanitizer

To run your own scripts, pass one file per worker thread; threads are numbered from 0 in argument order:

./pm_sim thread0.txt thread1.txt thread2.txt
cat snapshots.txt

Example output

scripts/orphans_t0.txt exits a parent that still has a running child and a zombie child. Both are adopted by init (PPID becomes 1) and the zombie is reaped by init's next wait:

Thread 0 calls pm_exit 2 1
PID		PPID		STATE		EXIT_STATUS
----------------------------------------------
1		0		RUNNING		-
2		1		ZOMBIE		1
3		1		ZOMBIE		7
4		1		RUNNING		-

Thread 0 calls pm_wait 1 -1
PID		PPID		STATE		EXIT_STATUS
----------------------------------------------
1		0		RUNNING		-
3		1		ZOMBIE		7
4		1		RUNNING		-

Full logs for each scenario are in examples/.

Test scenarios

Scripts What it checks
basic_t0, basic_t1 The reference two-thread interleaving
killblocked_t0, killblocked_t1 A process blocked in wait is killed and must not hang
orphans_t0 Children of an exiting parent are adopted and reaped by init
stress_t0 … stress_t5 Six threads: 48 concurrent forks, exits and waits; ends with only init left

Project structure

pm_sim.c        process manager, script interpreter, workers and monitor
Makefile        build, run, and ThreadSanitizer test targets
scripts/        worker scripts for each scenario
examples/       snapshot logs produced by the scenarios

Background

This started as the Operating Systems (CSE321) project at BRAC University. After submitting it, I fixed two issues the original version had:

  • Kill-while-blocked hang: killing a process that was blocked in wait left it hung.
  • Orphans: they were never re-parented, so zombie children could never be reaped.

I also added the ThreadSanitizer test suite.

About

Simulated OS process table in C: concurrent fork/exit/wait/kill across POSIX threads, zombie reaping, orphan adoption by init, and an event-driven snapshot monitor. Stack: C, pthreads, ThreadSanitizer.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages