IAE Academy

GATE CS

Processes, threads and system calls

A system call is the controlled way a user program asks the kernel to act for it, and a process is a program in execution with its own address space and kernel record (the PCB). These notes set out the rules for tracing process states, for counting the processes and output lines that a sequence of fork() calls produces, and for what threads share and what they keep private, with the traps in each.

9 previous-year questions · 9 solved · 5 practice questions

System calls and the two modes

The CPU runs in at least two modes. In user mode privileged instructions (I/O, changing the page-table base, halting, disabling interrupts) are not allowed. In kernel mode every instruction is allowed. The current mode is held in a mode bit of the processor status word.

Privileged and non-privileged instructions

  1. Privileged (kernel mode only): I/O instructions, setting the timer, enabling or disabling interrupts, setting the mode bit directly, loading the page-table base or other memory-management registers, halting the CPU.

  2. Not privileged (allowed in user mode): reading the time-of-day clock, ordinary arithmetic, loads and stores within the process's own address space, and the trap (system-call) instruction itself.

A system call is the only planned way for a user program to enter the kernel. The program executes a trap instruction (a software interrupt). The hardware switches to kernel mode and jumps to a fixed handler; the handler uses the system-call number to pick the service routine; on return the mode goes back to user mode. A library wrapper such as read() hides the trap from the programmer.

What happens on a system call, in order

  1. The program places the system-call number and arguments in registers (or on the stack, or in a memory block whose address is put in a register) and executes the trap instruction.

  2. The hardware changes to kernel mode, saves the user program counter and status word, and jumps to the trap handler through the trap vector.

  3. The kernel checks the call number and the arguments, then runs the service routine.

  4. The kernel stores the result (or an error code) and executes a return-from-trap instruction.

  5. The hardware restores the saved program counter and status word and drops to user mode.

Event

Caused by

Mode change

Examples

System call (trap)

The running program, on purpose

User to kernel

read(), fork(), write()

Exception

The running program, by error or fault

User or kernel to kernel

Divide by zero, page fault, illegal instruction

Interrupt

A device or timer, outside the program

User or kernel to kernel

Timer tick, disk-completion signal

EXAM TIP

A system call is not an ordinary procedure call: it changes the mode and enters the kernel at a fixed address. Switching from user to kernel mode on a system call is a mode switch and need not be a full process context switch, because the same process keeps running. Executing a privileged instruction in user mode causes an exception; the trap instruction itself is not privileged, which is why a user program can execute it.

The process, its address space and its PCB

A process is a program in execution. Its address space has these parts: text (code, read-only), data (global and static variables), heap (grows upward with malloc()), and stack (grows downward with function calls). Each process has its own address space, so a write to a variable in one process is invisible to another, unless the processes have explicitly set up shared memory.

The kernel keeps one process control block (PCB) per process. It holds the process id, the process state, the program counter, the saved CPU registers, scheduling information (priority, queue pointers), memory-management information (page-table base and limits), accounting information, the list of open files and the id of the parent. The PCB is where a context switch saves the process's state and from where it restores it.

State

Meaning

New

Being created; the PCB is built

Ready

Has everything except the CPU; waits in the ready queue

Running

Executing on the CPU

Waiting (blocked)

Waits for an event such as I/O completion or a wait() to return

Terminated

Finished; resources are released, though the PCB may remain until the parent collects the exit status

Transition

Cause

New to Ready

The kernel admits the process

Ready to Running

The scheduler dispatches it

Running to Ready

The time quantum expires, or a higher-priority process arrives (preemption)

Running to Waiting

It requests I/O or waits for an event

Waiting to Ready

The I/O or event completes

Running to Terminated

It calls exit() or is killed

The seven-state model adds two suspended states for processes swapped out to disk: Ready-suspended and Blocked-suspended. A Blocked-suspended process whose event occurs moves to Ready-suspended. The long-term scheduler admits new processes (it controls the degree of multiprogramming), the medium-term scheduler swaps processes out to disk and back in, and the short-term scheduler picks the next ready process to run on the CPU.

EXAM TIP

There is no direct Waiting to Running transition: a process whose event has occurred first goes to Ready and waits for the scheduler. A process in the Ready state is never waiting for I/O.

