,

Contents ยท Signals, Timers, Context Switching


Signals: delivery and handling

  • Signals notify a process/thread of exceptional events (e.g., SIGINT, SIGSEGV, SIGCHLD).
  • Delivery: kernel enqueues pending signals; on return to user space, installs a trampoline to invoke handler.
  • Realtime signals (SIGRTMIN..): queued with payload and ordering; legacy signals coalesce.
// Minimal signal handling demo (Node.js-like pseudo)
process.on('SIGINT', () => {
  console.log('Caught SIGINT, shutting down cleanly');
});

Signal masks and dispositions

  • Each thread has a signal mask controlling which signals are blocked.
  • Dispositions: default, ignore, or user handler; some are uncatchable (SIGKILL, SIGSTOP).
  • Use signalfd/eventfd or self-pipe trick to integrate with event loops without races.

Timers: POSIX timers, interval timers, and time sources

  • Interval timers: ITIMER_REAL/ITIMER_VIRTUAL/ITIMER_PROF send signals periodically.
  • POSIX timers: timer_create/timer_settime with SIGEV_SIGNAL or SIGEV_THREAD.
  • Clock sources: CLOCK_REALTIME (wall), CLOCK_MONOTONIC (steady), CLOCK_BOOTTIME, CLOCK_TAI.
// Periodic timer with setInterval (conceptual)
const id = setInterval(() => { /* do work */ }, 10);
// In POSIX, ITIMER_REAL would deliver SIGALRM; use signalfd to consume safely.

High-resolution timers and clockids

  • hrtimers provide microsecond/sub-millisecond precision with hardware timers.
  • Timer slack coalesces wakeups to save power; can be tuned per-thread.
  • Use CLOCK_MONOTONIC for durations; avoid REALTIME for timeouts due to NTP adjustments.

Context switching and preemption

  • Context switch saves/restores register state, stack pointer, program counter, and necessary MMU state.
  • Preemption triggered by timer interrupts, blocking syscalls, or higher-priority runnable tasks.
  • TLB shootdowns and cache warm-up add hidden costs; thread affinity can help.
// Rough latency model (ns)
function switchCost(regs=1000, tlb=2000, cache=5000){
  return regs + tlb + cache; // illustrative only
}

Performance, latency, and tuning

  • Batch signal delivery with signalfd; avoid per-signal overhead in hot paths.
  • Use timerfd/epoll or io_uring timeouts for scalable timers.
  • Pin threads and reduce context switches with cooperative scheduling or work-stealing pools.

Exercises

  1. Implement a timer wheel or min-heap scheduler and benchmark against setTimeout.
  2. Install handlers for SIGINT/SIGTERM/SIGCHLD; build a graceful shutdown sequence.
  3. Measure context switch rates and latency with threads competing on CPU under various niceness/priorities.
Use the right clock and delivery mechanism; minimize context switches on hot paths.