Kernel (computer science)

From Free net encyclopedia

In computer science, the kernel is the core piece of most operating systems. It is a piece of software responsible for hardware and software components to communicate.

As a basic component of an operating system, a kernel provides abstraction layers for hardware, especially for memory, processors and communication between hardware and software. It also provides software facilities such as process abstractions and makes interprocess communication easier.

A kernel might even not be allowed to use all of the abstraction mechanisms it provides to other software<ref>Various reason forbid a kernel to use facilities it provides; such as : interruptions management, memory space management and lack of reentrance.</ref>. It's central position in an operating system implies the necessity for good performance. This makes the kernel a critical piece of software and makes it's design and implementation difficult. However, technology has been created to make kernel programming easier while retaining good performance.

Contents

Introduction

Most, but not all operating systems rely on the kernel concept. The existence of a kernel, i.e. of a single piece of software responsible for the communication between the hardware and the software, results from complex compromises relating to questions of performance, security and processor architectures.

In most operating systems, the kernel starts as a process invoked by the boot loader, but after initialisation, it is not a process as we know it, but a whole of functions that can be invoked by userland applications using system calls in order to perform operations that need a higher privilege level. Kernel execution streams are a continuation of execution streams of userland processes which are paused when performing system calls and resumed when those return. By definition, there is also an "idle process", which collects unused processor time (and does nothing with).

Actually, an operating system (and thus, a kernel) is not strictly required in order to run a computer. Programs can be directly loaded and executed on the "bare metal" machine, provided that the authors of those programs are willing to do without any hardware abstraction or operating system support. This was the normal operating method of many early computers, which were reset and reloaded between the running of different programs. Eventually, small ancillary programs such as program loaders and debuggers were typically left in-core between runs, or loaded from read-only memory. As these were developed, they formed the basis of what became early operating system kernels. The "bare metal" approach is still used today on some video game consoles and embedded systems, but in general, newer systems will use modern operating systems and kernels.

Tasks of a kernel

The definition of a kernel is basically a house-keeping program that runs at the highest privilege level, manages the computer's resources and allows other programs to run. This involves tasks such as:

Furthermore, a kernel must provide userland programs a way to access these services through some kind of system calls.

Memory management

The kernel has full access to the system's memory and must provide a method to allow userland programs to access this memory securely. The first step of doing this is virtual addressing, usually achieved by paging or segmentation. Virtual addressing allows the kernel to make a given physical address appear to be another address, the virtual address. This allows every program to believe that it is the only one (apart from the kernel) running and thus prevents applications from crashing each other.

Virtual addressing also allows to create virtual partitions of the memory in two disjoind areas, one being reserved for the kernel (Kernel space) and the other for the applications (User space). This fundamental partition of the memory space have contributed a lot to give their current content and design to actual generalistic kernels.

In order to run many programs simultaneously, an operating system will often need more memory than the amount that is actually present. A commonly used solution to this is virtual memory, which allows the kernel to store parts of the memory elsewhere (such as a swap file on a hard disk) and then retrieve the information as it is requested.

Process management

The main task of an operating system kernel is to allow other applications to be executed and support them with additional features, such as hardware abstractions. To run a process, a kernel must load its file to memory (and eventually set up its own address space, as described in the previous section), set up a stack for the program and jump to a given location inside the program, thus starting its execution.

Multi-tasking kernels are able to give the illusion that the number of processes being run simultaneously on the computer is higher than the maximum number of processes the computer is able to run simultaneously. Typically, a single processor computer is only able to run one task at the same time; a dual-processor computer can only run two tasks simultaneously, etc.

In a multitasking system, the kernel will basically give every program a slice of time and switch from process to process so quickly that it will appear to the user as if these processes were being executed simultaneously. The kernel must also provide these processes a way to communicate; this is known as Inter-process communication.

When several tasks must run in a parallel, a multi-tasking kernel uses concepts of:

