\section{Design constraints}
\label{sec:constraints}

In this section, we discuss the language design constraints that arise
from the desire to be resource-aware and the use of mobility as a
mechanism to adapt to changes in resource availability. We discuss the
requirements of awareness, agility and authority and the constraints
each of them generates.  In the next section, we describe Sumatra and
discuss how its design has been guided by these constraints.


\subsection{Awareness}
\label{sec:awareness}

Resource-aware programs need to be able to monitor the availability
and quality of the resources in their environment.  A resource can be
monitored either on-demand or continuously.  Both kinds of monitoring
are useful. On-demand monitoring is useful in three kinds of
situations. First, if the resource in question is used infrequently
but is expensive to use -- e.g. an application on a mobile host that
uses a cell-modem to periodically scan incoming mail being held at a
post-office machine. Second, if the availability of the resource in
question changes infrequently -- e.g. an application that chooses the
location from which it monitors a process based on the amount of disk
space available at that location. Third, if the resource is expensive
to monitor and the cost of monitoring outweighs the potential gains --
e.g. an application that accesses large volumes of data over a very
slow link. Continuous monitoring is useful if the resource is
frequently used or if the resource changes frequently or is cheap to
monitor.

On-demand monitoring is, by necessity, synchronous. The request for
information does not return until the information is available.
Continuous monitoring can, on the other hand, support both synchronous
and asynchronous interfaces. A synchronous request would return
immediately with information about the current availability of the
resource in question whereas an asynchronous request would monitor the
resource and notify the application only when the resource
availability no longer satisfies an application-specified predicate. A
synchronous interface is suitable, for example, for an application
that sends a sequence of large messages and checks the state of the
network before sending each message. An asynchronous interface is
useful, for example, for an application that uses a resource
continuously (like receiving a video stream over the network) or an
application that does not use the network itself but calls library
routines which may do so. An asynchronous interface is also useful to
inform applications about a qualitative change in the operating
environment, for example if the platform is mobile and may need to
switch between multiple wireless networks~\cite{Katz96}. 

For continuous monitoring, an important decision is the granularity at
which resource change is to be monitored. The simplest alternative is
to report every change to the requesting application. This is often
impractical as most resource levels have some jitter which usually has
little impact on application performance. The next simplest
alternative is to use a jitter threshold and track only those changes
that larger than this threshold. Jitter-threshold-based schemes have
been proposed by several researchers as a way of dealing with resource
variability on mobile platforms~\cite{BadrinathW95,NoblePS95}.
Jitter-threshold-based schemes work well if changes in the resource
levels are usually stable. Transient changes (usually just spikes) in
the resource levels can cause spurious responses. The alternative is
to augment the jitter-based scheme with a filter that eliminates
transients. This allows the applications to track only the stable
changes. It is therefore important to allow applications to register
application-specific (or resource-specific) filters that determine
which changes in resource availability/quality should be reported to
the requesting application.

To summarize, languages for resource-aware mobile programs should
provide a resource-monitoring interface that allows on-demand
monitoring as well as continuous monitoring. For continuous monitoring,
the resource-monitoring interface should allow programs to register a
application-specific filter which determines which resource changes
should be reported.

\subsection{Agility}
\label{sec:agility}

To achieve agility, a mobile code language should provide mechanisms
that allow programs to react quickly to asynchronous events like
revocation of allocated bandwidth/memory or qualitative changes in
network connectivity (e.g. on a mobile host). Two mechanisms are
required.  First, the ability to receive the event in an asynchronous
manner (a la Unix signals) and second, the ability to take appropriate
action in response to such events including moving program execution
to a different site.

The requirement that programs be able to move within event handling
code constrains the choice of mobility mechanisms.  There are two
major alternatives: (1) a {\tt go()} (or a {\tt jump}) primitive that
freezes execution at current site and resumes execution at target
site; and (2) a function-call-like mechanism which allows programs to
execute a procedure at a specified site. Most mobile code languages
have selected one of these two alternatives.  Agent-Tcl~\cite{Gray96},
Telescript~\cite{White96} and Aglets~\cite{LangeO96} use a {\tt
go}-based mechanism whereas Obliq~\cite{Cardelli95},
Avalon~\cite{ClamenLNW90}, NCL~\cite{Falcone87} REV~\cite{StamosG90}
and TACOMA~\cite{JohansenRS95} use a function-call-based interface.
To ensure a prompt response to asynchronous events, a
function-call-based interface would require one of two things: (1)
either the language automatically captures the continuation at the
point at which an event occurs and makes it available for use within
the corresponding event handler; or (2) the programmer emulates this
functionality by writing a large number of functions that represent
continuations at different points in the programs. In both cases, the
language has to allow the use of a continuation-passing style.  We
believe a {\tt go()}-based interface is simpler to use; the astute
reader has probably already noted that the first option has exactly
the same effect as a {\tt go()}.

