A team [1] is similar to a Unix process: it creates a strong boundary around executing code, tracking its resource usage and isolating it from other programs. Unlike a Unix process, however, teams are maintained entirely within JanosVM, without reliance on any underlying OS or hardware support for such separation. Instead, JanosVM provides the team abstraction using mechanisms from garbage collection and the language runtime. Thus, JanosVM is able to run multiple Java bytecode programs within the same "JVM" without losing the ability to manage them, analogous to each Java bytecode program running in a separate Unix process. The obvious benefits of this approach lie in the ability to share the tremendous amount of machinery needed to execute Java code in the first place and to optimize the usage of resources between teams. In addition, this approach can also reduce the amount of work needed for inter-process communication since threads can easily switch between teams within the VM, rather than having to communicate through low-level Unix primitives.


Teams are represented internally as jteam structures which contain other structures that track resource usage and provide the context for the threads executing within the team. At the Java level a team is represented by two classes and can be accessed by a third proxy class. First, there is the kernel-private TeamBackEnd class [2] which provides room for the C jteam structure. Second, there is the Team class which holds any team-wide data not held by the kernel and provides a path for code in the same to access its TeamBackEnd object. Finally, there is the TeamHandle class which provides user code with limited access to any team in the system.


The team structure has only a few operations associated with it since most of the work is done by the objects hanging off these structures. The primary operation done on a team object is visiting it; in other words, changing the context of a thread from one team to another. This context change allows a thread to do work on behalf of one team with the facilities provided by another. For example, when a thread needs to load a class file it visits the kernel team (since files need to be managed by the kernel), loads the file, and returns to its previous team. When a thread visits another team its context is substantially switched to that team. While the visit is active both of the involved teams are unkillable, and both heaps are visible to the visiting thread. Hopefully, this simple primitive provides enough power for higher level code to implement almost any desired inter-team communication mechanism.

The visit operation has some similarities to certain lightweight client-server invocations in more traditional kernels such a Mach's "migrating threads" and Taos's LRPC. One difference is that in JanosVM the "server" doesn't have to dedicate any resources (i.e., worker thread) to handling incoming calls, since the caller's stack can be safely shared through language type safety mechanisms. Another difference is that the visit operation is not safe, as described above. In fact, the JanosVM cross-team visit is like a generalization of a kernel syscall, but without the trapping and stack switching.

The other major operation on a team object is termination. The termination of a team returns all of its resources back to the kernel for others to use. This is quite a complicated operation to perform correctly since we have to make sure that any shared state or data isn't going to be damaged when the team's threads are killed. Fortunately, the visit clearly tells us when shared data is being manipulated so we can just track how many threads have entered or left a team to determine when we can terminate it.

Note that a system built on top of JanosVM that needs to be able to terminate teams without delay will have to closely guard the visitation primitives as visits can indefinitely delay termination.

Cross-team references

Since some objects created by one team are likely to be needed by another we must have a method for tracking them so the references can be revoked or marked stale. Internally, the VM contains no cross-team pointers unless they are explicitly managed by a resource, bounded by another team's lifetime (e.g., the kernel), or are handled in an indirect way (like file descriptors in Unix). When working at the Java level there are instances of the Exportable and Importable classes which provide a base for objects that are to be exported or imported, respectively. Since any Exportable and Importable objects are tracked by the team we can null out their references so that no Java code attempts to use the now dead segment of memory.

Creating and using teams

Currently, all teams are Java objects since we use their Java locks [3]. To create one you use the create() static method in the Team class. This method will create a team with the specified name and set of resources and then return a TeamHandle object which can be used to communicate with the new team. Most likely, the first thing to do is visit the team, duplicate any data needed from your own team and start some new threads in the new team.

Related Files


  1. [1] - The name `team' was first used in the V Kernel [Cheriton 1984] and is currently used in the BeOS operating system to designate an entity similar to a Unix `process' or Mach `task'. Basically, in the JanosVM context the notion of a `team of threads' makes more sense to (some of) us than the more amorphous term `process', which is already overused (e.g., in the embedded systems community `process' actually means `thread').
  2. [2] - The TeamBackEnd class has been postprocessed by the nativeClass code which adds space in a Java object for C data structures.
  3. [3] - Using Java locks: might change in the future.
Return to the main documentation page.
Copyright (c) 2000, 2001 The University of Utah and the Flux Group.
All rights reserved.

Permission to use, copy, modify, distribute, and sell this documentation for any purpose is hereby granted without fee, provided that the above copyright notice(s) appear in all copies.