Creating and ending processes: fork, exec, wait, exit

fork() creates a new process (the child) that is a copy of the caller (the parent): same code, a copy of the data, heap and stack, copies of the open file descriptors, and the same next instruction to execute. It returns 0 in the child, the child's pid (a positive number) in the parent, and a negative value (no child is created) if it fails. After the call the two processes run independently, and the order in which they print is not fixed unless wait() or other synchronisation forces it.

exec() (a family of calls) replaces the code, data, heap and stack of the calling process with a new program. It does not create a process: the pid stays the same, and if it succeeds it never returns, so any statement after it in the old program does not run. wait() blocks the caller until one of its children terminates; it returns at once if a child has already terminated, and returns -1 if the caller has no children. It returns the pid of the child it collected and stores that child's exit status through its pointer argument (unless the argument is NULL). exit() ends the calling process, releases its resources and passes an exit status to the parent.

The usual pattern to run a new program is fork(), then exec() in the child, and wait() in the parent.

Rules for counting processes and printed lines

  1. Every executed fork() that succeeds creates exactly one new process. So the total number of processes created, counting the original, is 1 plus the number of fork() calls executed, summed over all processes.

  2. The child starts from the statement after the fork(), with the same variable values and the same loop counters as the parent had at that moment.

  3. In an expression such as fork() && fork(), the right operand runs only when the left is non-zero, which is the parent. In fork() || fork(), the right operand runs only when the left is zero, which is the child. (Both assume the fork succeeds.)

  4. A printf after the forks is executed once by every process that reaches it.

  5. Output that printf has buffered but not yet written is copied into the child too. On a terminal, standard output is line-buffered, so text printed without a newline before a fork() can appear twice; when output goes to a file or pipe it is fully buffered, so even lines ending in a newline can be duplicated. Unless a question says otherwise, take each printf to appear once per process that executes it.

  6. File descriptors are copied by fork() but refer to the same open file, so parent and child share the file offset of a file opened before the fork.

TOTAL PROCESSES

F is the number of fork() calls that actually execute, summed over all processes; assumes every fork succeeds.

N UNCONDITIONAL FORKS IN A ROW

n fork() calls one after another with no condition and no exit; the same holds for a loop that runs n times with a fork in it and no break. New (child) processes created = 2^n - 1.

LINES PRINTED BY A PRINTF AFTER A FORK INSIDE AN N-ITERATION LOOP

For a loop body of fork(); followed by printf("...\n"); with every process continuing the loop and each printf appearing once per process that executes it: iteration k (counting from 1) is executed by 2^k processes.

WORKED EXAMPLE

How many processes exist, and how many times is X printed, for this program (all calls succeed)?

int main()
{
    fork();
    if (fork() == 0)
        fork();
    printf("X\n");
    return 0;
}
Solution
  1. The first fork() is executed by the original process P only: 1 fork, giving P and A.

  2. The second fork() is executed by both P and A: 2 forks, giving children B (of P) and C (of A). In P and A the return value is non-zero, so they skip the if body. In B and C it is 0.

  3. The third fork() sits in the if body and is executed only by B and C: 2 forks.

  4. Total forks F = 1 + 2 + 2 = 5, so the number of processes is 1 + 5 = 6.

  5. Every one of the 6 processes reaches the printf.

Answer: 6 processes exist and X is printed 6 times.

WORKED EXAMPLE

What does this program print?

int main()
{
    int x = 5;
    if (fork() == 0) {
        x = x + 10;
        printf("C%d\n", x);
    } else {
        wait(NULL);
        x = x + 1;
        printf("P%d\n", x);
    }
    return 0;
}
Solution
  1. After the fork(), parent and child each have their own copy of x, equal to 5.

  2. The child takes the if branch, sets its own x to 15 and prints C15, then ends.

  3. The parent takes the else branch and blocks in wait() until the child ends, so C15 is certainly printed first.

  4. The parent's x is still 5 (the child's change did not touch it); it becomes 6 and the parent prints P6.

Answer: C15 then P6, in that order.

EXAM TIP