There might also be multiprocessing support in the kernel; in this case, the kernel must also provide a way to synchronize programs and threads running on different processors. Thus, memory management and process management are highly inter-related.

Device management

In order to actually do something, an OS needs access to the various devices connected to the computer. These devices can be controlled through drivers, which must be written by the developers and/or be provided by the manufacturers. For example, in order to show the user anything, a VGA/VESA driver needs to be present.

A device manager first performs a scan on different hardware buses (such as PCI, USB) in order to detect all devices installed and then searchs for an appropiate driver. After this point, everything depends on the type and design of the kernel; monolithic kernels might link these drivers directly to run along with the kernel, and microkernels would start these drivers as servers. These are design decisions and may be very important when considering the kernel's performance, as for frequently accessed devices, such as the hard disk, every access involves many context switches, thus making the operation very CPU-intensive.

Thus, device management is a very OS specific topic, but in all cases, the kernel has to provide the I/O in order to allow drivers to physically access their devices.

System calls

In order to actually perform some useful work, a userland program must have access to all the services provided by the kernel. This is implemented differently by each kernel, but most provide a C library, which in turn invokes some system calls, either interrupt driven or through some shared memory.

Different kernel designs

There are four broad categories of kernels:

  • Monolithic kernels provide rich and powerful abstractions of the underlying hardware.
  • Microkernels provide a small set of simple hardware abstractions and use applications called servers to provide more functionality.
  • Hybrid kernels (modified microkernels) are much like pure microkernels, except that they include some additional code in kernelspace in order to increase performance.
  • Exokernels provide minimal abstractions, allowing low-level hardware access. In exokernel systems, library operating systems provide the abstractions typically present in monolithic kernels.


Monolithic kernels

Template:Main

In a monolithic kernel, all OS services run along with the main kernel thread, thus also residing in the same memory area. This approach provides rich and powerful hardware access. Monolithic systems are easier to design and implement than other solutions, also being very efficient if well-written. The main disadvantage of monolithic kernels is the dependency between system components - a bug might crash the entire system - and the fact that large kernels also become difficult to maintain.

Microkernels

Template:Main The microkernel approach consists of defining a simple abstraction over the hardware, with a set of primitives or system calls to implement minimal OS services such as address space management, thread management, and inter-process communication. All other services, including those normally provided by the kernel such as networking, are implemented in user-space programs referred to as servers. Microkernels are easier to maintain than monolithic kernels, but the large amount of system calls might also slow down the system because they typically carry more overhead than plain function calls.

Monolithic kernels and microkernels

Microkernels generally underperform traditional designs, sometimes dramatically. This is due in large part to the overhead of moving in and out of the kernel, a context switch, in order to move data between the various applications and servers. It was originally believed that careful tuning could reduce this overhead dramatically, but by the mid-1990s most researchers had given up. In more recent times newer microkernels, designed for performance first, have addressed these problems to a very large degree.

Development of monolithic kernels

Unix was the culmination of many years of development towards a modern operating system. In the decade preceding Unix, computers had grown enormously in power - to the point where computer operators were looking for new ways to get people to use the spare time on their machines. One of the major developments during this era was time sharing, whereby a number of users would be given small slices of computer time in sequence, but at such a speed that it appeared they were each connected to their own, slower, machine.

The development of time share systems led to a number of problems. One was that users, particularly at universities where the systems were being developed, seemed to want to hack the system. Security and access control became a major focus of the Multics effort for just this reason. Another ongoing issue was properly handling computing resources: users spend most of their time staring at the screen instead of actually using their computers' resources, and the time shared system should give the CPU time to an active user during these periods. Finally, the systems typically offered a memory hierarchy several layers deep, and partitioning this expensive resource led to major developments in virtual memory systems.

