KeyTECH Design Considerations

Use of Multiple Domains

Many non-microkernel systems started as single user, single task systems and added task switching to satisfy the multitasking requirements of modern usage. In these systems it has not been possible to optimize the task switch because the attributes of tasks were determined by the single task model. With non-optimized task switching, it is not possible to extend the application design to using large numbers of tasks at the operating system level. Because complex applications often involve large numbers of tasks, what is usually done is to define application level tasks and then develop an application level “operating system” that schedules these tasks to accomplish the goals of the application.

A design goal of the KeyTECH Microkernel was to optimize task switching so that a majority of applications that required multitasking could use the Microkernel supplied tasks rather than define application level tasks. The result of this design is a Microkernel that accomplishes task switching many times faster than traditional systems, and allows this task switching to replace application level multiplexing. Applications become much simpler and performance is generally improved because the Microkernel really has only one thing to do (task switching), and it does it very well.

When an application requires multitasking, it means that it is switching between several execution streams in order to overlap pauses (mostly for I/O) in one stream with computation in another stream. Each time the application switches a task it must re-establish a great deal of contextual information. This information may involve aspects of authority to access data based on the original requester, local variables for the task, and scheduling information concerning the priority of the task relative to the other tasks. When the KeyTECH Microkernel switches tasks it is switching address spaces and Key spaces. This has the effect of switching a complete application context. If these fast task switch times are combined with multiple instantiation of application functions, all of the application context switching takes place with the single Microkernel level task switch.

The combination of fast switch times and multiple instantiation leads to very simple applications with high performance. This view of system behavior often runs counter to the prevailing collective wisdom. Traditional systems have either not had fast enough switch times, or have not been able to support the large number of address spaces required for multiple instantiation, or both. The discussion that follows, of the use of KeyTECH in support of UNIX™, is based on the demonstrated performance of this combination on the KeyTECH Microkernel. The client - server model is used extensively. A UNIX process is a client; it has a dedicated server that handles all system services. Files and Inodes are all represented as individual Objects to provide the maximum use of the simplification that comes from multiple instantiation.

Another aspect of the KeyTECH Microkernel that affects the design of applications is the fact that Virtual Memory and Domains (processes) are permanent and can be used to represent long term data such as files. Furthermore, when a system is interrupted by a power failure and is restarted, not only is the state of the virtual memory restored, but also the active processes are restored as well. This assures that processes that might leave data in an inconsistent state are restarted to restore the data to a consistent state. The application designer does not need to be concerned with restoring internal consistency after a system restart.

Use of Keepers

The Keeper technology of KeyTECH brings all exception policy to application level programs outside of the Microkernel. There is nothing particularly special about the design of a Keeper; it is an Object and receives messages like any other Domain. Since the UNIX implementation relies heavily on the Domain Keeper technology, the ideas and specifications concerning Keepers will be discussed before we delve into the UNIX specifics.

When a Domain encounters an exception (system call, arithmetic fault, invalid operation, etc.) the Domain stops executing and the Domain Keeper receives a message. It is almost as if the Domain itself had invoked a Start key to the Keeper. The message contains the non-privileged state of the Domain (its registers, instruction counter, etc.), a Domain key to the Domain, and a form of Resume key that the Keeper uses to restart the Domain. The only sensitivity to its role as a Domain Keeper that the Keeper must have is that simply using the Resume key to restart the Domain will cause the Domain to re-execute the instruction that caused the exception. In a few cases this is what is desired, as the conditions that caused the exception can be altered by the Keeper so that the exception will not occur when the instruction is re-executed.

In the case of a “system call” fault, the Keeper must alter the register contents and instruction counter of the Domain before using the Resume key to restart the Domain. The Keeper uses the Domain key that came as part of the message to update the Domain state with a Domain_PutRegistersAndControl invocation before using the Resume key to restart the Domain.

Between the receipt of the exception message and the restart of the Domain, the Keeper logic appears no different from that of any application that receives a message, computes a response, and sends a reply message.

The UNIX Keeper examines the register data passed in the exception message to determine what action to take, takes that action, and puts the results into the register data that is passed to the Domain key when the Domain is restarted. The Keeper may invoke Keys to other objects, create and destroy objects, or take any other action needed to perform the requested system function. In the UNIX system that is described in this document, all functions that require shared services, I/O, or signaling are done using Keys.

One aspect of the UNIX Keeper worth mentioning now is that except when it is performing a task, it is always in the “available” state. This is necessary because signal processing is handled by the Keeper. When one UNIX task signals another task, it is the Keeper that sends a message to the other Keeper. The receiving Keeper will effect the signal processing for the receiving process. This means that a UNIX Keeper may never invoke a Key (for example, to do I/O) and wait for the reply, since the reply may be delayed for extended periods while waiting for a remote system or keyboard activity. The Keeper must start the I/O operation using a FORK object and then become available without restarting its kept Domain. While the Keeper is available it may receive a message that indicates the completion of the I/O, the completion of a timer request, or a signal from another task and must be available to receive the message and process it. This need to keep the Keeper “available” shows through in the design of the device I/O interface.

The Keeper uses the databyte feature of Start keys to partition its function. Each separate aspect of the Keeper’s behavior has a separate databyte assigned. Thus the Start key used by I/O devices to inform the Keeper that I/O is complete is different from the Start key used by other Keepers to send signals. It is true that the message ordercode could indicate the intent of the invoker of the Key but use of the databyte removes a whole class of errors that would result in bugs that would be difficult to isolate.