Spring was 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 enviornment 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 OS's 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.
The Spring project started soon after the release of Mach 3. In earlier versions Mach was simply a modified version of existing BSD Unix 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 that would normally be private in the kernel under a traditional system would now be passed between the servers and user programs using an interprocess communications (IPC) system, ending in ports that 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 (MMU) 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. Instead of a single large operating system server, functionality common to more than one OS would first be separated out into smaller servers handling a single task, the file system for instance. Operating system servers would then call these services. Under this model Mach could not only run any modern system, but several at the same time, and the user could tailor the system to their needs simply by starting or stopping programs. This was particularily 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 that made any system running on it Unix-like to some degree. Most notable was a security system that 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 and Apple Computer's Star Trek, were eventually adbandoned.
Although Sun was also interested in supporting multiple operating systems, their needs were nowhere as pressing as IBM or Apple. They had already moved platforms from the 68k-based early machines to SPARC-based machines, and their UNIX V-based Solaris operating system was slowly taking over from their BSD-based SunOS. Sun's concerns were somewhat more subtle, keeping developers interested in what was really "just another Unix", and allowing their system to scale downwards onto smaller devices such as set-top boxes. A microkernel-based system would be particularily useful in this later role.
Spring concentrated on "programmibility"; making the system easier to develop on. The primary addition in this respect was the use of a richer interface definition language (IDL), which exported interfaces with considerably more information than the one used in Mach. In addition to functions and their parameters, Spring's interfaces also include 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++, which was a major target language although Spring documentation seems to pretend this is not the case.
Note that Mach can be used in a Spring-like fashion in this regard with little effort. After exporting the Mach interface in the IDL, the code can then be wrapped in any target language to provide an object layer. This was extensively used in various Mach projects under C++, as well as on NeXTSTEP/Mac OS X under Objective-C. However this does not imply the resulting system will be as easy to use. In particular the lack of a namespace mechanism means that the resulting interfaces will be a "big bag of functions" unless the developers take care to organize the resulting code. In the end though, it seems there is little real-world difference.
Although not part of the IDL itself, Spring also included hints, referred to as subcontracts, about how to physically make calls between programs. The most common subcontract was a singleton using Mach-like IPC to pass data from one program to another. Although buzzword compliant, singletons are really nothing more than applications being sent messages using IPC; in other words, identical to the Mach model in all but name. Spring also included other subcontracts for lightweight (in-process) objects, caching, and error handling, which seem to demonstrate the utility of the concept.
Spring also used a single access control list-based (ACL) security system for all permissioning. Unlike Mach, which followed the Unix model without seeming to have given it any thought, using ACL's in the root of the system meant that they were univerally available. For instance, implementing ACL's in the file system simply meant writing them down, the user's requests would already be checked against them as a natural part of trying to send IPC to the file system server. Unlike Mach these permissions were not enforced by the kernel, applications that required the services were expected to do the work internally.
Although Spring did not specifically set out to address performance issues, the system was nevertheless much faster than Mach. Specifically, Mach IPC was fairly slow, much slower than the analagous syscall or trap into a Unix kernel. Measurements showed that such a call took about 20 usec on a 486DX-50 for existing BSD Unix systems, and 114 usec under Mach. This led to a performance hit of 50% or more, and doomed most Mach projects. In retrospect the vast majority of this time is spent poorly, applying rights and permissioning and checking the message for validity. These are better handled by the applications that need them, and only those applications, whereas under Mach IPC was a serious distributed cost .
In contrast, Spring boasted a IPC time of only 11 usec on a SPARCstation 2. The exact reasons for this excellent performance are not clear, as explainatory documents are no longer easily available. It is likely that some of this is due to architechtual differences between the x86 and SPARC processors, but that could not explain it all. It is more likely that Spring removed the type checking and permissioning from the kernel itself, as was done on more modern kernels such as L4. This leaves some question to the overall effect on performance, although the functionality does not appear to belong in the kernel, it still has be run somewhere.
Spring's kernel was divided into two parts, the nucleus which provided application support, task management and IPC, and the vm manager which handled memory. Another serious performance problem under Mach was poor vm because the system didn't have a real understanding of the operating system as a whole, under Spring this was addressed by special-casing the vm. Developers could write custom pagers tuned for different workloads, and link them directly into the kernel for added performance. Mach also added user-built pagers in Mach 3, but used the IPC mechanism to communicate with them, adding a major performance overhead.
Another key addition was a naming service for doors. Mach had developed from the Unix model, where devices were represented as "well known files"; for instance a printer could always be found in the /dev directory. Mach 2 was a re-programming of BSD and did not offer too much flexibility, so it wasn't until Mach 3 arrived that problems with this concept became clear. Under Mach 3 it was imagined that a user could start or stop servers as they wanted, which meant that the system would have no idea exactly what was running or how to serve various requests. Moreover each operating system would have different sets of expected services, and many of these never had the concept of well known locations. Once again Mach was exporting Unix-like ideas to all systems.
Spring added what is, in retrospect, an obvious solution, a name server that hands out door addresses on demand. Under Spring applications could discover what capabilities were available and what server was handling them, as a minimum conversion needed to run on Spring. Although in most cases the ports/doors would indeed be well known -- a Unix server would know to expect certain Unix servers, a Mac OS server would know to expect certain Mac OS servers -- Spring was developed with the express intent of allowing several completely different operating systems to be run at the same time. Under this model, the name server becomes very important.
The rest of the Spring system consisted of a number of servers. These included a file system server (note the language here, this is a file-system server, not a file-server system), TCP/IP server, authentication manager and name server. Spring's server set represented everything needed to run a full system. Applications could be written by importing the needed libraries and calling functions, which would in turn use the name server to find the required servers and pass them information using IPC. From a development standpoint, Spring applications were small and easy to write.
Spring also needed to support existing Unix applications, the basis of Sun's business. To do this, Spring also shipped with two key extensions, a Unix process server that mimiced a full Unix, and a re-write of the standard libc library called libue that redirected Unix kernel requests to various servers. For instance, a Unix application that required file or network services would be directed to the associated Spring server, while one that wanted to list the currently running programs would be directed to the Unix process server. The process server was also responsible for handling signals, a concept that had no analog under Spring -- nor did it really need it, signals are essentially an inflexible single-purpose IPC mechanism.
Running Unix applications under Spring required that they be re-linked against libue, and the system shipped with the majority of basic Unix utilities and an X11 server pre-rolled. However this process was neither invisible nor guarenteed to work; Spring documents note that "many" applications will run unmodified, but fails to mention what sort of problem areas the developer should expect.