Spring (operating system)


Spring is a discontinued project in building an experimental microkernel-based object-oriented operating system developed at Sun Microsystems in the early 1990s. Using technology substantially similar to concepts developed in the Mach kernel, Spring concentrated on providing a richer programming environment supporting multiple inheritance and other features. Spring was also more cleanly separated from the operating systems it would host, divorcing it from its Unix roots and even allowing several OSes to be run at the same time. Development faded out in the mid-1990s, but several ideas and some code from the project was later re-used in the Java programming language libraries and the Solaris operating system.

History

Spring started in a roundabout fashion in 1987, as part of Sun and AT&T's collaboration to create a merged UNIX. Both companies decided it was also a good opportunity to "reimplement UNIX in an object-oriented fashion". However, after only a few meetings, this part of the project died.
Sun decided to keep their team together and instead explore a system on the leading edge. Along with combining Unix flavours, the new system would also be able to run almost any other system, and in a distributed fashion. The system was first running in a "complete" fashion in 1993, and produced a series of research papers. In 1994, a "research quality" release was made under a non-commercial license, but it is unclear how widely this was used. Described as a "clean slate" intended to help Sun improve its existing Unix products, the software was made available at a cost of $75, with Sun targeting universities and computer scientists. Commercial research institutions could obtain the software at a cost of $750. The team broke up and moved to other projects within Sun, using some of the Spring concepts on a variety of other projects.

Background

The Spring project began soon after the release of Mach 3. In earlier versions Mach was simply a modified version of existing BSD kernels, but in Mach 3 the Unix services were separated out and run as a user-space program like any other, a concept Mach referred to as a server. Data which would normally be private in the kernel under a traditional Unix system was now passed between the servers and user programs using an inter-process communication system, ending in ports which both programs held. Mach implemented these ports in the kernel, using virtual memory to move data from program to program, relying on the memory management unit and the copy on write algorithm to do so with reasonable performance.
In its ultimate development, an OS on Mach would consist of a number of such servers, each handling a specific task. Examples would include the file system or network stack. The operating system server in such a system would be quite small, providing services unique to that OS, and forwarding most other calls to other servers. Since the OS was running on top of single set of common servers, several OS servers could be run at the same time, allowing a single system to "natively" support DOS, Unix and other operating systems at the same time.
This capability was particularly exciting to companies like IBM, who were already supporting several different systems, and saw Mach as a way to combine these with common underlying code. In fact this was not so easy. Mach made several decisions at a low-level which made any system running on it Unix-like to some degree. Most notable was a security system which was modelled on fairly inflexible inherited model of Unix programs. Additionally the IPC system proved to be a major performance problem, although the nature of this issue didn't become clear until later. The performance was so poor that many commercial projects to port existing operating systems to Mach, notably IBM's Workplace OS, were eventually abandoned.

Rationale

Although Sun was also interested in supporting multiple operating systems, their needs were nowhere as pressing as IBM or Apple. By this point in time they had already moved platforms from their early 68k-based machines to their SPARC-based lineup, and their UNIX System V-based Solaris operating system was taking over from their BSD-based SunOS. Sun's concerns were somewhat more subtle: keeping developers interested in Sun's version of Unix; and, allowing their system to scale downwards onto smaller devices such as set-top boxes. A microkernel-based system would be particularly useful in this latter role.
Spring concentrated on "programmability"; making the system easier to develop on. The primary addition in this respect was the development of a rich interface definition language, which exported interfaces with considerably more information than the one used in Mach. In addition to functions and their parameters, Spring's interfaces also included information about what errors can be raised and the namespace they belong to. Given a proper language, programs, including operating system servers, could import multiple interfaces and combine them as if they were objects native to that language — notably C++. Some time later the Spring IDL was adopted with minor changes as the CORBA IDL.
Spring also explored a number of specific software advances in file systems, virtual memory and IPC performance. The result was a single Unix-like system with much better performance than Mach. Some of these changes are detailed below.

Description

The Sun engineers used non-standard terminology for a number of common components, which makes discussing the system somewhat confusing. For instance, Mach tasks are referred to as domains, ports as doors, and the kernel as the nucleus.

The nucleus