Variables are copied, not shared, so a change in one process is not seen in the other. Printing &x in parent and child gives the same value, because the child's copy sits at the same virtual address; the two copies are in different physical frames (with copy-on-write, a page is shared read-only until one process writes to it). A fork inside a loop makes the child continue the loop with the same counter value; that is why for (i = 0; i < n; i++) fork(); gives processes. A loop in which each child breaks out at once gives only children ( processes):

for (i = 0; i < n; i++)
    if (fork() == 0)
        break;

Orphans, zombies and the context switch

A zombie process has terminated, but its PCB stays in the process table because its parent has not yet called wait() to read its exit status. It uses no CPU or memory apart from the table entry, and it cannot be killed since it is already dead. It disappears when the parent calls wait(); if the parent ends first, init adopts the zombie and collects it. A parent that never waits and never ends leaves zombies behind and can fill the process table.

An orphan process is one that is still running after its parent has terminated. The system makes the init process (or its modern equivalent) the new parent; it calls wait() regularly, so an orphan's PCB is cleaned up when it ends.

Zombie

Orphan

Is it still executing?

No, it has terminated

Yes

What happened to the parent?

Alive, has not called wait()

Terminated

Who removes it?

The parent's wait(), or init after the parent exits

init as new parent, when the orphan ends

A context switch is the kernel saving the state of the running process in its PCB and loading the saved state of another process, so that the CPU can run it. The time taken is pure overhead because no user work is done during it, and it depends on the hardware (number of registers, cache and TLB effects) and on the kernel's work. Switching between two threads of the same process is cheaper than switching between two processes, because the address space (and the page-table base) stays the same and the TLB entries stay valid; a switch to another process makes them invalid unless the TLB tags its entries with an address-space id.

CPU EFFICIENCY WITH CONTEXT-SWITCH OVERHEAD

q is the length of the useful time slice before each switch and s is the context-switch time, in the same unit; assumes every slice is used in full. If each process instead runs only for T < q before blocking, use T in place of q.

EXAM TIP

A system call that does not change the running process (a mode switch) is not a context switch. A context switch happens when the scheduler picks a different process or thread, for example after a timer interrupt, or when the running process blocks, such as in a read() that must wait for the disk.

Threads

A thread is a unit of execution inside a process. A process can have several threads. They share the resources of the process and each has its own execution state.

Shared by all threads of a process

Private to each thread

Code (text) segment

Stack

Global and static data

Program counter

Heap

Register set

Open files and other resources

Thread id and thread state (in its thread control block)

Address space and page table

Signal mask and thread-local storage

Threads are cheaper than processes to create and to switch between, and they communicate by reading and writing shared memory with no kernel help. The price is that they must synchronise access to shared data themselves, and one faulty thread can damage the whole process.

User-level threads are created and scheduled by a library in user space; the kernel sees only one execution unit for the process. Switching is fast (no system call). But if one thread makes a blocking system call, the kernel blocks the whole process, and the threads cannot run in parallel on several CPUs. Kernel-level threads are created and scheduled by the kernel: a blocking thread does not block the others and they can run on different CPUs, but creating and switching them needs the kernel (a system call or a kernel entry).

Model

Mapping

Effect of a blocking call

Parallelism on many CPUs

Many-to-one

Many user threads to 1 kernel thread

Blocks the whole process

No

One-to-one

Each user thread to its own kernel thread

Blocks only that thread

Yes

Many-to-many

m user threads to n kernel threads, n ≤ m

Other threads can still run on the other kernel threads

Yes, up to n at a time

EXAM TIP

On POSIX systems, the child of a fork() in a multithreaded process has exactly one thread, a copy of the thread that called fork(). Threads of one process share open files, so a file offset moved by one thread is seen by the others.

PREVIOUS-YEAR QUESTIONS

9 questions from the CS papers

Try each question first, then open the answer. We placed each question under a topic ourselves; the exam paper does not label topics.

See these papers in full: GATE CSE 2026 Set 1 · GATE CSE 2025 Set 1 · GATE CSE 2024 Set 1 · GATE CSE 2024 Set 2 · GATE CSE 2023 · GATE CSE 2020

GATE 2026 CS1 Q.63

GATE 2026 · CS1Q.63 · 2 marks · NAT

