black rotary dial phone on white surface
Mon Sep 04

System Calls in OS

Have you ever wondered how your computer’s software interacts with its underlying hardware? How do they access files, devices, processes, and other system resources? How do they communicate with each other over a network? Well, the secret sauce that makes this interaction possible is known as “system calls”. While the term may sound complex, system calls are the fundamental building blocks that enable your programs to communicate with the core of your computer’s operating system.

What are system calls?

System calls are a special set of procedures that allow user programs to request services from the kernel of the operating system (OS kernel). You can see it as the bridge between programs and the operating system. A user program is any application or process that runs on your computer, such as a web browser, a text editor, or a game. The OS kernel is the core part of the OS that controls the basic functions of your computer, such as memory management, process scheduling, device drivers, file systems, network protocols, etc.

Why need system calls?

You may asked, “What if we don’t have system calls?“. To answer this, we need to know that system calls provide a standardized and secure way for user programs to access system resources. Without system calls, each user program would have to implement its own methods for interacting with the hardware and the OS kernel, which would lead to inconsistency, inefficiency, and potential errors. System calls also provide protection and security for the system by preventing unauthorized or malicious access to sensitive or critical parts of the OS kernel.

Types of system calls in OS

System calls can be classified into five major categories, depending on the type of service they provide:

Process control system calls

These system calls are used to create, terminate, or control the execution of processes. For example, some common process control system calls are:

  • fork(): Creates a new child process that is a copy of the parent process
  • exec(): Replaces the current process with a new program
  • wait(): Waits for a child process to terminate and returns its exit status
  • exit(): Terminates the current process and returns an exit status
  • kill(): Sends a signal to a specified process to terminate it

File management system calls

These system calls are used to create, delete, open, close, read, write, or manipulate files. For example, some common file management system calls are:

  • open(): Opens a file and returns a file descriptor
  • close(): Closes a file descriptor
  • read(): Reads data from a file into a buffer
  • write(): Writes data from a buffer to a file
  • lseek(): Changes the current position of a file pointer
  • rename(): Renames a file or directory
  • unlink(): Deletes a file or directory

Device management system calls

These system calls are used to request access to or release devices, such as disks, keyboards, printers, or monitors. For example, some common device management system calls are:

  • ioctl(): Performs device-specific operations on a file descriptor
  • read() and write(): Same as for files, but for devices
  • mmap(): Maps a file or device into memory

Information maintenance system calls

These system calls are used to get or set information about processes, files, devices, or the system. For example, some common information maintenance system calls are:

  • getpid(): Returns the process ID of the current process
  • getppid(): Returns the process ID of the parent process
  • getuid(): Returns the user ID of the current process
  • getgid(): Returns the group ID of the current process
  • stat(): Returns information about a file or directory
  • time(): Returns the current system time
  • gethostname(): Returns the name of the host machine

Communication system calls

These system calls are used to establish or terminate communication between processes or machines. They can be either message-based or stream-based. For example, some common communication system calls are:

  • socket(): Creates a new communication endpoint
  • bind(): Associates a local address with a socket
  • listen(): Marks a socket as passive and ready to accept connections
  • accept(): Accepts a connection request from a remote socket
  • connect(): Initiates a connection to a remote socket
  • send() and recv(): Sends and receives messages from a socket
  • write() and read(): Same as for files, but for sockets
  • shutdown(): Closes one or both directions of communication on a socket

How system calls work?

To understand how system calls work and how to use them, we need to know some basic concepts about the user space and kernel space, OS architecture, CPU modes.

User space and kernel space are two regions of memory that are used by the OS and the user programs. User space is the region of memory that is allocated for user programs to run and store their data. On the other hand, kernel space is the region of memory that is reserved for the OS kernel to run and store its data.

The OS architecture and the CPU modes are related to the user space and the kernel space in the following ways:

  • The OS architecture determines how the user space and the kernel space are organized and interact with each other. The layered architecture divides the OS into several layers that provide different services and functionalities to the user programs and the OS itself. The user interface layer, the system library layer, and some parts of the intermediate layers belong to the user space, while the OS kernel layer and some parts of the intermediate layers belong to the kernel space.
  • The CPU modes determine how the user programs and the OS kernel access the user space and the kernel space. User mode is the mode in which user programs run and access only the user space. Kernel mode is the mode in which the OS kernel runs and accesses both the user space and the kernel space. User programs cannot access kernel space directly, they can only access it through system calls, which cause a switch from user mode to kernel mode. The OS kernel can access user space directly, but it has to follow some rules and precautions to avoid corrupting or interfering with user programs.