The Spring kernel was divided into two parts: a virtual memory system and the nucleus. Although the nucleus is equivalent to only one portion of the Mach kernel, the kernels of each OS are analogous enough to be considered to perform the same function.
The Spring kernel includes only the most basic functionality and state needed to support user-side applications. Primarily this includes state to maintain lists of running programs and their threads, as well as the communications links between them.
The Spring kernel is not multi-threaded. Normally this would preclude it from use in realtime settings, but it is not clear that is the case. Normally kernels need to be threaded in order to ensure a long-running task such as disk I/O won't tie up the system and prevent a subsequent call from being serviced in time; under Spring the kernel almost immediately hands off the vast majority of requests to the servers, so under this model it is only the servers which, in theory, need to be threaded.

IPC model

One major difference between Mach and Spring was the IPC system. In Mach, the system was arranged as a set of one-way asynchronous pipes between programs, a concept derived from Unix pipes. In programming, however, the most common method of communications is the procedure call, or call/return, which Mach did not support directly. Call/return semantics could only be supported via additional code in higher-level libraries based on the underlying ports mechanism, thereby adding complexity.
Spring instead directly supported call/return semantics in the basic communications system. This resulted in a change of terminology from ports in Mach, to doors in Spring. Doors were known to the kernel only; programs were handed a "handle" to the door with an identifier which was unique to that program. The system worked similarly to ports for the initial message; messages sent to a door were examined by the nucleus in order to find the target application and translate the door handle, but the nucleus then recorded small amounts of information from the caller in order to be able to return data quickly. This sped up the return by about 40%.
Additionally, the Mach model was asynchronous — the call would return if and when the server had data. This followed the original Unix model of pipes, which allowed other programs to run if the server was busy. However, for a call/return system this has serious drawbacks, because the task scheduler has to run to select the next program to be serviced. Hopefully this was the server the call was requesting data from, but it this was not guaranteed. Under Spring, IPC is synchronous; control is immediately passed to the server without running the scheduler, improving the round trip time in the common case when the server can immediately return.
Under Mach, the virtual memory system, supported by the memory management unit, was expected to provide a lightweight solution to copying data, by simply mapping the same data in memory into the two programs. In reality this solution was not at all efficient, as many MMUs had design features which made this mapping slow or even impossible.
Unlike Mach's one-size-fits-all solution to IPC, Spring used a variety of methods to physically pass data between programs. One of these, the bulk-path, was basically identical to Mach's ports and messages, but in practice the bulk-path was the least common message type. For smaller messages Spring provided the vanilla-path, which directly copied the data from one space to another, something which proved to be faster than memory mapping in the real world for less than 5k of data.
The fast-path allowed for extremely fast invocations — at least when running on SPARC-based platforms. The fast-path used a unique "half-trap" to avoid much of the context switching overhead which plagued Mach systems. Instead of saving out all of the processor state—the normal procedure in the case of a trap into the kernel—Spring only saved out the top 16 SPARC registers, a number which was defined by specific implementation details of the SPARC architecture. The other portions of the register stack were rendered invisible to the receiver using the SPARC's WIM instruction, providing some level of security. The fast-path strongly resembles a classic procedure call within a single application, which uses register windows on the SPARC, adding some MMU work to move the context from one program to another.
The fast-path was only available for calls passing simple values which didn't have to be translated with up to 16 values in total. Although this would seem to be quite limiting, the fast-path is actually used by the vast majority of calls in Spring—generally over 80% of the calls and about 60% of the returns. Returns often respond with large blocks of data, for instance, a disk block, explaining why the returns more often used the other IPC systems.
On 32-bit SPARC V8 systems, a complete round-trip call using the fast-path took just over 100 instructions, making it many times faster than a typical Mach call. It remains unclear whether or not the fast-path could be implemented on other machines, so the overall performance improvement of Spring is difficult to compare with Mach, which was typically measured on IA-32 systems. Specifically, a full syscall took under 20 μs on a 486DX-50 for existing BSD Unix systems, and 114 μs under Mach. This led to a performance hit of 50% or more, and doomed most Mach projects. In contrast, Spring using the fast-path boasted an IPC time of only 11 μs on a SPARCstation 2.