This document applies to the Janos Java Libraries v1.2.0 and later snapshots containing minor updates.
Due to inadequate ``style sheet'' support in various tools, the HTML version of this document is currently missing substantial font faces that make it easier to read, in particular bold face, italics, and those +/- signs in the bulleted list below. You might want also to look at the postscript version. On the other hand, you can click on these links.
The Janos Java NodeOS (or ’jnodeos’) is a Java implementation of the NodeOS API Specification. The Janos Java NodeOS supports all of the major NodeOS abstractions including Threads, Channels, Domains, ThreadGroups, and DemultiplexKeys.
The Janos Java NodeOS distribution is organized as follows. The top-level includes the following directories
The src/ directory contains the most interesting bits. Specifically, the subdirectories breakdown as follows:
The source files actually contain a lot of useful and up-to-date comments so, as always, the source is the best place to go for answers.
The current NodeOS Specification1 specifies the following standard interfaces and abstractions. The “+” and “-” marks indicate the current degree of support in our Java binding.
Of these interfaces, the Janos Java NodeOS currently provides Java bindings for the Domain, ThreadPool, and Channels. A Buffer abstraction that works at a higher level than the Packet abstraction is also provided. The Java bindings in this interface are meant to simultaneously take advantage of Java’s direct support for objects (e.g., utilizing constructors) and hide NodeOS details that need not be exposed at this level (e.g., the memory page mapping interfaces). To these ends, on some details the mapping deviates from the C bindings defined in the NodeOS specification. The goal of this interface is that it be trivial to implement on top of the specified NodeOS C API, while only exposing the details that a Java-based EE needs.
There are currently two implementations of the Janos Java NodeOS. One, the “pure java” version, is written purely in Java and runs on standard JDK 1.1-compliant runtimes. The other implementation runs on the Janos project’s C implementation of the NodeOS, Moab. The two implementations share a lot of code, the choice of which to use is a compile-time configuration option. For details read the installation instructions.
Several of the names chosen for Janos NodeOS Interface functions are different than their C API NodeOS counterparts. Some of these will be changed to reflect the NodeOS name; others are more in line with Java conventions and will remain. Details are provided later.
The javadoc-style documentation of the actual Java interfaces is available at http://www.cs.utah.edu/flux/janos/apidoc/.
This section provides a function-to-function comparison of the C language binding of the NodeOS API with the equivalent Janos Java NodeOS interface function. This section will make sense only if you are very familiar with the NodeOS specification, or if you have a copy of it next to you.
Each of the Janos classes listed below is in the edu.utah.janos.nodeos package, e.g., the fully qualified name of the method Domain.newDomain(...) is edu.utah.janos.nodeos.Domain.newDomain(...).
Because Java supports real namespaces (via package names), the Janos Java NodeOS dispenses with the an_, AN_, and ani_ prefixes that plague the C implementation.
The Janos Domain abstraction is designed to directly map a NodeOS domain’s capabilities into Java. There are no semantic changes introduced other than the DomainHandle which is a “cross-process” handle on a Domain object, and is used for termination.
Thread Pools are basically unchanged in the Janos implementation. We do expose a Thread object, but it contains only the features defined by the NodeOS Thread Pool interface. The Janos Java NodeOS bindings do not expose the ability to disable/enable interrupts or to change a thread’s priority. Additionally, thread-interrupt handlers are not available at the Java level. Currently, the interrupt() method only provides the function provided by native Java; it will only wake sleeping threads and post an interrupt flag on them.
While the NodeOS interfaces are the same, one change is made to the semantics. The NodeOS C API maintains a strictly one-to-one binding between ThreadPool and Domain. We relax that restriction in Janos. Thus, in Janos, a domain’s start function is part of the Domain object, and not part of the ThreadPool constructor (as in the NodeOS C API). This lets us create multiple ThreadPools within a single Domain, for example, to have different thread pools to service the control and data packets in a single logical domain.
In terms of synchronization, the Janos Java NodeOS interface provides the standard Java synchronization mechanisms in place of the NodeOS specified functions. Additionally, there is a Semaphore construct available. Mutexes may be added later, but we have not yet had a need for them.
The Janos Java NodeOS interface wraps the low-level NodeOS Channel abstractions into three distinct classes: OutChannel, InChannel and CutThroughChannel. Instead of sending or receiving Packets, at the Java level BufferHandle objects are used.
Just as in the NodeOS spec, Java Channel objects are fairly static. The constructor determines the demultiplex key, address, protocol processing, and thread pool that the channel should use.
All memory management in Janos is implemented within the JVM (err, it will be implemented in there). There are currently no memory management interfaces at the Java level except for specifying a limit when a new Domain is created (see MemSpec).
Janos does not define any wrappers for the POSIX-like file system interfaces specified in the NodeOS document. On the other hand, the existing JDK file interfaces are quite close to POSIX already. Janos does define some utility classes for logging, but they are “above” the NodeOS specifications.
There is some support in the implementation of ThreadPools and their WorkItems to support events, but no public interface is yet implemented (ANTSR didn’t need it...).
Janos uses the Java-standard new to allocate objects. Since Java is garbage collected, the reclamation of objects is hidden from Java.
The NodeOS defines a Packet object for sending and receiving chunks of data from the network. Packets are designed to simplify adding and re-writing headers. The Janos NodeOS interface provides a higher-level abstraction, the BufferHandle which, in addition to the services provided by a Packet, provide a level of indirection that makes Buffers suitable for sharing between domains. See the Javadoc description of BufferHandle for more detail.
The Janos NodeOS interface is designed for a JVM (the JanosVM, actually) that will provide strong separation of domain heaps. As such, sharing between domains is strictly limited to raw buffers (shared via BufferHandles).
Additionally, a rudimentary inter-domain communication mechanism, the CommSpace, has been implemented. These interfaces and their semantics are not derived from any part of the NodeOS specification. They are unique to the Janos approach to multiple domains in a single JVM. Note also that at the Java level we do not plan to expose any of the inter-domain or inter-EE facilities specified in the NodeOS spec.
The development effort was led by Patrick Tullmann. The Java NodeOS layer was developed by Patrick and Chris Hawblitzel, while the latter was on a summer internship at Utah. Tim Stack wrote the JanosVM bindings and re-worked a lot of the internals for that work. Patrick wrote most of this document.