\subsection{Authority}
\label{sec:authority}

The requirement of authority is, by far, the most demanding. It
requires that language allow programs to control the way in which
resources are used on their behalf by system support as well as by
libraries. In effect, it requires that module boundaries not be
completely opaque and that they allow resource-usage related
restrictions to pass through and enforced as a part of execution.

There is a trade-off between the extent to which programs are allowed
to control resource-use and ease of programming. At one extreme, a
language can require that operations that use resources of interest be
performed only after they have been explicitly authorized. This allows
complete control over resource usage. Unauthorized accesses would
raise an exception. A scheme similar to this is used by Java applets
to control access to local resources (see
Figure~\ref{fig:java-security} for an example). This works well for
Java applets as the level of access to local resources is not usually
changed during the execution of a program and there is no advantage in
retrying the operation.

On the other hand, it is entirely possible that the response to
authorization failure for resource-usage can be (and in many cases,
will be) to change the level of authorization. In such cases, retrying
the operation would be desirable. This can be a problem if
authorization failures occur deep in library code. It may or may not
be possible to restart the operation if the failure is delivered as an
exception. For example, consider the code in
Figure~\ref{fig:restart-problem}. For this example, assume that the
resource of interest is the number of sockets. If the first call to
checkCreateSocket() succeeds and the second fails (say the program has
already created as many sockets as it was permitted to), an exception
will be raised. A common response to this situation would be to
negotiate with the resource manager for a higher limit on the number
of sockets and to restart the operation. However, a clean restart for
{\tt createTwoSockets()} is not possible as the first socket has
already been created.

This situation can be dealt with by treating resource-use violation as
an asynchronous event and allowing programs to associate a handler
with every restriction on resource-use. The handler would be executed
in the same context as the operation that caused the violation and
would allow the operation to be restarted, if that is what is desired.

To summarize, both forms of control over resource use are desirable:
(1) checking all operations that might use resources of interest for
authorization and delivering an exception if the usage is not
authorized; (2) considering resource-use violation as an asynchronous
event and allowing programs to associate event handlers to
resource-use restrictions which execute in the same context as the
faulting operation.


\begin{figure}
\tightboxit{
\begin{tabbing}
ttttttttt\=ttt\=ttt\=ttt\= \kill
\>{\tt  public boolean mkdir() \{ \ \ \ \ \ \ \ \ \ \ \ \ \ \ }\\
\>\>{\tt        SecurityManager security = System.getSecurityManager();}\\
\>\>{\tt        if (security != null) \{}\\
\>\>\>{\tt            security.checkWrite(path);}\\
\>\>{\tt        \}}\\
\>\>{\tt        return mkdir0();}\\
\>{\tt    \}}\\
\\
\>{\tt    public boolean renameTo(File dest) \{}\\
\>\>{\tt        SecurityManager security = System.getSecurityManager();}\\
\>\>{\tt        if (security != null) \{}\\
\>\>\>{\tt            security.checkWrite(path);}\\
\>\>\>{\tt            security.checkWrite(dest.path);}\\
\>\>{\tt        \}}\\
\>\>{\tt        return renameTo0(dest);}\\
\>{\tt    \}}\\
\end{tabbing}
}
\caption{Excerpts from Java class libraries that illustrate how access
to local resources is controlled. The actual operations of creating 
a directory and renaming a file are performed by {\tt mkdir0()} and
{\tt renameTo0()}.}
\label{fig:java-security}
\end{figure}

\begin{figure}
\tightboxit{
\begin{tabbing}
tt\=ttt\=ttt\=ttt\= \kill
\>{\tt public boolean createSocket(String host, int port, boolean stream) \{}\\
\>\>{\tt        ResourceManager resource = System.getResourceManager();}\\
\>\>{\tt        if (resource != null) \{ }\\
\>\>\>{\tt        resource.checkCreateSocket(host,port,stream);}\\
\>\>{\tt        \}}\\
\>\>{\tt        return Socket(host,port,stream);}\\
\>{\tt    \}}\\
\\
\>{\tt  private Socket socket1;}\\
\>{\tt  private Socket socket2;}\\
\> .... \\
\>{\tt  public void createTwoSockets(String host1,String host2,int port,}\\
\>\>\>{\tt boolean stream) \{ }\\
\> ... \\
\>\>{\tt        socket1 = createSocket(host1,port,stream);}\\
\>\>{\tt        socket2 = createSocket(host2,port,stream);} {\bf // fails authorization check}\\
\>{\tt    \}}\\
\end{tabbing}
}
\caption{Sample Java code to illustrate the problem with 
restarting operations that fail authorization checks. This code assumes 
that Java is extended with a Resource Manager similar to its current
Security Manager.}
\label{fig:restart-problem}
\end{figure}