Consider the following program snippet. Assume that the program compiles and runs successfully. Further, assume that the fork() system call is always successful in creating a process.

int main () {
    int i;
    for (i = 0; i < 3; i++){
        if (fork() == 0){
            continue;
        }
        break;
    }
    printf("Hello!");
    return 0;
}

The total number of times that the printf statement gets executed is ________. (answer in integer)

Answer and solution
See the question in the paper
GATE 2026 CS1 Q.63: answer and solution

GATE 2025 CS1 Q.29

GATE 2025 · CS1Q.29 · 1 mark · NAT

Suppose in a multiprogramming environment, the following C program segment is executed. A process goes into I/O queue whenever an I/O related operation is performed. Assume that there will always be a context switch whenever a process requests for an I/O, and also whenever the process returns from an I/O. The number of times the process will enter the ready queue during its lifetime (not counting the time the process enters the ready queue when it is run initially) is ________. (Answer in integer)

int main()
{
    int x=0,i=0;
    scanf("%d",&x);
    for(i=0; i<20; i++)
    {
        x = x+20;
        printf("%d\n",x);
    }
    return 0;
}
Answer and solution
See the question in the paper
GATE 2025 CS1 Q.29: answer and solution

GATE 2024 CS1 Q.24

GATE 2024 · CS1Q.24 · 1 mark · MSQ

Which of the following statements about threads is/are TRUE?

  1. (A)

    Threads can only be implemented in kernel space

  2. (B)

    Each thread has its own file descriptor table for open files

  3. (C)

    All the threads belonging to a process share a common stack

  4. (D)

    Threads belonging to a process are by default not protected from each other

Answer and solution
See the question in the paper
GATE 2024 CS1 Q.24: answer and solution

GATE 2024 CS1 Q.57

GATE 2024 · CS1Q.57 · 2 marks · NAT

Consider the following code snippet using the fork() and wait() system calls. Assume that the code compiles and runs correctly, and that the system calls run successfully without any errors.

int x = 3;
while(x > 0) {
  fork();
  printf("hello");
  wait(NULL);
  x--;
}

The total number of times the printf statement is executed is _______

Answer and solution
See the question in the paper
GATE 2024 CS1 Q.57: answer and solution

GATE 2024 CS2 Q.25

GATE 2024 · CS2Q.25 · 1 mark · MSQ

Consider a process P running on a CPU. Which one or more of the following events will always trigger a context switch by the OS that results in process P moving to a non-running state (e.g., ready, blocked)?

  1. (A)

    P makes a blocking system call to read a block of data from the disk

  2. (B)

    P tries to access a page that is in the swap space, triggering a page fault

  3. (C)

    An interrupt is raised by the disk to deliver data requested by some other process

  4. (D)

    A timer interrupt is raised by the hardware

Answer and solution
See the question in the paper
GATE 2024 CS2 Q.25: answer and solution

GATE 2020 CS Q.12

GATE 2020 · CSQ.12 · 1 mark · MCQ

Consider the following statements about process state transitions for a system using preemptive scheduling.

I. A running process can move to ready state.
II. A ready process can move to running state.
III. A blocked process can move to running state.
IV. A blocked process can move to ready state.

Which of the above statements are TRUE?

  1. (A)

    I, II, and III only

  2. (B)

    II and III only

  3. (C)

    I, II, and IV only

  4. (D)

    I, II, III, and IV

Answer and solution
See the question in the paper
GATE 2020 CS Q.12: answer and solution

OTHER EXAMS

ISRO: 3 questions

From ISRO's Scientist/Engineer written test: ISRO CS 2025, ISRO CS 2023. They are not counted in the GATE numbers on this page.

ISRO CS 2025 Q.64

ISRO 2025 · CSQ.64 · 1 mark · MCQ

64. Operating systems must provide a mechanism for parent processes to create new child processes. Which of the following statements is true when a parent process creates new process?

  1. (A)

    The parent continues to execute concurrently with its children

  2. (B)

    The parent waits until some or all of its children have terminated

  3. (C)

    The parent waits for the child process by issuing a signal ( ) system call

  4. (D)

    Both (a) and (b)

Official answer

Official answer: ASource: ISRO's final answer key of 15 May 2026