System calls are the way for user programs and the OS kernel to communicate and access system resources. System calls are related to the user space and the kernel space in the following ways:

  • System calls provide a standardized and secure interface between the user space and the kernel space. User programs do not need to know the details of the hardware or the OS kernel, they only need to know the interface and the parameters of the system calls. System calls also prevent user programs from accessing kernel space directly, which could cause damage or compromise to the system.
  • System calls involve a switch from user mode to kernel mode and vice versa. When a user program makes a system call, it executes a special instruction that causes a trap or an exception, which switches the CPU from user mode to kernel mode. The OS kernel then handles the system call and returns control back to the user program, which switches the CPU back from kernel mode to user mode. This switch involves saving and restoring the state of the user program and the OS kernel, which adds some overhead to the system.
  • System calls can access both user space and kernel space. The OS kernel can access user space directly, but it has to follow some rules and precautions to avoid corrupting or interfering with user programs. For example, the OS kernel has to copy data from user space to kernel space before processing it, and copy it back from kernel space to user space after processing it. The OS kernel also has to check the validity and legality of the parameters and return values of user programs, and handle any errors or exceptions that may occur.

System Calls in OS

System calls work differently in different operating systems. However, they all follow a similar pattern:

1. The program invokes a library function that corresponds to a system call. The library function is a wrapper that simplifies the usage of the system call for the program.
2. The library function prepares the arguments and registers for the system call and executes a special instruction that triggers a software interrupt or an exception. This instruction transfers the control from the user mode to the kernel mode of the processor.
3. The kernel mode handler of the software interrupt or the exception checks the validity and security of the system call number and arguments. It then invokes the appropriate system call service routine that performs the requested service.
4. The system call service routine executes the service and returns a result or an error code to the kernel mode handler.
5. The kernel mode handler restores the registers and returns the control to the user mode by executing another special instruction. The library function receives the result or the error code and passes it to the program.

However, different operating systems have different implementations of system calls. For example, Windows and Linux have different sets of system calls, different ways of invoking them, and different ways of handling them.

Windows System Calls

Windows is a family of operating systems that use a layered architecture. The lowest layer is the hardware abstraction layer (HAL), which provides a uniform interface to access hardware devices. The next layer is the kernel, which consists of several components, such as the executive, the microkernel, and device drivers. The executive provides various services to user processes, such as memory management, process management, security, etc. The microkernel handles interrupts, exceptions, and system calls. Device drivers communicate with hardware devices and provide device-specific functions.

Windows system calls are also known as Windows API (Application Programming Interface) or Win32 API. They are divided into several categories, such as graphics, user interface, networking, file system, etc. Windows system calls are invoked by using library functions that are provided by dynamic link libraries (DLLs). DLLs are files that contain executable code that can be loaded and executed by different programs.

Windows system calls use a fast system call mechanism that involves a special instruction called sysenter. This instruction transfers the control from user mode to kernel mode by jumping to a predefined address in the HAL. The HAL then invokes the appropriate system call service routine in the executive or device drivers. The result or error code is returned to user mode by using another special instruction called sysexit.

Linux System Calls

Linux is a family of operating systems that use a monolithic kernel architecture. The kernel is a single executable file that contains all the core components of the operating system, such as memory management, process management, file system, networking, device drivers, etc. The kernel provides various services to user processes through system calls.

Linux system calls are identified by numbers that are defined in header files. They are invoked by using library functions that are provided by the GNU C Library (glibc). glibc is a standard library that implements various functions and macros for C programs.

Linux system calls use different mechanisms depending on the processor architecture. For example, on x86 processors, Linux system calls use an instruction called int 0x80. This instruction generates a software interrupt with number 0x80, which is handled by the kernel mode handler of interrupts. The handler checks the validity and security of the system call number and arguments and invokes the appropriate system call service routine in the kernel. The result or error code is returned to user mode by using another instruction called iret.

Examples of System Calls in OS

Different operating systems may have different sets of system calls, depending on their design and functionality. However, some system calls are common across most operating systems, such as those for process control, file management, device management, information maintenance, and communication. Here are some examples of system calls in three popular operating systems: Linux, Windows, and MacOS:

System CallLinuxWindowsMacOS
Create a processfork()CreateProcess()fork()
Execute a programexec()CreateProcess()exec()
Terminate a processexit()ExitProcess()exit()
Wait for a processwait()WaitForSingleObject()wait()
Send a signal to a processkill()TerminateProcess()kill()
Open a fileopen()CreateFile()open()
Close a fileclose()CloseHandle()close()
Read from a fileread()ReadFile()read()
Write to a filewrite()WriteFile()write()
Change the position of a file pointerlseek()SetFilePointer()