During the development of Unix, its programmers decided to model every high-level device as a file, as they believed the purpose of computation to be transformation of data. For instance, printers were represented as a "file" at a known location - when data was copied into the file, it would print out. Other systems, to provide a similar functionality, tended to virtualize devices at a lower level - that is, both devices and files would be instances of some lower level concept. Virtualizing the system at the file level allowed users to manipulate the entire system using their existing file management utilities and concepts, dramatically simplifying operation. As an extension of the same paradigm, Unix allows programmers to manipulate files using a series of small programs, using the concept of pipes, where output of one program becomes the input of another. Users could complete operations in stages, feeding a file through a series of single-purpose tools. Although the end result was the same, using smaller programs in this way dramatically increases flexibility as well as ease of development and use, allowing the user to modify their workflow by adding or removing programs from the chain.

In the Unix model, the Operating System consists of two parts; one is the huge collection of utility programs that drive most operations, the other the kernel that runs them. Under Unix the distinction between the two is fairly thin from a programming standpoint; the kernel is a program given some special privileges and running in a protected supervisor mode. The kernel's job is to act as a program loader and supervisor for the small utility programs making up the rest of the system and to provide locking and I/O services for these programs; beyond that the kernel need not intervene in the working of the programs.

Over the years the computing model changed, and Unix's everything-is-a-file no longer seemed as universally applicable as it had before. For instance, although a terminal could be treated as a file or a stream, which is printed to or read from – a glass printer in a way – the same did not seem to be true for a GUI. Networking posed a different problem. Although in some situations network communication can be equated to file access, need arose to access the lower level packet-oriented architecture, which dealt in discrete chunk of data and not whole files. As the capability of computers grew, Unix became increasingly cluttered with code. While early kernels might have had 100,000 lines of code, kernels of modern Unix successors like Linux has over four and a half million lines.

Disadvantages of monolithic kernels

As a computer's kernel grows, a number of problems become evident. One of the most obvious is that its memory footprint increases, even if the developer is not interested in many of its features. This is mitigated to some degree by increasing sophistication of the virtual memory system, but not all computers have virtual memory. In order to reduce the kernel's footprint, extensive surgery needs to be performed to carefully remove the unneeded code. Often, non-obvious dependencies that exist between parts of the kernel make this very difficult.

Another, less obvious, problem is a result of the fact that programs are tightly bound to the memory they use and the "state" of their processor. In machines with more than one processor, the former is usually not an issue, as all the processors share a common memory (in modern systems at least). However, the processor state is not so easy an issue to address in multi-processor machines. In order to allow a kernel to run on such a system, it has to be extensively modified to make it "re-entrant" or "interruptible", meaning that it can be called in the midst of doing something else. Once this conversion is complete, programs running at the same time on another processor can call the kernel without causing problems.

This task is not difficult in theory, but in a kernel with millions of lines of code it becomes a serious problem in practice. Adding to the problem is the fact that there is often a performance "hit" for implementing re-entrant code, meaning that such a conversion makes the system run slower on the vast majority of systems in the world -- those with a single processor.

The biggest problem with the monolithic kernels, or monokernels, was sheer size. The code was so extensive that working on such a large system was tedious.

Development of microkernels

Due to the problems that monolithic kernels posed, they were considered obsolete by early 1990s. As a result, the design of Linux using a monolithic kernel rather than a microkernel was the topic of a famous flame war between Linus Torvalds and Andrew Tanenbaum[1] [2]. There is merit in both sides of the arguments presented in the Tanenbaum/Torvalds debate.

Monolithic kernels tend to be easier to design correctly, and therefore may grow more quickly than a microkernel-based system. However, a bug in a monolithic system usually crashes the entire system; this would not happen in a microkernel with servers running apart from the main thread. Monolithic kernel proponents reason that incorrect code doesn't belong in a kernel, and microkernels offer little advantage for correct code. There are success stories in both camps. Microkernels are often used in embedded robotic or medical computers because most of the OS components reside in their own private, protected memory space. This is impossible with monolithic kernels, even with modern module-loading ones. However, the monolithic model tends to be more efficient through the use of shared kernel memory, rather than the slower Inter-process communication characteristic of microkernel designs.