See the question in the paper
ISRO CS 2025 Q.64: official answer

PRACTICE

5 questions to test yourself

PRACTICE 11 mark · NAT

Assume every call succeeds and each printf appears once per process that executes it. How many times is hi printed when this program runs?

int main()
{
    fork() && fork();
    fork();
    printf("hi\n");
    return 0;
}
Answer and solution

Answer:

  1. In fork() && fork() the original P calls the first fork(), creating child A. P gets a non-zero value, so P also calls the second fork(), creating child B.

  2. A got 0 from its first fork, so the && is short-circuited and A does not call the second fork(). B got 0 from the second fork, which ends the expression for it. After the expression there are 3 processes: P, A and B.

  3. The next statement fork(); is executed by all 3 processes, which doubles the count to 6.

  4. All 6 processes reach printf, so hi is printed 6 times.

PRACTICE 21 mark · MCQ

A process has 4 user-level threads, all mapped on a single kernel thread (many-to-one model). One of the threads makes a blocking read system call on a disk file. What happens?

  1. (A)

    Only that thread blocks; the other 3 keep running

  2. (B)

    The whole process blocks, including the other 3 threads, until the read completes

  3. (C)

    The 3 other threads run in parallel on other CPUs

  4. (D)

    The kernel creates a new kernel thread for the blocked thread

Answer and solution

Answer: (B)

  1. In the many-to-one model the kernel sees one schedulable entity for the whole process.

  2. A blocking system call blocks that kernel thread, and so every user thread mapped on it.

  3. Parallel execution on several CPUs is impossible with a single kernel thread, which rules out C. The kernel does not create kernel threads on its own in this model, which rules out D. The answer is B.

PRACTICE 32 marks · MSQ

Which of the following are private to each thread of a multithreaded process (not shared with the other threads of the same process)?

  1. (A)

    The stack

  2. (B)

    The heap

  3. (C)

    The saved register set, including the program counter

  4. (D)

    The table of open files

Answer and solution

Answer: (A), (C)

  1. Each thread runs its own sequence of calls, so it needs its own stack, which makes A true.

  2. Each thread has its own program counter and registers, so that it can be suspended and resumed independently: C is true.

  3. The heap and the open-file table belong to the process and are shared by all its threads, so B and D are false.

  4. The answer is A and C.

PRACTICE 42 marks · NAT

Assume every call succeeds; every process, including each child, continues the loop from the point where it was created, with the loop counter value it had then. How many processes are created in all, counting the original one?

int main()
{
    int i;
    for (i = 0; i < 3; i++) {
        fork();
        if (i == 1)
            fork();
    }
    return 0;
}
Answer and solution

Answer:

  1. Every process, original or created, executes every remaining part of the loop from where it was created, so each iteration multiplies the number of processes by 2 for each fork() that every process executes in it.

  2. Iteration i = 0: one fork(), so the count doubles (factor 2).

  3. Iteration i = 1: the first fork() doubles the count; every process, including the new children, then has i = 1 and executes the second fork() inside the if, which doubles it again (factor 4).

  4. Iteration i = 2: one fork() (factor 2).

  5. Total = 1 x 2 x 4 x 2 = 16.

PRACTICE 51 mark · MCQ

What are the lines printed, and their order, by the following program (all calls succeed)?

int main()
{
    int x = 10;
    if (fork() == 0) {
        x = x + 5;
    } else {
        wait(NULL);
        x = x * 2;
    }
    printf("%d\n", x);
    return 0;
}
  1. (A)

    15 then 20

  2. (B)

    20 then 15

  3. (C)

    15 then 30

  4. (D)

    20 then 20

Answer and solution

Answer: (A)

  1. The child (fork returns 0) changes its own copy: x = 15, and it prints 15.

  2. The parent waits for the child to end, so the child's line comes first.

  3. The parent's copy of x is still 10, so after waiting it becomes 20 and the parent prints 20.

  4. The output is 15 then 20, which is option A.

OFFICIAL GATE 2027 SYLLABUS WORDING

Copied from the GATE 2027 syllabus; see all 2027 syllabi.

GATE CS

System calls, processes, threads

Preparing in Kolkata? IAE Academy's course for GATE CSE.