Janos Component Manual

Flux Research Group
Department of Computer Science, University of Utah
janos@flux.cs.utah.edu

October 14, 1999

This document applies to Janos snapshot 990923 and later snapshots containing minor updates. Eventually this document will become a repository of information on the structure and design of the major components of Janos.

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. You might want also to look at the postscript version. On the other hand, you can click on these links.

The released Janos code is currently all in the java/ subdirectory. There are currently two major components to that code:

The route/ directory contains a first pass implementation of the NodeOS-level routing table. Its a simple table that maps addresses to route objects. The other parts of the current java directory (io/ and lib/) are very underdeveloped and hardly worth documenting at this point. The io/ directory will contain the NodeOS logging and debugging facilities; lib/ contains utility code for EEs running on the Janos NodeOS interface;

1 Janos Nodelib

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 NodeOS interface currently provides Java bindings for the Flow, 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 NodeOS C API, while only exposing the details that an EE needs. (The current implementation is entirely in Java, using the standard JDK 1.1 facilities.)

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/.

1.1 Comparison to NodeOS C bindings

This section provides a function-to-function comparison of the C language binding of the NodeOS API with the equivalent Janos NodeOS interface function. This section will make sense only if you are very familiar with the NodeOS specification, or you have a copy of it next to you.

Each of the Janos classes listed below is in the utah.janos.core package, e.g., the fully qualified name of the method Flow.newFlow(...) is utah.janos.core.Flow.newFlow(...).

1.1.1 Flows

The Janos Flow abstraction is designed to directly map a NodeOS flow's capabilities into Java. There are no semantic changes introduced other than the FlowHandle which is a "cross-process" handle on a Flow object, and is used for termination.

1.1.2 Thread Pool

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. Janos does 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 functions provided by native Java; it will only wake sleeping methods or 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 Flow. We relax that restriction in Janos. Thus, in Janos, a flow's start function is part of the Flow object, and not part of the ThreadPool constructor (as in the NodeOS C API). This lets us create multiple ThreadPools within a single Flow, for example, to have different thread pools to service the control and data packets in a single logical flow.

In terms of synchronization, the Janos NodeOS interface provides the standard Java synchronization mechanisms in place of the NodeOS specified functions. There is a Semaphore construct in the core. Mutexes may be added later, but we haven't yet had a need for them.

1.1.3 Channels

The Janos NodeOS interface wraps the low-level NodeOS Channel abstraction into three distinct classes: OutChannel, InChannel and CutThroughChannel. In place of attributes, the Janos Channel abstractions just use constructor arguments. Additionally instead of sending or receiving Packets, at the Java level Buffer objects are used.

Just as in the NodeOS spec, Java Channel objects are fairly static. The constructor determines the demultiplex key, address, and thread pool that the channel should use.

The only public methods on an InChannel are the constructor and the msgLoop() function (which implements the packet dispatch). Note that msgLoop() isn't necessary on a "real" NodeOS as the packet dispatch functionality is part of the NodeOS-provided service. In Janos this method dedicates the calling thread to receiving packets (UDP) and finding the appropriate target thread.

OutChannels in Janos are similar to an output Channel created with the NodeOS C API. When an OutChannel is created a Flow object and Address must be specified. This implies that an OutChannel is statically tied to a single destination host. We believe this is consistent with the spec, but were somewhat surprised to discover this.

CutThroughChannels are even simpler, having only a constructor. The constructor requires a Flow, a DemultiplexKey, a ThreadPool, and an Address. Like OutChannels, a CutThroughChannel cannot be changed once created. Note that the Janos DemultiplexKey is somewhat more complicated (multiple, variable-offset sequences) than the simple keys to which the NodeOS C API is limited.

We seem to have gotten this far without the destroy operation on a Channel, but will have to implement it soon.

1.1.4 Memory Pool

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 Flow is created (see MemSpec).

1.1.5 FileSystem

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.

1.1.6 Attributes

Not implemented yet. If necessary, this will simply provide another interface to object construction. For example, a new constructor might be added to Flow with this signature: Flow(Attribute attrs).

1.1.7 Events

There is some support in the implementation of ThreadPools and their WorkItems to support events, but no public interface is yet implemented (ANTS didn't need it...).

1.1.8 Heap

Janos uses the Java-standard new to allocate objects. Since Java is garbage collected, the reclamation of objects is hidden from Java.

1.1.9 Packets

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 higher-level abstractions, the Buffer and BufferHandle which, in addition to the services provided by a Packet, provide a level of indirection that makes Buffers suitable for sharing between flows. See the Javadoc description of BufferHandle for more detail.

1.1.10 Inter-flow Sharing

The Janos NodeOS interface is designed for a JVM (the JanosVM, actually) that will provide strong separation of flow heaps. As such, sharing between flows is strictly limited to Buffers (shared via BufferHandles). A rudimentary inter-flow 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 flows in a single JVM. Note also that at the Java level we do not plan to expose any of the inter-flow or inter-EE facilities specified in the NodeOS spec.

2 ANTSR

Within the ANTSR tree are three subtrees. Look at the documentation within each file to get a handle on its function. There are also a couple of README files scattered around that should help.

For those who have an understanding of earlier versions of ANTS, the following high-level change list might be useful.

2.1 Changes to ANTS to make our ANTSR

2.1.1 Rationale and motivation

The NodeOS interfaces defines InChannels, OutChannels, and CutThroughChannels, Threads, packet filters, Addresses, and Flows (Processes). We take advantage of these primitives wherever possible in ANTSR. In many cases the new abstractions are much cleaner than the implicit abstractions defined in ANTS.

Many internal parts of ANTS had to change to accommodate precise resource control. For example, we start up a new Flow (a new "process") as early as possible in order to charge the resources used in downloading code and creating Flow-specific state to the appropriate Flow. This required fundamental changes to the way protocols are stored and forwarded.

We strove not to change the programming interface exported to ANTS protocols and applications. However, minor changes were introduced into the startup and definition of an application, and we removed some of the softstate interfaces.

We updated class and object names. While making wholesale changes to the infrastructure we took the opportunity to rename classes that had evolved beyond their original design. For example, Method in the old ANTS actually stood for a Class. It is now named CapsuleClass.

We installed each protocol in its own namespace, using a ClassLoader. Each protocol instance now gets its own set of threads for handling dispatch, decoding and delivery.

2.1.2 Specific Changes

Credits

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. ANTSR was developed by the same crew, building on earlier ANTS work by Godmar Back. Original ANTS, of course, was developed by David Wetherall. Patrick wrote most of this document.