Although Mach is the best-known general-purpose microkernel, several other microkernels have been developed with more specific aims. L3 was created to demonstrate that microkernels are not necessarily slow. L4 is a successor to L3 and a popular implementation called Fiasco is able to run Linux next to other L4 processes in separate address spaces. There are screenshots available on freshmeat.net showing this feat. A newer version called Pistachio also has this capability.

QNX is an operating system that has been around since the early 1980s and has a very minimalistic microkernel design. This system has been far more successful than Mach in achieving the goals of the microkernel paradigm. It is used in situations where software is not allowed to fail. This includes the robotic arms on the space shuttle, and machines that grind glass to very fine tolerances (a tiny mistake may cost hundreds of thousands of dollars, as in the case of the mirror of the Hubble Space Telescope).

Hybrid kernels (aka modified microkernels)

Template:Main

Hybrid kernels are essentially a compromise between the monolithic kernel approach and the microkernel system. This implies running some servers in kernel space in order to cut down on the amount of system calls occurring in a traditional microkernel. Nevertheless, there is still kernel code running in their own memory space.

Nanokernels

Template:Main

A nanokernel delegates virtually all services - including even the most basic ones like interrupt controllers or the timer - to device drivers in order to make the kernel even smaller in memory than a traditional microkernel.

Atypical microkernels

There are some microkernels which should not be considered to be pure microkernels, because they implement some functions such as server services. These "atypical" microkernels are characterized by a vast number of features which mark them as belonging to the "large microkernel" family. Foremost known in this category is Exec, the kernel of AmigaOS, and its direct descendant ExecSG (or "Exec Second Generation").

Exokernels

Template:Main

An exokernel is a type of kernel that does not abstract hardware into theoretical models. Instead it allocates the physical hardware resources, such as processor time, memory pages, and disk blocks, to different programs. A program running on an exokernel can link to a library operating system that uses the exokernel to simulate the abstractions of a well-known OS, or it can develop application-specific abstractions for better performance.

No-kernel designs

TUNES Project [3] and UnununiumOS [4] are no-kernel [5] experiments. No-kernel software is not limited to a single centralizing entry point.

See also

Operating system links

Kernel links

External links

Bibliography

  • Andrew Tanenbaum, Operating systems ;
  • Daniel P. Bovet, Marco Cesati, The Linux Kernel ;
  • David A. Peterson, Nitin Indurkhya, Patterson, Computer Organization and Design, Morgan Koffman (ISBN 1558604286) ;
  • James L. Peterson, Abraham Silberschatz, Peter B. Galvin (dir.), Operating system concepts, Addison-Wesley, 1990 (ISBN 020151379X) ;
  • B.S. Chalk, Computer Organisation and Architecture, Macmillan P. (ISBN 0333645510).

Notes

<references/>Template:Link FA

ast:Kernel ca:Nucli del sistema operatiu cs:Kernel da:Kerne (styresystem) de:Betriebssystemkern es:Núcleo (computación) fa:هسته سیستم عامل fr:Noyau (informatique) gl:Núcleo ko:커널 (컴퓨터) id:Kernel (ilmu komputer) ia:Kernel is:Stýrikerfiskjarni it:Kernel he:ליבת מערכת ההפעלה lt:Branduolys (OS) hu:Rendszermag nl:Kernel ja:カーネル no:Kjerne (datamaskiner) pl:Jądro systemu operacyjnego pt:Kernel ru:Ядро (операционной системы) simple:Kernel sl:Jedro (računalništvo) sr:Нуклеус fi:Käyttöjärjestelmän ydin sv:Operativsystemskärna th:นิวเคลียส tr:Çekirdek (unix) zh:内核