A real-time program sometimes needs to perform disk I/O under tight time constraints and without affecting the timing of other activities such as data collection. This chapter covers techniques that IRIX supports that can help you meet these performance goals, including these topics:
When an input file has a fixed size, the simplest as well as the fastest access method is to map the file into memory (for details on mapping files and other objects into memory, see the book Topics in IRIX Programming). A file that represents a data base of some kind—for example a file of scenery elements, or a file containing a precalculated table of operating parameters for simulated hardware—is best mapped into memory and accessed as a memory array. A mapped file of reasonable size can be locked into memory so that access to it is always fast.
You can also perform output on a memory-mapped file simply by storing into the memory image. When the mapped segment is also locked in memory, you control when the actual write takes place. Output happens only when the program calls msync() or changes the mapping of the file. At that time the modified pages are written. (See the msync(2) man page.) The time-consuming call to msync() can be made from an asynchronous process.
You can use asynchronous I/O to isolate the real-time processes in your program from the unpredictable delays caused by I/O. Asynchronous I/O is implemented in IRIX to conform with the POSIX real-time specification 1003.1c. The details of asynchronous I/O are covered at more length in the manual Topics in IRIX Programming (see “Related Publications and Sites”).
Conventional I/O in UNIX is synchronous; that is, the process that requests the I/O is blocked until the I/O has completed. The effects are different for input and for output.
For disk files, the process that calls write() is normally delayed only as long as it takes to copy the output data to a buffer in kernel address space. The device driver schedules the device write and returns. The actual disk output is asynchronous. As a result, most output requests are blocked for only a short time. However, since a number of disk writes could be pending, the true state of a file on disk is unknown until the file is closed.
In order to make sure that all data has been written to disk successfully, a process can call fsync() for a conventional file or msync() for a memory-mapped file (see the fsync(2) and msync(2) man pages). The process that calls these functions is blocked until all buffered data has been written.
Devices other than disks may block the calling process until the output is complete. It is the device driver logic that determines whether a call to write() blocks the caller, and for how long. Device drivers for VME devices are often supplied by third parties.
A real-time process needs to read or write a device, but it cannot tolerate an unpredictable delay. One obvious solution can be summarized as “call read() or write() from a different process, and run that process in a different CPU.” This is the essence of asynchronous I/O. You could implement an asynchronous I/O scheme of your own design, and you may wish to do so in order to integrate the I/O closely with your own design of processes and data structures. However, a standard solution is available.
IRIX (since version 5.3) supports asynchronous I/O library calls conforming to POSIX document 1003.1b-1993. You use relatively simple calls to initiate input or output. The library package handles the following details:
Initiating several lightweight processes to perform I/O
Allocating a shared memory arena and the locks, semaphores, and/or queues used to coordinate between the I/O processes
Queueing multiple input or output requests to each of multiple file descriptors
Reporting results back to your processes, either on request, through signals, or through callback functions
Under specific conditions, your program can demand a guaranteed rate of data transfer. You can use this feature, for example, to ensure input of picture data for real-time video display, or to ensure disk output of high-speed telemetry data capture.
The details of guaranteed-rate I/O (GRIO) are covered at length in two other manuals:
For an overview of concepts, and for instructions on how to set up and configure a volume for GRIO use, see IRIX Administration: Disks and File Systems.
For an overview of the programming use of GRIO, see Topics In IRIX Programming.
Both manuals are listed under “Related Publications and Sites”.