Introduction to Kernel

Posted: February 7, 2011 in Linux

The kernel makes its services available to the application programs that run on it through a large collection of entry points, known technically as system calls.

 The kernel uses system calls such as ‘read’ and ‘write’ to provide an abstraction of your hardware

From a programmer’s viewpoint, these look just like ordinary function calls, although in reality a system call involves a distinct switch in the operating mode of the processor from user space to kernel space. Together, the repertoire of system calls provides a ‘Linux virtual machine’, which can be thought of as an abstraction of the underlying hardware.

One of the more obvious abstractions provided by the kernel is the filesystem. By way of example, here’s a short program (written in C) that opens a file and copies its contents to standard output:

#include <fcntl.h>

int main()

{

    int fd, count; char buf[1000];

    fd=open(“mydata”, O_RDONLY);

    count = read(fd, buf, 1000);

    write(1, buf, count);

    close(fd);

}

Here, you see examples of four system calls – open, read, write and close. Don’t fret over the details of the syntax; that’s not important right now. The point is this: through these system calls (and a few others) the Linux kernel provides the illusion of a ‘file’ – a sequence of bytes of data that has a name – and protects you from the underlying details of tracks and sectors and heads and free block lists that you’d have to get into if you wanted to talk to the hardware directly. That’s what we mean by an abstraction.

the kernel is responsible for process scheduling. At any one time, there are likely to be several processes (programs) waiting to run.

The kernel’s scheduler allocates CPU time to each one, so that if you look over a longer timescale (a few seconds) you have the illusion that the computer is running several programs at the same time. Here’s another little C program:

#include <stdlib.h>
main()
{
  if (fork()) {
    write(1, "Parent\n", 7);
    wait(0);
    exit(0);
  }
  else {
    write(1, "Child\n", 6);
    exit(0);
  }
}

This program creates a new process; the original process (the parent) and the new process (the child) each write a message to standard output, then terminate. Again, don’t stress about the syntax. Just notice that the system calls fork(), exit() and wait() perform process creation, termination and synchronisation respectively. These are elegantly simple calls that hide the underlying compexities of process management and scheduling.

An even less visible function of the kernel, even to programmers, is memory management. Each process runs under the illusion that it has an address space (a valid range of memory addresses) to call its own. In reality, it’s sharing the physical memory of the computer with many other processes, and if the system is running low on memory, some of its address space may even be parked out on the disk in the swap area.

Another aspect of memory management is that it prevents one process from accessing the address space of another – a necessary precaution to preserve the integrity of a multi-processing operating system.

The kernel also implements networking protocols such as IP, TCP and UDP that provide machine-to-machine and process-to-process communication over a network. Again, this is all about illusions. TCP provides the illusion of a permanent connection between two processes – like a piece of copper wire connecting two telephones – but in reality no permanent connection exists. Note that specific application protocols such as FTP, DNS or HTTP are implemented by user-level programs and aren’t part of the kernel.

The modular kernel

Now we have some idea of what the kernel does, let’s look briefly at its physical organisation. Early versions of the Linux kernel were monolithic – that is, all the bits and pieces were statically linked into one (rather large) executable file.

In contrast, modern Linux kernels are modular: a lot of the functionality is contained in modules that are loaded into the kernel dynamically. This keeps the core of the kernel small and makes it possible to load or replace modules in a running kernel without rebooting.

The core of the kernel is loaded into memory at boot time from a file in the /boot directory called something like vmlinuz-KERNELVERSION, where KERNELVERSION is, of course, the kernel version. (To find out what kernel version you have, run the command uname -r.) The kernel’s modules are under the directory /lib/modules/KERNELVERSION. All of these pieces were copied into place when the kernel was installed.

It’s also possible to configure and build your own kernel. For this, you might try Greg Kroah-Hartman’s Linux Kernel in a Nutshell, an O’Reilly title that makes a delightful but presumably unintended play on words. But, of course, you have to be nuts to make a kernel.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s