From: russ@alliant.com (Russell McFatter)
Subject: Ada and real-time
Organization: Alliant Computer Systems Corp.
Date: Tue, 13 Oct 1992 15:32:17 GMT

I'm seeing a lot of people banter about the meaning of "real time" (or
"real-time") as it affects C/C++ and Ada, yet nobody has touched upon
the actual, practical definition of this concept.

While the practicality of a real-time system sometimes hinges on issues
of performance, there is exactly one commonly-accepted definition of
what makes a real-time application deserve that title:

The performance of a real-time OS, system, or application is
*deterministic*.  If you are writing flight control software for an
aircraft manufacturer, you do not necessarily care that a particular
operation occurs with all possible speed-- you do care, however, that
it performs consistently; that the response of the control surfaces to
the pilots, for example, is not compromised by the desire of many
passengers to press their stewardess-call buttons at once, even if the
same hardware is handling all of those events.  Likewise, a system
that's responsible for processing the sensor returns from underground
(seismic) exploration doesn't want to miss half the data because the
system just happens to be receiving its netnews feed at the moment.  In
other words, if it works during testing, it should also be "guaranteed"
to work at all other times.

No language can really make the claim of being "real-time" on its own;
Ada is certainly no better suited to real-time applications than C, for
example.  What makes a language suitable for real-time is simple:

	1:  It runs on an OS/hardware platform that supports real-time
	    activities

	2:  It provides access to "real time safe" facilities

	3:  It is not, in and of itself, nondeterministic.

(1)  OS/hardware support:

     No application can be deterministic if the underlying hardware or
     OS isn't.  There's all sorts of gremlins that can get thrown in
     one's way here.  Interrupt service, virtual memory (page faults),
     and other preemption serves to make a process nondeterministic.
     In a system which supports real time, these preemptions can be
     eliminated (or made deterministic) as necessary.  A small
     microprocessor system might be considered real-time: only the
     "foreground" process gets any resources, so a simple application
     running on one is, essentially, deterministic.  Larger multitasking
     or multiprocessor systems generally offer some way of "partitioning"
     or isolating the real-time activities from traditional work, so that
     the non-deterministic (timesharing) processes don't interfere with
     the real-time ones.

(2)  Language real-time support:

     Almost every real-time application needs to do things which are
     not "real-time-safe".  For example, an application receiving
     seismic sensor data might need to write this data to tape or disk.
     Generic I/O (such as "read" and "write" calls provided by the OS)
     is not deterministic, as the operation can take varying amounts
     of time.  To be "real-time", the application needs either to have
     direct (deterministic) access to the I/O device (which itself has
     to be deterministic), or be able to hand off those tasks to another,
     less critical, non-realtime process.

     The language needs access to the OS facilities which make real-time
     possible.  For example, can you "lock" your process in memory to
     prevent other processes from swapping yours out?  Can you signal
     other tasks (using events or semaphores) using only real-time-safe
     calls?


(3)  No self-imposed nondeterminism:

     Can a language be nondeterministic?  Sure it can.  Take LISP, for
     example...

	"Whoa!  That missile flew right over our heads and this thing
	 didn't even try to intercept it!"

	"Bummer of a time to do a garbage collection.  Sorry 'bout your
	 city, man."


Most real-time applications I see are "hybrids"-- the critical real-time
portion of the code communicates (usually via shared memory) to a
timesharing counterpart that handles all the asynchronous duties (I/O).
That can be done equally well in C or Ada (or even Fortran).   The
manufacturer of a real-time-capable system ususally provides language
libraries with bindings to system calls for real-time services.  For
example, a typical application needs to:

	1:  Enable real-time facilities ("rt_enable")
	2:  Bind itself to a particular processor ("rt_bind")
	3:  Lock itself in memory ("rt_lockmem")
	4:  Directly access external devices ("rt_alloc_extba",
                "rt_map...", and others)
	5:  Examine or set the processor schedules ("rt_getscheduler",
	        etc.)
	6:  Select a scheduling algorithm (fixed priority, frame, others)
	7:  Install hardware interrupt handlers ("rtdev_conn_intr")
	8:  Install event handlers
	9:  Create or attach to shared memory regions
	10: Coordinate things such as semaphore/event ID's with related
	    processes
	11: Post or wait on semaphores or events
	12: Set the process priority (fixed priority scheduling) or the
	    frame length and frame overrun handling (frame schedulers)
	13: Undo all of the above when it is time to exit.

Multiuser systems require special privileges from processes which need
realtime facilities, as, essentially, such a process is accessing much of
the hardware directly, and by definition cannot be pre-empted by other
activities.  On Alliant's systems, for example, you must be a member of
the "realtime" group, or "rt_enable()" fails with "Permission Denied" and
all of the other critical realtime calls fail as well.

System and library calls are always identified as "real-time safe" or
"not real-time safe".  Very few calls are "safe", generally; especially
during the initialization or release of the RT facilities themselves.  Once
the real-time environment is set up, however, and the application does
nothing else "unsafe", the code is deterministic; whatever works during
testing will continue to work (with the same data, at least) in reality
(and thus won't spontaneously fail in front of a roomful of Navy Admirals
even if someone decides to format a floppy disk while the demo is running).

Speed, of course, still helps.  For example, a radar tracking application
that uses real-time facilities might be able to follow five targets.  It
will, as long as the software is correct, never have trouble handling those
five targets.  But, when six are attempted, the code detects (by several
means) that it can't handle the load (can't update all the targets within
the required interval).  If run on a faster platform, or written more
efficiently, or distributed across more processors, the same application
might instead be certified to track thirty targets.

It's all a matter of meeting the specifications.  In a critical
application, I'd much rather know that the system will always meet the spec
than have a system that outperforms the specification by a factor of 5,
"most of the time."

--- Russell McFatter [russ@alliant.com]
std. disclaimers apply.