Source: http://www.dedicated-systems.com/magazine/97q2/winntasrtos.htm
More and more companies are trying to use Windows NT as a standard Operating
System (OS) at all levels of the industrial hierarchy. The use as server
and workstation is obvious, but some people want to use it also on the factory
floor. These factory floor applications demand real-time system behaviour.
Can Windows NT be a component to fulfil this need?
First, we will define what a real-time system is and the OS characteristics
we need to allow developers to build such a real-time system. The distinction
will be made between hard and soft real-time systems. In the second part,
we demonstrate how and why Windows NT cannot fulfil the requirements of a
hard real-time system. We show, however, that for some simple soft real-time
applications, Windows NT could be used under certain circumstances.
Windows NT was not designed with the requi-rements of a Real-Time Operating System (RTOS) in mind: it has been designed as a General Purpose OS (GPOS) or, to be more precise, as a Network OS (NOS). Nevertheless, because Win-dows NT was created by developers of the VMS Operating System, some characteristics from the real-time world have been introduced. For example Micro-soft introduced the notion of real-time class processes. They are scheduled in the same way, as it would be in an RTOS. The ISR (Interrupt Service Routine) has been designed in a very efficient way [1]. However, do these elements allow for a classification of Windows NT as a RTOS?
A Real-Time System responds in a timely predictable way to unpredictable
external stimuli arrivals.
To fulfil this, some basic requirements are needed:
A classification can be made into hard and soft real-time systems based on
their properties.
The properties of a hard real-time system are:
A good example of a hard real-time system is the fly-by wire control system
of an aircraft.
A soft real-time system is characterised by:
Examples are a vending machine and a network interface subsystem. In the
latter you can recover from a missed packet by using one or another network
protocol asking to resend the missed packet. Of course, by doing so, you
accept system performance degradation.
Other real-time systems examples are nuclear power plant control, industrial
manufacturing control, me-dical monitoring, weapon delivery systems, space
na-vigation and guidance, reconnaissance systems, laboratory experiments
control, automobile engines control, robotics, telemetry control systems,
printer controllers, anti-lock breaking, burglar alarms the list is
endless.
The difference between a hard and a soft real-time system depends on the
system requirements: it is called hard if the requirement is "the system
shall not miss a deadline" and soft if "the system should not miss a
deadline".
There are a lot of discussions going on about the exact meaning of a hard
and soft real-time system. One could even argue that a soft real-time system
is not a real-time system, as the first requirement: meet deadlines, is not
met. Indeed, the term "real-time" is often misused to indicate a fast system.
And fast can then be seen as "should meet timing deadlines", thus meaning
a soft real-time system. Therefore, we define a RTOS as an OS that can be
used to build a hard real-time system.
People often confuse the notion of real-time systems with real-time operating
systems (RTOS). From time to time people, even misuse hard and soft attributes.
They say this RTOS is a hard RTOS or this one is a soft one. There is no
hard RTOS or soft RTOS. A specific RTOS can only allow you to develop a hard
real-time system. But having such an RTOS will not prevent you from developing
a system that does not meet deadlines.
If, for example, you decide to build a real-time system that should respond
to an Ethernet TCP/IP connection, it will never be a hard real-time system
as the Ethernet itself is never predictable.
Of course, if you decide to build an application on top of an OS like
Windows 3.11, your system will never be a hard real-time system
as the behaviour of the "OS" software is by no means predictable.
As mentioned above, a RTOS should be predictable. This does not mean that
a RTOS should be fast, but that the maximum time to do something should be
known in advance and should be compatible with the application requirements.
Windows 3.11 even on a Pentium Pro 200 MHz is useless for a
Real-Time System, as one application can keep the control forever and block
the rest of the system (Windows 3.11 is co-operative).
The first requirement is that the OS is multi-threaded and preemptible. To
achieve this the scheduler should be able to preempt any thread in the system
and give the resource to the thread that needs it most. The OS (and the hardware
architecture) should also allow multiple levels of interrupts to enable
pre-emption at the interrupt level.
The problem is to find which thread needs a resource the most. In an ideal
situation, a RTOS gives the resources to the thread or driver that has the
closest deadline to meet (we call this a deadline driven OS - see also [2]).
To do so, however, the OS has to know when a thread has to finish its job
and how much time each thread needs in order to do so. For the time being
there is no RTOS for which this is the case, as it is so far too difficult
to implement.
Therefore, the OS developers took another point of view: they introduced
the concept of priority levels for threads.
The designer is responsible for converting deadline requirements in thread
priorities. As this human activity is prone to error, a Real-Time System
can easily go amiss. The designer can get help in this transformation process
by using for example Rate Monotonic Scheduling theories [2] and some simulation
software [9] but it can be of no avail. Nevertheless, as there is no other
solution today, the notion of thread priority has to exist.
As threads share data (resources) and need to communicate, it is logical that locking and inter-thread communication mechanisms exist.
In fact, it is these synchronisation mechanisms and the fact that the different
threads run in the same memory space that makes the difference between threads
and processes. Processes do not share the same memory space. For instance,
old UNIX versions are not multi-threaded. (Old) UNIX is a multi-task OS,
but the tasks are processes that can only communicate via pipes and shared
memory. Both mechanisms use the file-system characterised by an unpredictable
behaviour.
The combination of thread priority and resource sharing between them leads
to another point: the classical problem of priority inversion. Before having
a priority inversion condition, at least three threads have to be involved.
When the lowest priority thread has locked a resource (shared with the highest
one) while the middle priority thread is running, the highest priority thread
is then suspended until the locked resource is relea-sed and the middle priority
thread stops running. In such a case the time needed to complete a high priority
level thread depends on a lower priority level "priority inversion". It is
clear that in such a situation it is hard to meet deadlines. (Figure 1).
To avoid this, a RTOS should allow priority inheritan-ce in order to boost
the lowest priority thread above the middle one up to the requester. Priority
inheritance means that the blocking thread inherits the priority of the thread
it blocks (of course, this is only the case if the blocked thread has a higher
priority).
Some people will argue that a correct design would avoid the problem. This is not true for complex applications. The only way to solve this is to increase the priority of the thread manually before locking a resource. This implies of course that only two threads of different priorities are sharing the protected resource. If not, there is no solution.
Lastly, the timing requirements should be considered. In fact, the developer should know all the timing of system calls and the system behaviour in all his flavours. Therefore, the following figures should be clearly given by the RTOS manufacturer:
The developer should also know the following points:
When all the previous metrics are known, one can imagine to develop a hard Real-Time System on top of this OS. Of course, the performance requirements of the System to develop should be compatible with the RTOS and the hardware chosen.
It is clear that Windows NT is a multi-threaded and preemptible OS [3], as such it fulfils the first requirement (Req. 1). Let us now examine the predictability of Windows NT. Therefore, we have to recall the structure of Windows NT and to figure out if and how real-time aspects of a system can be handled in Windows NT.
In a real-time system, not all the jobs have the same priority. Some of them
(those that are time critical) have higher priorities. Others like displaying
the state of the system, logging events to file or configuring the system
have on the contrary lower priorities. To take this into account, the OS
should be able to assign different priorities for these jobs.
In Windows NT the notion of priorities is quite complex:
Figure 2 represents these two classes of processes.
As there is a notion of thread priority, the second requirement is met. But
there is a problem: only a small number of priority levels are allowed in
Windows NT. Most of the modern RTOS allow for at least 256 priorities.
Why is this a problem? The answer is obvious: the more priorities you have,
the more predictable your system is predictable. The best way to design a
system is to assign to each different thread a different priority [2]. For
a given process in Windows NT you have only 5 (7 if you count the two extreme
ones) priorities for threads in a given process. So doing, a lot of them
will have to run at the same level. Your predictability will then be mediocre
if you have to handle more than one or two critical events. Some would say
that different processes could be. But even then, the total number of priorities
is only 16. Moreover, context-switching time between threads from different
processes is much higher than between threads in the same process, as they
do not share their memory space, which is a part of the context. Therefore,
this is not a good solution.
Figure 2 Windows NT priority spectrum
As mentioned previously the problem of priority inversion is a classical
one in a real-time system. There-fore, in a RTOS the synchronisation system
calls such as mutexes, semaphores and critical sections should be capable
of handling priority inheritance. In Win-dows NT this is NOT POSSIBLE [4],
so the requirement 4 is not met.
Another problem related to the priority inversion in Windows NT is due to
the implementation of some GUI system calls. These are handled in a synchronous
way (the calling thread is suspended until the completion of the system call)
by a process running at a non real-time class priority [5]. So doing, a lower
real-time class thread can prevent the upper ones from running.
As we have seen, the relatively low number of priorities correlated to the
problem of the priority inversion make windows NT only suitable for simple
(few diffe-rent kinds of events) Real-Time Systems.
Why then choose Windows NT? As mentioned be-fore, it could be interesting
to have the same OS at different levels in the company's industrial hierarchy.
But another very interesting point to consider is the very rich and powerful
Win32 API. You have a lot of good development platforms, good compilers and
also a lot of engineers that know this API well. The features of this API
are numerous. There is everything you need to create a powerful multi-threaded
application. The only question is to know if you can build a reliable Real-Time
Application on top of it.
To do so, the system call should be predictable and independent from the
number of objects in the system.
To measure this we have done a few simple tests. We have designed a process
(belonging to the real-time class) that has a thread executing synchronisation
system calls. We used the QueryPerformanceCounter system call before and
after each synchronisation system call to measure the time it takes. At the
end of the test, we saved everything on disk to exploit the results with
Excel (Figure 3).
We made sure that no swapping had occurred during the tests and that no resource
had been locked -so our measures are significant. We have also measured the
delay introduced by the tracing activity and removed it from the test results.
The tests have been performed on a 100 MHz Pentium with 24MB RAM.
For the request mutex system call, for example, we got an average of 35 µs.
But the maximum has once been up to 670 µs!
Figure 3 Get Mutex System call time
Why? This is simply due to an interrupt either from the disk or from the
network as this was the only possible activity of the system (this machine
is connected on our network). This was reproduced many times when loading
artificially the system with disk and network transfers while performing
the tests. So doing, we ended up delaying the system calls up to a few
milliseconds!
The Win32 API as we said is very rich. But it should be noticed that it is
not well designed for real-time. For example mutex requests are queued in
FIFO order and not in priority order [10]. This is a big drawback for
predictability. Great care should also be taken when choosing a system call.
For instance, for thread synchronisation in the same process, the critical
section should be preferred to any other call (this call takes only a few
microseconds compared to 35 µs with Mutex). This call is designed to
work only in such a case (threads have to belong to the same process). This
is normal, as the context switch between two threads of the same process
is much lighter than the one between two processes.
A final remark concerning this API: when using an API system call one should
notice that some of them are executed by system processes running at a lower
priority (dynamic class) and are synchronous. So doing, the calling thread
will wait for the completion of the call. This could result in a priority
inversion.
Our conclusion after these very simple tests is that, despite a powerful
API, the underlying kernel and I/O manager is not well adapted to handle
real-time events at the application level!
We will discuss later if this problem can be solved at the driver level.
A real-time system interacts with the external world via the computer hardware. External events are converted into interrupts and handled by a device driver.
Figure 4 Windows NT hardware interfacing
Figure 4 from the DDK Documentation [6], shows how Windows NT is designed
to deal with the hardware.
The only way to reach the hardware is via a kernel device driver. This is
logical in such an OS as pro-cesses are running in separate memory spaces
and cannot gain access directly to the hardware. As most real-time applications
are dealing with special external events, the developer must also develop
the kernel device drivers to gain access to the hardware. Let us see how
a device driver is designed.
The device driver is responsible for handling the interrupt generated by
the hardware it controls. To do this, an original mechanism has been chosen
in order to increase the responsiveness of the OS. The interrupts are handled
in two stages. First, the interrupt is handled by a very short Interrupt
Servicing Routine (ISR). Afterwards the work is completed by executing a
DPC (Deferred Procedure Call). This delivers the following event flow:
Figure 5 Windows-NT Interrupt levels
As we can see the handling of an interrupt is quite complex in Windows NT.
Moreover, an ISR must be designed in the correct way to be as short as possible.
So most drivers do a lot of work in the DPC (which are only preemptible by
an ISR) causing other DPC to wait for their completion as all DPC run at
the same priority level (DISPATCH_LEVEL, level 2 on Figure 5).
The Windows NT Device Driver Documentation tells you that: "the ISR are
preemptible by upper priority ISR and that DPC have higher priority than
user and system threads". But as all DPC are running at the same level and
as the policy that should be used when designing a Device Driver is to reduce
the ISR to the minimum (deferring the rest of the critical job in the DPC),
your DPC will have to wait for other DPC to be completed. Therefore, here
your application will depend on others device drivers.
Is this different in a RTOS? Of course it is. In an RTOS the developer first
knows at which level the other device drivers are running. There is usually
some free space for interrupts above the standard drivers. All the critical
work is then done in the ISR allowing the developer to tune its drivers'
configuration depending on the time constraint of the application. In Windows
NT the ISR are very fast, so the interrupts are not blocked for a long period,
but nothing is done in the ISR. Most of the job is deferred to the DPC. So
if you are using a third party device driver badly designed, you will finally
miss deadlines, except if you do not follow Microsoft policy and do the entire
job in the ISR but then, why use an OS?
Figure 6 Preemption at the interrupt level
Notice here that this could be very crucial as we discovered that some DPC from hard disk and network drivers take more than a few milliseconds.
Another point to consider when designing a real-time system is the memory
management policy of the RTOS. In Windows NT, processes are in their own
me-mory space. Virtual memory mechanism and a pa-ging system can only achieve
this. For business applications, this is great, but for a real-time system
that has to respond to external events in a predefined time limit, this generates
unpredictability when the system has to get a memory page from disk. There-fore,
Windows NT allows you to lock pages into memory through the call to the
VirtualLock function. . In his book, Jeffrey Richter says that Windows NT
can still unlock the pages and swap them out to the disk if the whole process
is inactive [7]. However, we have not manage to demonstrate this. The only
thing we manage to find that the memory allocated for the window can still
be swapped out when you iconise them. So normally for Real-Time applications,
this will not be a problem. Is the previous point still a problem? It is
not, if the application and other third party applications are well designed
and do not take more memory than physically available.
At the device driver level, however, swapping can be avoided.
Some other few points should be considered when trying to use an OS for real-time or embedded applications:
Last but not least, one should consider the fact that some companies are offering solutions to make Windows NT more Real-Time a proof if any that it is not the case by default! Likewise, this shows that there is a market for it.
We showed in this article that Windows NT, as it has been designed to deal mainly with classical applications, is not a good platform to support Real-Time applications:
So why do some people say they can manage to use Windows NT for real-time applications [8]? First, one specific application never demonstrates anything on its own. Second, Windows NT can only be used un-der the following circumstances:
This last point, however, makes the use of any OS pointless.
But, for hard Real-Time systems, Windows NT is out of the question. Your
system will never be predictable enough. To put it bluntly you can
rely upon it and take a plane: Windows NT will not be used in any fly-by-wire
systems in the near future!
But in earnest, what should be changed in Windows NT to enable its use in
hard real-time systems? The real-time class process should have more priority
levels. The problem of the priority inversion should be solved. The whole
interrupt system should be chan-ged:
Is Microsoft willing and ready to introduce such enhancements in Windows NT or do they find the market to small to let this open for third parties?
Dr. Ir. Martin Timmerman is graduated in Tele-communications Engineering at the Royal Military Academy (RMA) Brussels and is Doctor in Applied Science at the Gent State University (1982). He became the director of the System Development Centre (SDC) at RMA, which he created in 1983, and converted himself to a Computer Science Engineer. Actually he is giving general courses on Computer Platforms and more specific courses on System Development Methodologies at RMA. Outside RMA, Martin is known for his audits, reviews and seminars for his two companies Real-Time Consult and Real-Time User's Support International. RTUSI provides hardware and software support services and is involved in project engineering for Real-Time Systems.
Ir. Jean-Christophe Monfret graduated in 1993 as an Ingénieur Télécom Bretagne, France. He has a master's degree in Parallel Computer Science from the University of Rennes I, France (1993), a specialisation he had the opportunity to put to practice for a year at the Commissariat à l'Energie Atomique, France. He has been working since 1994 for RTUSI and Real-Time Consult as a project manager where he is also involved in audits and review activities.
REFERENCES
1. Technology Brief: Real-Time Systems with Micro-soft Windows NT, Publication of the Microsoft De-veloper Network, Microsoft Corporation, 1995.
2. J. Zalewski, "What Every Egineer Needs To Know About Rate-Monotonic Scheduling: A Tutorial," in Real-Time Magazine, Issue 1995/1
3. Joel Powell, Multitask Windows NT, Waite Group Press, 1993.
4. Microsoft® Win32® Software Development Kit Documentation.
5. Helen Custer, Inside Windows NT , Microsoft Press, 1992.
6. Microsoft® Windows NT Version 3.51 Device Driver Kit Documentation.
7. Jeffrey Richter, Advanced Windows, The Developer's Guide to the Win32 API for Windows NT 3.5 and Windows 95, Microsoft Press, 1995.
8. Brian Catlin, Design of a TCP/IP Router Using Windows NT, a paper presented at the 1995 Digital Communications Design Conference, Catlin & Associates, Redondo Beach, CA.
9. P. KORTMANN and G. MENDAL, PERTS Proto-typing Environment for Real-Time Systems, Real-Time Magazine, Issue 1996/1 (ISSN 1018-0303).
10. Mutex Wait is FIFO but Can Be Interrupted, in Win32 SDK Books Online, Microsoft Corporation, 1995.