You can get real-time response when certain conditions are met. This section identifies these conditions and some of the more significant design errors.
Most of the potential problems described here can degrade the response time of the system. One of the potential problems can freeze a workstation. Other, more subtle, mistakes are priority inversion and system overload.
An Oracle Solaris real-time process has the following characteristics:
Runs in the RT scheduling class, as described in Real-Time Scheduler
Locks down all the memory in its process address space, as described in Memory Locking
Is from a program in which all dynamic binding is completed early, as described in Shared Libraries
Real-time operations are described in this chapter in terms of single-threaded processes, but the description can also apply to multithreaded processes. For more information about multithreaded processes, see Multithreaded Programming Guide. To ensure real-time scheduling of a thread, the thread must be created as a bound thread. The thread's LWP must be run in the RT scheduling class. The locking of memory and early dynamic binding is effective for all threads in a process.
When a real-time process has the highest priority, the process acquires the processor within the specified dispatch latency period of becoming runnable. For more information, see Dispatch Latency. The process continues to run as long as it is the highest priority runnable process.
A real-time process can lose control and can also be unable to gain control of the processor because of other system events. These events include external events, such as interrupts, resource starvation, waiting on external events such as synchronous I/O, and preemption by a higher priority process.
The problems described in this section increase the response time of the system to varying extents. The degradation can be serious enough to cause an application to miss a critical deadline.
Real-time processing can also impair the operation of aspects of other applications that are active on a system that is running a real-time application. Because real-time processes have higher priority, time-sharing processes can be prevented from running for significant amounts of time. This phenomenon can cause interactive activities, such as displays and keyboard response time, to slow noticeably.
System response running Oracle Solaris provides no bounds to the timing of I/O events. This means that synchronous I/O calls should never be included in any program segment whose execution is time critical. Even program segments that permit very large time bounds must not perform synchronous I/O. Mass storage I/O is such a case, where causing a read or write operation hangs the system while the operation takes place.
A common application mistake is to perform I/O to get error message text from disk. Performing I/O in this fashion should be done from an independent process or independent thread. This independent process or independent thread should not run in real time.
Interrupt priorities are independent of process priorities. The priorities that are set for a group of processes are not inherited by the services of hardware interrupts that result from those processes' actions. As a consequence, devices controlled by high-priority real-time processes do not necessarily have high-priority interrupt processing.
Time-sharing processes can save significant amounts of memory by using dynamically linked, shared libraries. This type of linking is implemented through a form of file mapping. Dynamically linked library routines cause implicit reads.
Real-time programs can set the environment variable LD_BIND_NOW to a non-NULL value when the program is invoked. Setting the value of this environment value allows the use of shared libraries while avoiding dynamic binding. This procedure also forces all dynamic linking to be bound before the program begins execution. For more information, see Oracle Solaris 11.3 Linkers and Libraries Guide.
A time-sharing process can block a real-time process by acquiring a resource that is required by a real-time process. Priority inversion occurs when a higher priority process is blocked by a lower priority process. The term blocking describes a situation in which a process must wait for one or more processes to relinquish control of resources. Real-time processes might miss their deadlines if this blocking is prolonged.
Consider the case that is depicted in the following figure, where a high-priority process requires a shared resource. A lower priority process holds the resource and is preempted by an intermediate priority process, blocking the high-priority process. Any number of intermediate processes can be involved. All intermediate processes must finish executing, as well as the lower-priority process' critical section. This series of executions can take an arbitrarily long time.
Figure 7 Unbounded Priority Inversion
This issue and the methods of dealing with this issue are described in Mutual Exclusion Lock Attributes in Multithreaded Programming Guide.
A page is permanently locked into memory when its lock count reaches 65535 (0xFFFF). The value 0xFFFF is defined by the implementation and might change in future releases. Pages that are locked this way cannot be unlocked.
Runaway real-time processes can cause the system to halt. Such runaway processes can also slow the system response so much that the system appears to halt.
When a high priority real-time process does not relinquish control of the CPU, you must break the infinite loop in order to regain control of the system. Such a runaway process does not respond to Control-C. Attempts to use a shell set at a higher priority than the priority of the runaway process do not work.
Asynchronous I/O operations do not always execute in the sequence in which the operations are queued to the kernel. Asynchronous operations do not necessarily return to the caller in the sequence in which the operations were performed.
If a single buffer is specified for a rapid sequence of calls to aioread(), the buffer's state is uncertain. The uncertainty of the buffer's state is from the time the first call is made to the time the last result is signaled to the caller.
The Oracle Solaris OS provides no facilities to ensure that files are allocated as physically contiguous.
For regular files, the read() and write() operations are always buffered. An application can use mmap() and msync() to effect direct I/O transfers between secondary storage and process memory. For more information, see the read(2), write(2), mmap(2), and msync(3C) man pages.