PTSS — Priority Task Scheduler System
A task scheduler in C with POSIX threads. Handles priorities, deadlines, dependencies, and resource limits — everything cron can’t do.
A single scheduler thread runs on a 100ms tick. It evaluates which tasks are due, checks dependency chains, and assigns work to a pool of worker threads. The scheduler never executes tasks — it delegates. Scheduling latency stays predictable regardless of task duration.
How it works
The ready queue is a binary min-heap — tasks ordered by deadline first, priority second. This is Earliest Deadline First scheduling, provably optimal for single-processor deadline workloads. Insert and extract are O(log n).
Scheduler Thread (100ms tick)
┌─────────────────────────────────────┐
│ Phase 1: Scan pool for due tasks │
│ Phase 2: Drain heap → assign workers│
│ Phase 3: Enforce deadlines │
└────────────────┬────────────────────┘
│ assign
┌────────────┼────────────┐
▼ ▼ ▼
┌────────┐ ┌────────┐ ┌────────┐
│Worker 0│ │Worker 1│ │Worker 2│ ...
│ (idle) │ │ (busy) │ │ (idle) │
└────────┘ └────────┘ └────────┘
Each task has a hard deadline checked against CLOCK_MONOTONIC. When time runs low, status escalates through DEADLINE_SOON, DEADLINE_CRITICAL, and DEADLINE_EXCEEDED — at which point the task is killed and marked FAILED.
Dependencies are resolved every tick. Task B depends on Task A? B won’t run until A completes. If A fails, B is blocked — it doesn’t run against bad state.
Workers are a fixed thread pool. Each sleeps on a pthread_cond_wait until the scheduler signals it. No polling. No busy-waiting. If a task crashes — segfault, FPE, bus error — the worker catches it via siglongjmp and survives. The task is marked FAILED. The next task runs.
Seven-level documented lock ordering. Pre-allocated task pool — no
mallocduring scheduling. Three-phase graceful shutdown with state persistence.
The file structure
PTSS/
├── protocol.h 351 lines — Structs, constants, error codes, declarations
├── scheduler.c 786 lines — Tick loop, task pool, dependencies, CLI
├── executor.c 455 lines — Worker pool, crash recovery, deadline checks
├── heap.c 244 lines — Min-heap: sift_up, sift_down, insert, extract
├── log.c 250 lines — Structured logging, execution log, persistence
├── monitor.c 150 lines — Metrics, dashboard, status reports
├── test_ptss.c 610 lines — 7 tests: priorities, deadlines, deps, load
└── Makefile 75 lines — Debug/release, test, valgrind
Readable in an afternoon. protocol.h is the single source of truth. heap.c is a textbook min-heap you’ll want to steal.
Quick start
git clone https://github.com/devwail/PTSS.git
cd PTSS && make
make test
./scheduler --workers 4 --log-level DEBUG
Also usable as a library — compile with -DPTSS_NO_MAIN and call scheduler_add_task() from your own code.
GCC, C11, pthreads. Nothing else. Read the full write-up →