Originally Published: Wednesday, 15 August 2001 Author: Subhasish Ghosh
Published to: develop_articles/Development Articles Page: 1/4 - [Printable]

Understanding Re-entrant Kernels

Undertanding the details of the Linux kernel may seem beyond the reach of many people, but at Linux.com we don't believe in "beyond the reach". In this article Ghosh begins his exploration down into the depths of the machine with a look at how a multi-threaded program can help illustrate re-entrancy, and vica versa.

An Overview of Unix Kernels   Page 1 of 4  >>

If you ever go to a book-shop, pick up a book on "Linux Kernel Architecture" or "Unix Kernel Architecture", or maybe even a book on "Linux Kernel programming" which has topics like 'POSIX Threads', 'Processes and Signals' etc. you are bound to come across words such as 'Re-entrancy', 'Re-entrant Kernels', 'Re-entrant threads' and so on. So, what does the word "Re-entrant' mean?

This article begins to explores the depths of the Linux, in other words, the Unix Kernel architecture, in this case specifically the term "Re-entrancy". So, these are the things that will be covered:

  1. An Overview of the Unix/Linux Kernel Architecture (in relation to "Re-entrancy").

  2. What the term "Re-entrant Kernel" means.

  3. A practical example illustrating "re-entrancy" at its best.

Please Note:

Though "re-entrancy" is an advanced topic in Linux Kernel architecture, I will try to explain all other things that need to be mentioned for proper understanding of the subject matter. The example shown at the end illustrating "re-entrant routines" uses "POSIX Threads" as its core.

I have used Red Hat Linux 7.1, Linux Kernel 2.4.2-2 for compiling all the code.

An Overview of Unix Kernels

In Unix Kernels, applications (i.e. executables) run in a specific execution environment that is provided by the Kernel. Thus, the Kernel implements a set of services, interfaces and other resources that the applications use for interacting with the hardware resources of the system (like the keyboard, monitor etc). The applications don't just directly interact with the hardware resources.

Let's look into the "Unix Process/Kernel Model" in more detail. A CPU either runs in User Mode or in Kernel Mode. (Please note however, Intel 80x86 microprocessors have four different execution states.) But, all standard Unix Kernels implements the User and the Kernel Mode.

When an application is running in User Mode, it cannot directly access the kernel programs, more precisely the Kernel data structures. But, when an application is executing in Kernel Mode, there are no restrictions on accessing the kernel data structures. An application mostly executes in the User mode, and switches to Kernel mode only when it needs to utilize a particular resource managed by the Kernel. Different CPU models govern this "switching" of an application from the User to the Kernel mode. Each CPU model provides special instructions to switch from User Mode to Kernel Mode and vice-versa when required.

Now let's talk about "processes" and "threads". A process is simply an application/program in execution. The path of execution defines a "thread". And an execution context is defined as an "apartment". In many articles and books, I have come across this line: "a "thread" is a Light-weight process". I personally feel that this definition of a "thread" is an injustice to threads! It's like defining Linux in terms of Microsoft Windows 98. 'Processes' and 'Threads' are two totally different entities and should never be defined in terms of one another. (For a very detailed coverage of "POSIX Threads", please refer to one of my forth coming articles at Linux.com.)

Now, the task of creating, eliminating and synchronizing processes is controlled by a group of routines in the Kernel. Same with POSIX threads. This group of routines are referred to as "re-entrant routines". An example illustrating "POSIX Threads using re-entrant routines" will been given later.

An important point to keep in mind while dealing with Unix/Linux Kernels is: The Kernel is not a process but only a process manager. The Process/Kernel model assumes that processes that require a kernel service utilize specific program constructs called "system calls". When a "system call" is invoked by a process (an executing program), the system call sets up a group of parameters, which then identifies the process request, then hands over the power to the CPU, which then performs the earlier mentioned "switching" of the process from User Mode to Kernel Mode.

Kernel Threads

Now, let's talk a little about "Kernel Threads". Kernel threads are very easy to understand, but extremely difficult when it comes to implementing them in the real world. Programming multithreaded applications in Linux can be an extremely hazardous task at times, and dangerous too, and is one of the most advanced stages in Linux programming. The question that arises here is: Why? The answer is: Kernel threads run in Kernel mode in the Kernel address space. (Please note: Each process runs in its private address space.) A process running in User Mode refers to a private stack, private data and code sections. When it runs in Kernel Mode (as Kernel threads do), it addresses the kernel data and code area directly. So, if you write a program that runs in User mode, and it corrupts some code section (often referred to as "malicious code"), in most cases it receives a "Segmentation fault (core dumped)" memory segmentation fault error and exits. This doesn't happen in Kernel Mode when you have a faulty Kernel Thread running, which can ultimately crash a running system.

On a uniprocessor system only one process is running at any given point in time and it may run either in User or in Kernel Mode. If it runs in Kernel Mode, the processor is executing some Kernel routine. Let's look at a transition between User and Kernel Mode more closely. Suppose we have a process named Process 1 initially running in User Mode. Process 1 issues a system call, after which Process 1 is switched to Kernel Mode and the system call is thus serviced. After the system call has been serviced, Process 1 then resumes execution in User Mode. All this time (while you were reading this section), another process named Process 2 has appeared and is waiting for its turn in User Mode. A timer interrupt occurs, and the "scheduler" in Kernel Mode is activated. Thus, a process switch takes place, Process 2 starts execution in User Mode until a particular hardware raises an interrupt. As a result of this interrupt, Process 2 switches to Kernel Mode and finally the interrupt is serviced. It then again switches back to User Mode. This is how transitions take place between the two modes.

After reading to this point, the most obvious question in the minds of the readers might be: This article was supposed to explain "Re-entrant Kernels". What has all this got to do with that? Well, a lot. Since understanding the basic operations of "Processes" and "Kernel Threads" is what re-entrancy is all about. So, let's move on to the next section.

An Overview of Unix Kernels   Page 1 of 4  >>