🗓️ 13062026 2200

SYSTEM CALLS

A system call (syscall) is the controlled gateway between cpu_privilege_modes. Every time application code needs something from the OS — read a file, allocate memory, send a network packet — it makes a syscall. The CPU switches from ring 3 to ring 0, the kernel handles the request, then switches back.

Without syscalls, user-mode code cannot do I/O. There is no other way to talk to hardware.

How a Syscall Works​

  1. Application calls a library function (e.g. read() in C, FileInputStream.read() in Java)
  2. Library sets up CPU registers with the syscall number and arguments
  3. Executes the syscall instruction — CPU switches to ring 0
  4. Kernel validates arguments, performs the operation
  5. CPU switches back to ring 3, result returned to the application

Each crossing costs ~100ns — cheap individually, expensive at thousands per second.

Common Syscalls​

SyscallTriggered byRing 0 work
read / writeAny file or socket I/OCopy data between kernel buffers and user space
mmapLarge memory allocations (malloc internally)Update virtual_memory page tables
sendto / recvfromNetwork send/receiveNetwork stack processing
futexThread synchronization (locks, wait/notify)Manage kernel wait queues
cloneCreating threads or processesDuplicate process structures
epoll_waitEvent-driven I/O (Netty, Nginx)Monitor file descriptors for readiness

Why High System CPU Happens​

Each syscall is a mode switch. Workloads that make many syscalls per second drive up the "system" portion of CPU (see interpreting_cpu_modes):

  • Excessive small I/O — many tiny read()/write() calls instead of buffered batches
  • Heavy logging — each log line can trigger a write() syscall
  • Short-lived connections — each TCP connection involves socket(), connect(), close() — multiple syscalls per request
  • Lock contention — threads competing for locks generate futex syscalls

Java / JVM Context​

JVM syscalls are hidden behind APIs. The developer does not see them, but they drive the "system" CPU mode:

  • FileInputStream.read() calls native read()
  • Socket.getInputStream().read() calls recvfrom()
  • synchronized under contention uses futex
  • new Thread() calls clone
EXAMPLE

A Java service writing 10,000 small log lines per second: each unbuffered write() is a syscall. Wrapping in BufferedOutputStream batches them, reducing syscalls by 100x and visibly dropping system CPU.


References​