100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
C

System Calls

Understand how applications request kernel services through system calls and the user-to-kernel mode transition.

Introduction to Operating SystemsIntermediate10 min readJul 8, 2026
Analogies

Introduction

A system call is the controlled gateway through which a user-mode application requests a privileged service from the kernel, such as creating a process, reading a file, or allocating memory. Because user-mode code cannot execute privileged instructions or directly touch hardware, system calls are the only legitimate path from an application into kernel functionality.

🏏

Cricket analogy: A batsman cannot walk onto the field and change the pitch or scoreboard directly; he must request the umpire, the only authority allowed to act, just as user-mode code must request the kernel for privileged operations.

How It Works

When a program calls a library function like read() or fork(), the C library wraps the request in a special trap instruction (on x86-64 Linux, historically 'int 0x80', and on modern systems the faster 'syscall' instruction). Executing this instruction causes a controlled transition from user mode to kernel mode: the CPU switches privilege level, saves the user context, and jumps to a fixed kernel entry point. The kernel looks up the requested operation in a system call table using a syscall number, executes the corresponding kernel function with the given arguments, and then returns the result, switching the CPU back to user mode and resuming the calling process. This mechanism is what keeps the kernel in full control of hardware while still letting applications request services safely.

🏏

Cricket analogy: Calling read() is like a captain signaling the third umpire via a formal review request; the syscall/trap instruction is the review signal, the third umpire's booth is kernel mode, and the decision returns control to the field.

Example

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

int main(void) {
    printf("Before fork(): PID=%d\n", getpid());

    /* fork() is a system call: it traps into the kernel,
       which duplicates the calling process's address space
       and scheduling state, then returns twice -- once in
       the parent, once in the new child. */
    pid_t pid = fork();

    if (pid < 0) {
        perror("fork failed");
        return 1;
    } else if (pid == 0) {
        /* Child process: write() is also a system call,
           trapping into the kernel to perform actual I/O. */
        const char msg[] = "Child: hello from kernel-mediated I/O\n";
        write(STDOUT_FILENO, msg, sizeof(msg) - 1);
        _exit(0);
    } else {
        /* Parent waits for the child using the wait() system call. */
        int status;
        waitpid(pid, &status, 0);
        printf("Parent: child %d finished\n", pid);
    }

    return 0;
}

Analysis

Each of fork(), write(), and waitpid() triggers a user-to-kernel mode transition. fork() asks the kernel's process manager to duplicate the calling process; the kernel returns 0 in the new child and the child's PID in the parent, letting one call produce two distinct control-flow paths. write() asks the kernel's file/I/O subsystem to copy bytes from user-space memory into the OS-managed file descriptor (here, standard output), which the kernel then flushes to the terminal driver. waitpid() blocks the parent, requesting the scheduler suspend it until the kernel signals that the child has exited. In every case, the application never touches hardware or the scheduler directly — it only issues a well-defined request and lets the kernel act on its behalf, illustrating the safe boundary system calls enforce.

🏏

Cricket analogy: fork() is like a coach cloning a player into two identical twins mid-match, one continuing as the original batsman and one starting a new innings elsewhere, each returned a different signal to know which role they play.

Key Takeaways

  • System calls are the only sanctioned path from user mode into kernel-mode services.
  • A trap instruction (e.g., syscall on x86-64) triggers the user-to-kernel mode switch.
  • The kernel dispatches requests via a syscall number looked up in a system call table.
  • fork(), write(), and waitpid() are classic examples of process and I/O system calls.
  • After servicing the request, the kernel returns control and the CPU switches back to user mode.

Practice what you learned

Was this page helpful?

Topics covered

#OperatingSystemsStudyNotes#OperatingSystems#SystemCalls#System#Calls#Works#Example#StudyNotes#SkillVeris#ExamPrep