Real-time Extensions Of Linux Operating Systems
Real-Time Extensions of Linux Operating Systems
The adoption of Linux has increased steadily in recent years as the operating system becomes increasingly more stable, its performance improves, and more and more Linux applications become available. The remainder of this section describes two extensions that enable applications with firm or hard real-time requirements to run on Linux. As you will see shortly, these extensions fall far short of making Linux compliant to POSIX real-time extensions. More seriously, applications written to run on these extensions are not portable to standard UNIX machines or other commercial real-time operating systems.
Important Features. Like NT, Linux also has many shortcomings when used for real-time applications. One of the most serious arises from the disabling of interrupts by Linux subsystems when they are in critical sections. While most device drivers disable interrupts for a few microseconds, the disk subsystem may disable interrupts for as long as a few hundred microseconds at a time. The predictability of the system is seriously damaged when clock interrupts can be blocked for such a long time. The solution to this problem is to rewrite all the offending drivers to make their nonpreemptable sections as short as possible, as they are in real-time operating systems. Neither extension described below attacked this problem head on; rather, one tries to live with it, while the other avoids it.
Scheduling. Linux provides individual processes with the choices among SCHED FIFO, SCHED RR, or SCHED OTHER policies. Processes using the SCHED FIFO and SCHED RR policies are scheduled on a fixed-priority basis; these are real-time processes. Processes using SCHED OTHER are scheduled on the time-sharing basis; they execute at priorities lower than real-time processes.
There are 100 priority levels altogether. You can determine the maximum and minimum priorities associated with a scheduling policy using the primitives sched get priority min( ) and sched get priority max( ). You can also find the size of the time slices given to processes scheduled according to the round-robin policy using sched rr get interval( ). Since you have the source, you can also change these parameters.
Clock and Timer Resolutions. Like NT, Linux updates the system clock and checks for timer expirations periodically, and the period is 10 milliseconds on most hardware platforms. [In Linux, each clock interrupt period is called a jiffy, and time is expressed in terms of (the number of) jiffies.] Consequently, the actual resolution of Linux timers is 10 milliseconds. To improve the clock resolution on Pentium processors, the kernel reads and stores the time stamp counter at each clock interrupt. In response to a gettimeofday call, it reads the counter again and calculates from the difference in the two readings the number of microseconds that have elapsed from the time of the previous timer interrupt to the current time. In this way, it returns the current time to the caller in terms of jiffies and the number of microseconds into the current jiffy.
In addition to reading the time stamp counter at each clock interrupt, the timer interrupt service routine checks the timer queue to determine whether any timer has expired and, for each expired timer found, queues the timer function that is to be executed upon the expiration of that timer. The timer functions thus queued are executed just before the kernel returns control to the application. Timer error can be large and unpredictable because of the delay thus introduced by the kernel and possibly large execution times of the timer functions.
Threads. Until recently, Linux did not offer a thread library. Rather, it offers only the low-level system call clone( ). Using this system call, one can create a process that shares the address space of its parent process, as well as the other parts of the parent’s context (e.g., open file descriptors, message managers, and signal handlers) as specified by the call.
Recently, X. Leroy developed LinuxThreads. Each thread provided by this thread library is a UNIX process that is created using the clone( ) system call. These threads are scheduled by the kernel scheduler just like UNIX processes. LinuxThread provides most of the POSIX thread extension API functions and conforms to the standard except for signal handling.29 In particular, LinuxThreads uses signals SIGUSR1 and SIGUSR2 for its own purpose. As a consequence, these signals are no longer available to applications. Since Linux does not support POSIX real-time extensions, there is no signal for application-defined use! Moreover, signals are not queued and may not be delivered in priority order.
The major advantage of the one-thread-per process model of LinuxThreads is that it simplifies the implementation of the thread library and increases its robustness. A disadvantage is that context switches on mutex and condition operations must go through the kernel. Fortunately, context switches in the Linux kernel are efficient.