lseek()
Rename a file or directory| rename()| MoveFile()| rename()
Delete a file or directory| unlink()| DeleteFile(), RemoveDirectory()| unlink(), rmdir()
Perform device-specific operations on a file descriptor| ioctl()| DeviceIoControl()| ioctl()
Map a file or device into memory| mmap()| CreateFileMapping(), MapViewOfFile()| mmap()
Get the process ID of the current process| getpid()| GetCurrentProcessId()| getpid()
Get the user ID of the current process| getuid()| GetUserName()| getuid()
Get information about a file or directory| stat()| GetFileAttributes(), GetFileInformationByHandle()| stat()
Get the current system time| time()| GetSystemTime(), GetLocalTime()| time(), gettimeofday()
Get the name of the host machine| gethostname()| GetComputerName()| gethostname()
Create a socket| socket()| socket()| socket()
Bind a socket to a local address| bind()| bind()| bind()
Listen for incoming connections on a socket| listen()| listen()| listen()
Accept a connection request from a remote socket| accept()| accept()| accept()
Connect to a remote socket| connect()| connect()| connect()
Send and receive messages from a socket| send(), recv()| send(), recv(), or WSASend(),WSARecv()| send(), recv(), or write(), read()
Close one or both directions of communication on a socket| shutdown()| shutdown()| shutdown()

As you can see, system calls are essential for user programs to communicate with the operating system and access the hardware resources. They provide a standardized and abstracted interface that hides the complexity and diversity of the underlying hardware and software. System calls are also the basis for many higher-level functions and libraries that user programs can use to perform various tasks.

Examples of system calls

Here are some examples of how to use some common system calls in C language:

fork()

This system call creates a new process by duplicating an existing process. The new process is calledthe child process and the existing process is called the parent process. The child process inherits most of the attributes of the parent process, such as open files, environment variables, etc., but has its own memory space and process ID. The fork() system call returns a value to both the parent and the child processes. The value is 0 for the child process, positive for the parent process (the child’s process ID), and negative for an error. The fork() system call can be used to create multiple processes that can run concurrently or in parallel. For example, the following code snippet creates two child processes and prints their process IDs:

int main() {
	int pid1, pid2;
	pid1 = fork(); // create first child process
	if (pid1 == 0) { // in first child process
		printf("I am the first child, my pid is %d\n", getpid());
	} else if (pid1 > 0) { // in parent process
		pid2 = fork(); // create second child process
		if (pid2 == 0) { // in second child process
			printf("I am the second child, my pid is %d\n", getpid());
		} else if (pid2 > 0) { // in parent process
			printf("I am the parent, my pid is %d\n", getpid());
		} else { // error occurred
			perror("fork");
		}
	} else { // error occurred
		perror("fork");
	}
	return 0;
}

open()

This system call opens a file and returns a file descriptor that can be used to access the file. A file descriptor is an integer that identifies a file or a device. The open() system call takes two or three parameters: the name of the file, the mode of opening the file, and optionally the permissions of the file. The mode of opening the file can be read-only, write-only, read-write, append, etc. The permissions of the file can be specified as a combination of read, write, and execute bits for the owner, group, and others. The open() system call returns a positive value for a successful operation or -1 for an error. The open() system call can be used to create new files or modify existing files. For example, the following code snippet opens a file named “test.txt” in write-only mode and creates it if it does not exist:

int main() {
	int fd;
	fd = open("test.txt", O_WRONLY | O_CREAT, 0644); // open file in write-only mode and create it if not exist
	if (fd == -1) { // error occurred
		perror("open");
	} else { // success
		printf("File opened successfully, file descriptor is %d\n", fd); // write data to file using write() system call
		close(fd); // close file using close() system call
	}
	return 0;
}

read()

This system call reads data from a file or a device and stores it in a buffer. The read() system call takes three parameters: the file descriptor of the file or device, the address of the buffer, and the number of bytes to read. The read() system call returns the number of bytes actually read or -1 for an error. The read() system call can be used to read data from files, keyboards, mice, etc. For example, the following code snippet reads 100 bytes from a file named “test.txt” and prints them on the screen:

int main() {
	int fd, n;
	char buf[100];
	fd = open("test.txt", O_RDONLY); // open file in read-only mode
	if (fd == -1) { // error occurred
		perror("open");
	} else { // success
		n = read(fd, buf, 100); // read 100 bytes from file
		if (n == -1) { // error occurred
			perror("read");
		} else { // success
			printf("Read %d bytes from file, data is:\n", n);
			write(1, buf, n); // write data to standard output device (screen)
			}
		close(fd); // close file
	}
	return 0;
}

Conclusion

We have seen that system calls are a vital component of any operating system and user program, as they provide a bridge between them. We have learned what system calls are, how they work, and how they are classified and understand some examples of system calls and how it may different based on the operating systems. Thank you for reading this article. If you liked it, please share it with your friends or colleagues who might be interested in learning about system calls in OS.