1150 lines
47 KiB
TeX
1150 lines
47 KiB
TeX
\documentclass[a4paper,twoside]{report} % for a report (default)
|
|
|
|
\usepackage{amsmath}
|
|
\usepackage{bftn} % You need this
|
|
\usepackage{cite}
|
|
\usepackage{color}
|
|
\usepackage{listings}
|
|
|
|
\title{Inter-dispatcher communication in Barrelfish} % title of report
|
|
\author{Andrew Baumann} % author
|
|
\tnnumber{011} % give the number of the tech report
|
|
\tnkey{IDC} % Short title, will appear in footer
|
|
|
|
% \date{Month Year} % Not needed - will be taken from version history
|
|
|
|
\begin{document}
|
|
\maketitle
|
|
|
|
%
|
|
% Include version history first
|
|
%
|
|
\begin{versionhistory}
|
|
\vhEntry{0.0}{06.08.2010}{AB}{Initial version}
|
|
\vhEntry{0.1}{01.09.2010}{AB}{Documented Flounder IDL, stub API and waitset}
|
|
\vhEntry{0.2}{21.10.2010}{AB}{Completed runtime support chapter}
|
|
\vhEntry{0.3}{05.12.2011}{MN}{Added meta-parameter note, AHCI references}
|
|
\end{versionhistory}
|
|
|
|
% \intro{Abstract} % Insert abstract here
|
|
% \intro{Acknowledgements} % Uncomment (if needed) for acknowledgements
|
|
% \tableofcontents % Uncomment (if needed) for final draft
|
|
% \listoffigures % Uncomment (if needed) for final draft
|
|
% \listoftables % Uncomment (if needed) for final draft
|
|
|
|
\lstset{
|
|
language=C,
|
|
basicstyle=\ttfamily \small,
|
|
flexiblecolumns=false,
|
|
basewidth={0.5em,0.45em},
|
|
boxpos=t,
|
|
}
|
|
|
|
\newcommand{\note}[1]{[\textcolor{red}{\emph{#1}}]}
|
|
|
|
\tableofcontents
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
\chapter{Introduction}
|
|
|
|
TODO
|
|
|
|
\chapter{Flounder stub compiler}\label{cha:flounder}
|
|
|
|
\section{Overview}
|
|
|
|
\section{Interface definition language}\label{sec:idl}
|
|
|
|
\subsection{Lexical conventions}
|
|
The following convention, derived from Mackerel\cite{btn002-mackerel} has
|
|
been adopted for Flounder. It is similar to the convention in modern
|
|
day programming languages like C and Java.
|
|
|
|
\begin{description}
|
|
\item[Whitespace:] As in C and Java, Flounder considers sequences of
|
|
space, newline, tab, and carriage return characters to be
|
|
whitespace. Whitespace is generally not significant.
|
|
|
|
\item[Comments:] Flounder supports C-style comments. Single line comments
|
|
start with \texttt{//} and continue until the end of the line.
|
|
Multiline comments are enclosed between \texttt{/*} and \texttt{*/};
|
|
anything inbetween is ignored and treated as white space.
|
|
|
|
\item[Identifiers:] Valid Flounder identifiers are sequences of numbers
|
|
(0-9), letters (a-z, A-Z) and the underscore character ``\texttt{\_}''. They
|
|
must start with a letter or ``\texttt{\_}''.
|
|
\begin{align*}
|
|
identifier & \rightarrow ( letter \mid \_ ) (letter \mid digit \mid \_) \\
|
|
letter & \rightarrow (\textsf{A \ldots Z} \mid \textsf{a \ldots z})\\
|
|
digit & \rightarrow (\textsf{0 \ldots 9})
|
|
\end{align*}
|
|
|
|
\item[Integer Literals:] A Flounder integer literals is a sequence of
|
|
digits, optionally preceded by a radix specifier. As in C, decimal (base 10)
|
|
literals have no specifier and hexadecimal literals start with
|
|
\texttt{0x}.
|
|
\begin{align*}
|
|
digit & \rightarrow (\textsf{0 \ldots 9})\\
|
|
hexadecimal & \rightarrow (\textsf{0x})(\textsf{0 \ldots 9} \mid \textsf{A
|
|
\ldots F} \mid \textsf{a \ldots f})
|
|
\end{align*}
|
|
|
|
|
|
\item[Reserved words:] The following are reserved words in Flounder:
|
|
\begin{alltt}\begin{tabbing}
|
|
xxxxxxxxx \= xxxxxxxxx \= xxxxxxxxx \= xxxxxxxxx \= xxxxxxxxx \= xxxxxxxxx \kill
|
|
alias \> call \> enum \> in \> interface \> message \\
|
|
out \> response \> rpc \> struct \> typedef
|
|
\end{tabbing}\end{alltt}
|
|
|
|
\item[Builtin types:] The following identifiers are recognised as builtin types:
|
|
\begin{alltt}\begin{tabbing}
|
|
xxxxxxxxxxxx \= xxxxxxxxxxxx \= xxxxxxxxxxxx \= xxxxxxxxxxxx \= xxxxxxxxxxxx \=
|
|
xxxxxxxxxxxx \kill
|
|
bool \> cap \> char \> give_away_cap \> int \> int8 \\
|
|
int16 \> int32 \> int64 \> intptr \> iref \> size \\
|
|
string \> uint8 \> uint16 \> uint32 \> uint64 \> uintptr
|
|
\end{tabbing}\end{alltt}
|
|
|
|
\item[Special characters:] The following characters are used as operators,
|
|
separators, terminators or for other special purposes in Flounder:
|
|
\begin{alltt}
|
|
\{ \} [ ] ( ) ; ,
|
|
\end{alltt}
|
|
|
|
\end{description}
|
|
|
|
|
|
\subsection{Interface specification}
|
|
|
|
A Flounder input file must specify a single interface, of the form:
|
|
|
|
\begin{syntax}
|
|
interface \synit{name} ["\synit{description}"]
|
|
\verb+{+
|
|
\synit{types};
|
|
\ldots
|
|
\synit{messages};
|
|
\ldots
|
|
\verb+}+;
|
|
\end{syntax}
|
|
|
|
\begin{description}
|
|
\item[name] is an identifier for the interface type, and will be used to
|
|
generate identifiers in the target language (typically C). While
|
|
not currently enforced by the Flounder compiler, by
|
|
convention this should only differ from the name of the file in case
|
|
and suffix, e.g.\ the file \texttt{xapic.dev} defines a device type
|
|
of name \texttt{xAPIC}.
|
|
|
|
\item[description] is a string literal in double quotes, which
|
|
describes the interface being specified, for example
|
|
\texttt{"Name service"}.
|
|
\end{description}
|
|
|
|
After the description string follows in curly brackets a series of
|
|
declarations which specify types, messages and their arguments. Each
|
|
declaration must be one of the following:
|
|
|
|
\begin{itemize}
|
|
|
|
\item A transparent type alias, using the \texttt{alias} declaration,
|
|
described in Section~\ref{sec:lang:alias}.
|
|
|
|
\item A type definition, using the \texttt{typedef} declaration,
|
|
described in Section~\ref{sec:lang:typedef}.
|
|
|
|
\item A simple message specification, using either the \texttt{message},
|
|
\texttt{call} or \texttt{response} declarations, describing a
|
|
single unidirectional message with typed arguments,
|
|
and described in Section~\ref{sec:lang:message}.
|
|
|
|
\item An \texttt{rpc} specification, which describes two related
|
|
messages (a call and the response) with a single declaration,
|
|
and described in Section~\ref{sec:lang:rpc}.
|
|
|
|
\end{itemize}
|
|
|
|
Type aliases and definitions (\texttt{alias} and \texttt{typedef}) are
|
|
optional, but if present must precede all messages. There must be at least
|
|
one message in every interface.
|
|
|
|
\subsection{Transparent type alias}\label{sec:lang:alias}
|
|
|
|
\begin{syntax}
|
|
alias \synit{aliasname} \synit{builtintype};
|
|
\end{syntax}
|
|
|
|
This simply declares a given alias name that may henceforth be used in the
|
|
interface file in place of the given builtin type. It does not alter the
|
|
generated code.
|
|
|
|
\subsection{Type definition}\label{sec:lang:typedef}
|
|
|
|
In contrast to an alias, the \texttt{typedef} keyword causes a new type
|
|
to be created in the context of both the interface file and the programming
|
|
language where the generated stubs are used.
|
|
|
|
\subsubsection{Structure}
|
|
|
|
\begin{syntax}
|
|
typedef struct \verb+{+
|
|
\synit{typename} \synit{fieldname};
|
|
\ldots
|
|
\verb+}+ \synit{structname};
|
|
\end{syntax}
|
|
|
|
This declares a compound type, akin to a structure in C.
|
|
|
|
\subsubsection{Fixed-size array}
|
|
|
|
\begin{syntax}
|
|
typedef \synit{typename} \synit{arrayname}\verb+[+\synit{size}\verb+]+;
|
|
\end{syntax}
|
|
|
|
Where \emph{typename} is a previously-defined type, and \emph{size} is an
|
|
integer literal, defines an array type with the given \emph{arrayname}. This
|
|
name refers to an array of a fixed size.
|
|
|
|
\subsubsection{Enumeration}
|
|
|
|
\begin{syntax}
|
|
typedef enum \verb+{+
|
|
\synit{fieldname},
|
|
\ldots
|
|
\verb+}+ \synit{structname};
|
|
\end{syntax}
|
|
|
|
An enumeration, as in C, is represented as an integer type that may take
|
|
one of the predefined symbolic values.
|
|
|
|
\subsubsection{Alias}
|
|
|
|
\begin{syntax}
|
|
typedef \synit{aliasname} \synit{typename};
|
|
\end{syntax}
|
|
|
|
This form creates a new name (in both Flounder and C) for a
|
|
previously-defined or builtin type.
|
|
|
|
|
|
\subsection{Simple message}\label{sec:lang:message}
|
|
|
|
A simple message specification takes the form:
|
|
|
|
\begin{syntax}
|
|
@\synit{context}\verb+(+\synit{name}\verb+=+\synit{value}, \ldots \verb+)+ \synit{(optional)}
|
|
message|call|response \synit{name} \verb+(+\synit{argdecl}, \ldots \verb+)+;
|
|
\end{syntax}
|
|
|
|
The three identifiers \texttt{message}, \texttt{call}, and \texttt{response}
|
|
exist for legacy reasons, and are treated identically by the stub compiler.
|
|
They may be used as a simple form of documentation, when messages are intended
|
|
to travel in a particular direction between client and server.
|
|
|
|
The meta-parameters beginning with the context identifier are optional and may
|
|
be used by individual stub compilers for additional information about messages
|
|
that is not part of the payload. Multiple such contexts may also be provided.
|
|
|
|
Message arguments use a comma-separated C-like syntax, and may take one of the
|
|
following forms:
|
|
|
|
\begin{description}
|
|
\item[Simple arguments] are denoted by type name and argument name literals,
|
|
separated by whitespace.
|
|
\item[Dynamic array arguments] include the type name, argument name, and size
|
|
name literals, as follows:
|
|
\begin{syntax}
|
|
\synit{typename} \synit{argname}\verb+[+\synit{sizename}\verb+]+
|
|
\end{syntax}
|
|
\end{description}
|
|
|
|
For example, the following defines a message named ``dummy'' with three
|
|
arguments: an integer, a character string, and a dynamic array of unsigned 8-bit
|
|
integers (ie. a data buffer).
|
|
|
|
\begin{example}
|
|
message dummy(int32 arg, string s, uint8 buf[buflen]);
|
|
\end{example}
|
|
|
|
\subsection{RPC}\label{sec:lang:rpc}
|
|
|
|
\begin{syntax}
|
|
@\synit{context}\verb+(+\synit{name}\verb+=+\synit{value}, \ldots \verb+)+ \synit{(optional)}
|
|
rpc \synit{name} \verb+(+in|out \synit{argdecl}, \ldots \verb+)+;
|
|
\end{syntax}
|
|
|
|
An \texttt{rpc} declaration defines a pair of related one-way messages for the
|
|
RPC \emph{call} and its \emph{response}. Argument declarations take the same
|
|
syntax as for a simple message, but are prefixed with either \texttt{in} or
|
|
\texttt{out}. All \texttt{in} arguments are arguments of the call, and all
|
|
\texttt{out} arguments are arguments of the response.
|
|
|
|
For example, the following defines an RPC that takes as input a string
|
|
and returns an \texttt{errval} type (which must previously have been defined):
|
|
|
|
\begin{example}
|
|
rpc testrpc(in string s, out errval reterr);
|
|
\end{example}
|
|
|
|
With the exception of its special treatment by the RPC client backend
|
|
(described in Section~\ref{sec:rpcclient}), this RPC is exactly equivalent
|
|
to the following message specifications:
|
|
|
|
\begin{example}
|
|
message testrpc_call(string s);
|
|
message testrpc_response(errval reterr);
|
|
\end{example}
|
|
|
|
\section{Invocation}
|
|
|
|
When invoked, Flounder processes a single interface file, and generates into a
|
|
single output file the results of one or more \emph{backends}. The names of the
|
|
input and output files and the backends to use are determined by the
|
|
command-line arguments, which are as follows:
|
|
|
|
\begin{verbatim}
|
|
Usage: flounder [OPTION...] input.if output
|
|
-G --generic-header Create a generic header file
|
|
--generic-stub Create generic part of stub implemention
|
|
-a ARCH --arch=ARCH Architecture for stubs
|
|
-i FILE --import=FILE Include a given file before processing
|
|
--lmp-header Create a header file for LMP
|
|
--lmp-stub Create a stub file for LMP
|
|
--ump-header Create a header file for UMP
|
|
--ump-stub Create a stub file for UMP
|
|
--rck-header Create a header file for RCK
|
|
--rck-stub Create a stub file for RCK
|
|
--bmp-header Create a header file for BMP
|
|
--bmp-stub Create a stub file for BMP
|
|
--loopback-header Create a header file for loopback
|
|
--loopback-stub Create a stub file for loopback
|
|
--rpcclient-header Create a header file for RPC
|
|
--rpcclient-stub Create a stub file for RPC
|
|
--msgbuf-header Create a header file for message buffers
|
|
--msgbuf-stub Create a stub file for message buffers
|
|
-T --thc-header Create a THC header file
|
|
-B --thc-stubs Create a THC stubs C file
|
|
--ahci-header Create a header file for AHCI
|
|
--ahci-stub Create a stub file for AHCI
|
|
\end{verbatim}
|
|
|
|
Zero or more files may be specified as \emph{imports}. An import file
|
|
provides a simplistic mechanism for sharing type definitions among multiple
|
|
interfaces: it consists of one or more \texttt{alias} or \texttt{typedef}
|
|
statements. All import files are processed in the order in which they occur on
|
|
the command line, before parsing of the interface definition file begins.
|
|
Otherwise, types defined in import files are equivalent to types appearing in
|
|
an interface definition.
|
|
|
|
The architecture option must be specified when generating stubs for either LMP,
|
|
UMP, or RCK backends; when specified, it must be one of the architectures
|
|
Flounder understands (see \texttt{Arch.hs} in the flounder source), which is
|
|
typically the same as the set of architectures supported by Barrelfish.
|
|
|
|
All other options cause Flounder to emit the C code generated by one of its
|
|
backends. The \emph{generic} backend defines the common interface and support
|
|
code that is shared by all other backends, and is always required.
|
|
Chapter~\ref{cha:hake} describes the location and contents of the generated
|
|
files that are used in the Barrelfish build system.
|
|
|
|
\chapter{Flounder stub API}
|
|
|
|
Most Flounder backends generate message stubs for specific interconnect
|
|
drivers, with implementations varying widely according to the properties of
|
|
the interconnect driver. However, common to all interconnect drivers for a
|
|
given interface is the interface to the \emph{binding object}, which allows
|
|
the typed messages defined in the interface definition to be sent and received
|
|
in an event-driven programming style. The interface to the binding object for
|
|
a given interface is generated by the \texttt{--generic-header} option to
|
|
Flounder, and is documented here.
|
|
|
|
Most interaction with bindings involves interface-type-specific functions.
|
|
In the examples that follow, we assume that a Flounder interface
|
|
named \texttt{iface} is used, with the following specification:
|
|
|
|
\begin{example}
|
|
interface iface \{
|
|
message basic(uint32 arg);
|
|
message str(uint32 arg, string s);
|
|
message caps(uint32 arg, cap cap1, cap cap2);
|
|
message buf(uint8 buf[buflen]);
|
|
\};
|
|
\end{example}
|
|
|
|
|
|
\section{Binding process}\label{sec:binding_bindingproc}
|
|
|
|
In order to communicate, two dispatchers must establish a communication channel
|
|
using a common interconnect driver, and must acquire binding objects for each
|
|
endpoint of the channel. This process is known as \emph{binding}, and operates
|
|
in two modes:
|
|
|
|
\begin{enumerate}
|
|
\item A \emph{client} dispatcher initiates a binding to a service by calling
|
|
the interface's \emph{bind} function
|
|
\item A \emph{server} dispatcher accepts an incoming binding request from a
|
|
client, on a service which it has previously \emph{exported}
|
|
\end{enumerate}
|
|
|
|
In any binding attempt, one dispatcher must act as server and the other as
|
|
the client, however once a binding is established, the binding objects and the
|
|
process of communication on both sides of the binding are equivalent and
|
|
indistinguishable.
|
|
|
|
\subsection{Server-side: export}
|
|
|
|
In order to accept binding requests, a dispatcher must first export a service.
|
|
This is done by calling the \emph{export} function for the given interface:
|
|
|
|
\begin{lstlisting}
|
|
typedef void idc_export_callback_fn(void *st, errval_t err, iref_t iref);
|
|
typedef errval_t iface_connect_fn(void *st, struct iface_binding *binding);
|
|
|
|
errval_t iface_export(void *st, idc_export_callback_fn *export_cb,
|
|
iface_connect_fn *connect_cb, struct waitset *ws,
|
|
idc_export_flags_t flags);
|
|
\end{lstlisting}
|
|
|
|
The \lstinline+iface_export()+ function initiates the export of a new service.
|
|
It takes a state pointer, export callback, connection callback, waitset
|
|
pointer, and flags. If it returns success, the export has been successfully
|
|
initiated.
|
|
|
|
When the export either succeeds or fails, the export callback will be invoked.
|
|
It takes the state pointer (which was passed to \lstinline+iface_export()+), an
|
|
error code indicating success or failure of the export, and an \emph{interface
|
|
reference} (iref). The iref is only meaningful if the export succeeds; if this
|
|
is the case, it identifies the exported service in such a way that a client can
|
|
use the iref to initiate a binding to the service. In order for the service to
|
|
be usable, the iref must be communicated to the potential clients in some
|
|
manner; typically by registering it in the name service, which is described in
|
|
Chapter~\ref{cha:nameservice}.
|
|
|
|
Once a service has been exported, clients may attempt to bind to it. When this
|
|
occurs, the connection callback will be invoked. This function takes the state
|
|
pointer used at export time, and a pointer to the new partly-constructed binding
|
|
object. If it returns success, the binding request will be accepted, and the
|
|
binding process will complete. If it returns an error code indicating failure,
|
|
the binding attempt will be rejected, and the error code will be returned to
|
|
the client. When accepting a binding request, the connection callback also has
|
|
the task of filling in the vtable of receive handers, as described in
|
|
Section~\ref{sec:binding_rx}, and the error handler, described in
|
|
Section~\ref{sec:binding_errors}.
|
|
|
|
\subsection{Client-side: bind}
|
|
|
|
In order to initiate a binding, a client dispatcher calls the \emph{bind}
|
|
function for a given interface:
|
|
|
|
\begin{lstlisting}
|
|
typedef void iface_bind_continuation_fn(void *st, errval_t err,
|
|
struct iface_binding *binding);
|
|
|
|
errval_t iface_bind(iref_t i, iface_bind_continuation_fn *continuation,
|
|
void *st, struct waitset *waitset, idc_bind_flags_t flags);
|
|
\end{lstlisting}
|
|
|
|
This function takes the iref for the service (obtained, for example, by a name
|
|
service query), a bind continuation function, state pointer, waitset poitner,
|
|
and flags. If it returns success, a binding attempt has been initiated.
|
|
|
|
At some later time, when the binding either completes or fails, the bind
|
|
continuation function will be run. This takes the state pointer passed to
|
|
\lstinline+iface_bind()+, an error code indicating success or failure, and a
|
|
pointer to the newly-constructed binding, which is only valid if the error code
|
|
indicates success.
|
|
|
|
\section{Binding objects}\label{sec:binding_objs}
|
|
|
|
The end result of the binding process (either client-side or server-side) is a
|
|
binding object, which is the abstract interface to a specific interconnect
|
|
driver for a specific interface type. It is implemented in C as the
|
|
\lstinline+struct iface_binding+ type, the defined portion of which is shown
|
|
below, and described in the following sections:
|
|
|
|
\begin{lstlisting}
|
|
struct iface_binding {
|
|
/* Arbitrary user state pointer */
|
|
void *st;
|
|
|
|
/* Waitset used for receive handlers and send continuations */
|
|
struct waitset *waitset;
|
|
|
|
/* Mutex for the use of user code. */
|
|
/* Must be held before any operation where there is a possibility of
|
|
* concurrent access to the same binding (eg. multiple threads, or
|
|
* asynchronous event handlers that use the same binding object). */
|
|
struct event_mutex mutex;
|
|
|
|
/* returns true iff a message could currently be accepted by the binding */
|
|
iface_can_send_fn *can_send;
|
|
|
|
/* register an event for when a message is likely to be able to be sent */
|
|
iface_register_send_fn *register_send;
|
|
|
|
/* change the waitset used by a binding */
|
|
iface_change_waitset_fn *change_waitset;
|
|
|
|
/* perform control operations */
|
|
iface_control_fn *control;
|
|
|
|
/* error handler for any async errors associated with this binding */
|
|
/* must be filled-in by user */
|
|
iface_error_handler_fn *error_handler;
|
|
|
|
/* Incoming message handlers (filled in by user) */
|
|
struct iface_rx_vtbl rx_vtbl;
|
|
};
|
|
\end{lstlisting}
|
|
|
|
The \lstinline+st+ pointer is available for users to associate arbitrary local
|
|
state with each binding object. It is not used by the binding implementation.
|
|
|
|
The \lstinline+waitset+ pointer identifies the waitset used by the binding for
|
|
executing receive handler functions, send continuations, and internal logic. It
|
|
is read-only for users of the binding; to change the actual waitset, the
|
|
\lstinline+change_waitset()+ control function must be used.
|
|
|
|
Binding implementations are not thread-safe, and it is the responsibility of
|
|
user code to ensure that no concurrent access to the same binding occurs.
|
|
The \lstinline+mutex+ field is not used by the binding implementation, but is
|
|
provided for user code to ensure safety of concurrent accesses to the binding
|
|
object. It is used, for example, to arbitrate access to the shared monitor
|
|
binding, as described in Section~\ref{sec:monitor}.
|
|
|
|
The remaining fields are documented in the following sections.
|
|
|
|
|
|
\section{Receiving messages}\label{sec:binding_rx}
|
|
|
|
When a message arrives, the binding implementation calls the \emph{receive
|
|
handler} function located in the binding's \lstinline+rx_vtbl+ table of function
|
|
pointers. This table has an entry for each message type, with arguments
|
|
corresponding to those of the message, as shown below:
|
|
|
|
\begin{lstlisting}
|
|
/*
|
|
* Message type signatures (receive)
|
|
*/
|
|
typedef void iface_basic__rx_method_fn(struct iface_binding *_binding, uint32_t arg);
|
|
typedef void iface_str__rx_method_fn(struct iface_binding *_binding, uint32_t arg, char *s);
|
|
typedef void iface_caps__rx_method_fn(struct iface_binding *_binding, uint32_t arg,
|
|
struct capref cap1, struct capref cap2);
|
|
typedef void iface_buf__rx_method_fn(struct iface_binding *_binding, uint8_t *buf, size_t buflen);
|
|
|
|
/*
|
|
* VTable struct definition for the interface (receive)
|
|
*/
|
|
struct iface_rx_vtbl {
|
|
iface_basic__rx_method_fn *basic;
|
|
iface_str__rx_method_fn *str;
|
|
iface_caps__rx_method_fn *caps;
|
|
iface_buf__rx_method_fn *buf;
|
|
};
|
|
\end{lstlisting}
|
|
|
|
It is the responsibility of the user to fill in the \lstinline+rx_vtbl+ when
|
|
the binding is initialised, either in the connection callback on the
|
|
server side, or in the bind callback on the client side. This is typically
|
|
achieved by copying a static table of function pointers. It is a fatal error
|
|
if a message arrives on a binding and the handler function for that message
|
|
type is uninitialised or NULL.
|
|
|
|
Any message arguments passed by reference become the property of the user, and
|
|
must be freed by the appropriate memory management mechanisms:
|
|
|
|
\begin{itemize}
|
|
\item Strings and arrays live on the heap, and should be
|
|
released by a call to \lstinline+free()+
|
|
\item Capabilities refer to an occupied capability slot allocated from the
|
|
standard capability space allocator, and should be released by a call to
|
|
\lstinline+cap_destroy()+
|
|
\end{itemize}
|
|
|
|
|
|
\section{Sending messages}
|
|
|
|
A message may be sent on the binding by calling the appropriate transmit
|
|
function. For our example interface, these are as follows:
|
|
|
|
\begin{lstlisting}
|
|
errval_t iface_basic__tx(struct iface_binding *_binding, struct event_closure _continuation,
|
|
uint32_t arg);
|
|
errval_t iface_str__tx(struct iface_binding *_binding, struct event_closure _continuation,
|
|
uint32_t arg, const char *s);
|
|
errval_t iface_caps__tx(struct iface_binding *_binding, struct event_closure _continuation,
|
|
uint32_t arg, struct capref cap1, struct capref cap2);
|
|
errval_t iface_buf__tx(struct iface_binding *_binding, struct event_closure _continuation,
|
|
const uint8_t *buf, size_t buflen);
|
|
\end{lstlisting}
|
|
|
|
Each function takes as arguments the binding pointer and a
|
|
\emph{continuation} closure (described below), followed by the message payload.
|
|
If it returns success, the message has been successfully enqueued for
|
|
transmission, and will eventually be sent if no asynchronous errors occur.
|
|
|
|
The continuation is optional. When specified, it provides a generic closure
|
|
which will be executed after the given message has been successfully sent.
|
|
Two macros are provided to construct continuations: \lstinline+NOP_CONT+
|
|
provides a no-op continuation, to be used when this functionality is not
|
|
required, whereas \lstinline+MKCONT(func,arg)+ constructs a one-off continuation
|
|
given a function pointer and its argument.
|
|
|
|
All binding implementations can buffer exactly one outgoing message. If another
|
|
send function is called on the same binding while the buffer is full, the
|
|
\lstinline+FLOUNDER_ERR_TX_BUSY+ error will be returned, indicating that the
|
|
binding is not currently able to accept another message. In this case, the user
|
|
must arrange to retry the send at a later time, typically from a send
|
|
continuation function, or by using the \lstinline+register_send()+ control
|
|
function (described below).
|
|
|
|
Any message arguments passed by reference (strings, arrays, and capabilities)
|
|
are borrowed by the binding, and must remain live for as long as the message
|
|
is buffered but not yet completely sent. The send continuation may be used to
|
|
determine when it is safe to reclaim the memory used by reference parameters.
|
|
|
|
|
|
\section{Control functions}
|
|
|
|
Four standard control functions are defined for all binding implementations,
|
|
and are invoked through function pointers in the binding object:
|
|
\lstinline+can_send+, \lstinline+register_send+, \lstinline+change_waitset+
|
|
and \lstinline+control+.
|
|
|
|
\subsubsection*{can\_send}
|
|
|
|
\begin{lstlisting}
|
|
typedef bool iface_can_send_fn(struct iface_binding *binding);
|
|
\end{lstlisting}
|
|
|
|
This function returns true if and only if the binding could currently accept
|
|
an outgoing message for transmission. Note this does not indicate the message
|
|
could immediately be delivered to the underlying channel (further queuing
|
|
may be involved), simply that a send function would succeed.
|
|
|
|
\subsubsection*{register\_send}
|
|
|
|
\begin{lstlisting}
|
|
typedef errval_t iface_register_send_fn(struct iface_binding *binding,
|
|
struct waitset *ws, struct event_closure continuation);
|
|
\end{lstlisting}
|
|
|
|
This function arranges for the given continuation closure to be invoked on the
|
|
given waitset when the binding is able to accept another outgoing message
|
|
(i.e. when \lstinline+can_send+ would next return true).
|
|
It may fail if a continuation is already registered and has not yet executed;
|
|
only one continuation may be registered at a time.
|
|
|
|
\subsubsection*{change\_waitset}
|
|
|
|
\begin{lstlisting}
|
|
typedef errval_t iface_change_waitset_fn(struct iface_binding *binding, struct waitset *ws);
|
|
\end{lstlisting}
|
|
|
|
This function changes the waitset used by the binding for send continuations
|
|
and running its internal event handlers.
|
|
|
|
\subsubsection*{control}
|
|
|
|
\begin{lstlisting}
|
|
typedef errval_t iface_control_fn(struct iface_binding *binding, idc_control_t control);
|
|
\end{lstlisting}
|
|
|
|
This function provides a generic control mechanism. The currently-defined
|
|
control operations are:
|
|
|
|
\begin{description}
|
|
\item[\texttt{IDC\_CONTROL\_TEARDOWN}] Initiate connection teardown.
|
|
\item[\texttt{IDC\_CONTROL\_SET\_SYNC}] Enable synchronous optimisations.
|
|
See below.
|
|
\item[\texttt{IDC\_CONTROL\_CLEAR\_SYNC}] Disable synchronous optimisations.
|
|
Currently only implemented for the LMP interconnect driver, this operation
|
|
disables the (default) behaviour of yielding the CPU timeslice to the
|
|
receiver on every message send.
|
|
\end{description}
|
|
|
|
|
|
\section{Error handling}\label{sec:binding_errors}
|
|
|
|
The binding structure contains an \lstinline+error_handler+ function pointer
|
|
field, of the following type:
|
|
|
|
\begin{lstlisting}
|
|
typedef void iface_error_handler_fn(struct iface_binding *binding, errval_t err);
|
|
\end{lstlisting}
|
|
|
|
This function is called to report any asynchronous errors occuring on the
|
|
binding, including connection teardown, and should be filled-in by the user
|
|
during the binding process (i.e. whenever the \lstinline+rx_vtbl+ is installed).
|
|
The default implementation of the error handler for every binding simply
|
|
prints a message and terminates the current dispatcher.
|
|
|
|
|
|
\chapter{Runtime support}
|
|
|
|
This chapter describes the IDC runtime support that is part of
|
|
\texttt{libbarrelfish} which is used by the Flounder-generated stubs.
|
|
|
|
\section{Waitsets and event handling}
|
|
\label{sec:waitset}
|
|
|
|
At the core of the Barrelfish event handling mechanism lies the \emph{waitset},
|
|
represented by the \lstinline+struct waitset+ type in C. Informally, waitsets
|
|
facilitate the rendezvous of \emph{threads} with \emph{events}, where an event
|
|
is represented simply as a closure (function and argument pointers), as follows:
|
|
|
|
\begin{lstlisting}
|
|
struct event_closure {
|
|
void (*handler)(void *arg);
|
|
void *arg;
|
|
};
|
|
\end{lstlisting}
|
|
|
|
These events are typically raised by message channels in response to activity,
|
|
such as the ability to receive a message on a specific channel. In the
|
|
following we introduce the abstract properties of channels as they interact
|
|
with the waitset; the concrete channel interfaces are specific to each
|
|
interconnect driver and are described in the respective parts of
|
|
Chapter~\ref{cha:icds}.
|
|
|
|
All waitsets are local to a specific dispatcher, and may not be accessed from
|
|
other dispatchers. Although there is no limit to the number of waitsets used,
|
|
there always exists one \emph{default waitset} for each dispatcher, which
|
|
may be located by calling the following function:
|
|
|
|
\begin{lstlisting}
|
|
struct waitset *get_default_waitset(void);
|
|
\end{lstlisting}
|
|
|
|
|
|
\subsection{(Abstract) event channels}
|
|
|
|
All events managed by a waitset originate in \emph{channels},\footnote{The
|
|
term ``channel'' is now something of a misnomer in this context, as events are
|
|
no longer used exclusively for message channels.} represented internally by the
|
|
\lstinline+struct waitset_chanstate+ type. This struct is typically embedded
|
|
into the state of a real message channel or other event mechanism.
|
|
|
|
Channels are used to track the registration of handlers for and occurrence
|
|
of a single specific event. Multiple events (such as the ability to send a
|
|
message, as distinct from the ability to receive a message) are supported by
|
|
distinct channels -- an interconnect driver will typically use multiple event
|
|
channels in its implementation. Moreover, each event channel supports only one
|
|
registration -- registration of multiple event handlers on a single event may
|
|
be implemented above this mechanism.
|
|
|
|
Every channel exists in one of the following states:
|
|
|
|
\begin{description}
|
|
\item[Unregistered:] the channel is initialised, but no event handler has been
|
|
registered, and it is not associated with a waitset
|
|
\item[Idle:] an event handler closure has been registered with the
|
|
channel on a specific waitset, but the event has not yet occurred
|
|
\item[Polled:] this is similar to an idle channel, in that an event has been
|
|
registered and not yet occurred, but due to the nature of the
|
|
channel implementation, it must be periodically polled for
|
|
activity to detect the occurrence of the event
|
|
\item[Pending:] the event for which a handler was registered has occurred, and
|
|
the channel is now waiting to deliver the event
|
|
\end{description}
|
|
|
|
The following operations on channels are used by interconnect drivers to change
|
|
their state in the waitset:
|
|
|
|
\begin{description}
|
|
\item[Register:] Associates an event handler with a previously-unregistered
|
|
channel, and moves it to either the \emph{idle} or \emph{polled}
|
|
state
|
|
\item[Deregister:] Cancels the previously-registered event handler of a
|
|
channel, moving it from either \emph{idle}, \emph{polled} or
|
|
\emph{pending} state back to unregistered
|
|
\item[Trigger:] Signals occurrence of an event on a \emph{idle} or
|
|
\emph{polled} channel, and changes it to the \emph{pending} state
|
|
\end{description}
|
|
|
|
These operations are available only to interconnect drivers, using
|
|
the ``private'' API defined in \texttt{waitset\_chan.h}.
|
|
|
|
Once a channel is in the \emph{pending} state, if it is not deregistered it will
|
|
eventually be \emph{delivered} to a user of the waitset (calling
|
|
a function such as \lstinline+get_next_event()+ or \lstinline+event_dispatch()+)
|
|
unless it is deregistered beforehand. Once the event is delivered a channel
|
|
reverts to \emph{unregistered} state. Event registrations are therefore
|
|
single-shot; an event handler function that wishes to handle future events will
|
|
typically re-register itself.
|
|
|
|
|
|
\subsection{Waitset API}
|
|
|
|
\subsubsection{Waitset creation/destruction}
|
|
|
|
\begin{lstlisting}
|
|
void waitset_init(struct waitset *ws);
|
|
errval_t waitset_destroy(struct waitset *ws);
|
|
\end{lstlisting}
|
|
|
|
These functions initialise the state of a new waitset, or destroy the state
|
|
of an existing waitset.
|
|
|
|
\subsubsection{Event dispatch}
|
|
|
|
\begin{lstlisting}
|
|
errval_t get_next_event(struct waitset *ws, struct event_closure *retclosure);
|
|
\end{lstlisting}
|
|
|
|
This function is the core of the event handling mechanism. It returns the next
|
|
pending event on the given waitset, if necessary by blocking the calling
|
|
thread until an event is triggered.
|
|
|
|
\begin{lstlisting}
|
|
errval_t event_dispatch(struct waitset *ws);
|
|
\end{lstlisting}
|
|
|
|
This function is a wrapper for \lstinline+get_next_event()+ which also invokes
|
|
the event (by calling \lstinline+event.handler(event.arg)+) before returning.
|
|
It is typically used within an infinite loop on an event-handling thread.
|
|
|
|
|
|
\subsection{Implementation}
|
|
|
|
Internally, the waitset maintains a queue of waiting threads, and three queues
|
|
of channels: one each for channels in the \emph{idle}, \emph{pending} and
|
|
\emph{polled} state. The majority of the implementation consists of manipulating
|
|
these queues, and implementing the state transitions described in the previous
|
|
subsection.
|
|
|
|
The core logic of the waitset lies in the \lstinline+get_next_event()+
|
|
function, whose operation is as follows:
|
|
|
|
\begin{enumerate}
|
|
\item If there are any channels in the pending queue, remove the next channel
|
|
from the queue, mark it unregistered, and return its event closure.
|
|
\item Otherwise, if there are any channels in the polled queue, and no other
|
|
thread is already polling channels on this waitset, poll channels in the
|
|
polled queue long for as long as the pending queue remains empty. The
|
|
polling mechanism is presently used only by the UMP interconnect driver,
|
|
and is described in more detail in Section~\ref{sec:ump_icd}.
|
|
\item Otherwise, block on the queue of waiting threads. When unblocked
|
|
(either when a channel becomes pending or when needed to begin polling),
|
|
resume from step 1.
|
|
\end{enumerate}
|
|
|
|
\section{Interconnect drivers}
|
|
\label{sec:icds}
|
|
|
|
Interconnect drivers implement the runtime support needed by specific
|
|
message transport mechanisms. Chapter~\ref{cha:icds} describes the specifics
|
|
of each interconnect driver. Although there is no uniform interface to the
|
|
interconnect drivers, they typically support the following:
|
|
|
|
\begin{itemize}
|
|
\item Binding (connection setup), as described in Section~\ref{sec:binding}
|
|
\item A mechanism to \emph{send} a message on a channel
|
|
\item A mechanism to \emph{receive} messages from a channel
|
|
\item An interface to the waitset, allowing the user to \emph{register} for
|
|
event notifications when it is possible to send or receive on a channel
|
|
\item Various channel-specific control operations
|
|
\end{itemize}
|
|
|
|
In general, messages at this level of the system are word-granularity
|
|
fixed-size (or variable-size with an upper bound) untyped data.
|
|
|
|
The interconnect drivers that are available in a given domain are determined by
|
|
the compile-time configuration and processor architecture. The only driver
|
|
that is always present is local message passing (LMP), which provides
|
|
kernel-mediated communication with other dispatchers on the same core,
|
|
and is used to communicate with the local Monitor.
|
|
|
|
\section{Export and binding}
|
|
\label{sec:binding}
|
|
|
|
The export and binding process for all interconnect drivers is mediated by
|
|
the monitors. Section~\ref{sec:binding_bindingproc} documents the user-level
|
|
API provided by the binding objects, while here we describe what happens under
|
|
the covers.
|
|
|
|
The monitors are responsible for allocating interface references, or irefs,
|
|
tracking the association of irefs to the dispatcher implementing that service,
|
|
and mediating the bind process when a client wishes to bind to an iref.
|
|
In order to boot-strap this mechanism, every dispatcher is always created
|
|
with a binding to its local monitor, as described in Section~\ref{sec:monitor}.
|
|
|
|
\subsection{Export}
|
|
|
|
In order to export a new service, a dispatcher sends an
|
|
\lstinline+alloc_iref_request+ message to its local monitor, passing an opaque
|
|
service identifier (which is unique to the dispatcher). The monitor constructs
|
|
an iref, and returns it to the user along with the service identifier in an
|
|
\lstinline+alloc_iref_reply+ message.
|
|
|
|
\subsection{Binding}
|
|
|
|
In order to bind, a client dispatcher on a core presents the iref to its local
|
|
monitor, and requests to bind with a specific interconnect driver. Although
|
|
different interconnect drivers use different messages and parameters, the
|
|
process is very similar for all, so by way of example we present here
|
|
the binding mechanism for the UMP interconnect driver.
|
|
|
|
\begin{figure}
|
|
\includegraphics[width=\columnwidth]{figures/ump_bind}
|
|
\caption{UMP bind process}\label{fig:ump_bind}
|
|
\end{figure}
|
|
|
|
Figure~\ref{fig:ump_bind} shows the steps in setting up UMP binding:
|
|
\begin{enumerate}
|
|
\item The client sends \lstinline+bind_ump_client_request+ to its local monitor,
|
|
with the iref, the client's (opaque) connection ID, and various parameters
|
|
that are specific to the interconnect driver. For UMP, this includes a
|
|
capability to a shared frame, which will be used for message transfer.
|
|
\item The local monitor determines (from the iref) the core on which the
|
|
service resides, and forwards the request to the monitor on that core
|
|
using a \lstinline+bind_ump_request+ message (NB: mislabelled
|
|
\lstinline+remote_bind_request+ in the figure).
|
|
\item The monitor on the server's core determines the local dispatcher which
|
|
has exported this iref, and forwards the bind request to it using a
|
|
\lstinline+bind_ump_service_request+ message. It also provides the
|
|
opaque service identifier which the dispatcher gave when originally
|
|
exporting the service.
|
|
\item The server dispatcher uses the service identifier to locate and invoke
|
|
the connection callback for the given service. Assuming this succeeds, it
|
|
allocates its local state for the binding (e.g. the binding object). It
|
|
then replies to its local monitor with a
|
|
\lstinline+bind_ump_reply_monitor+ message (labelled
|
|
\lstinline+bind_service_reply+ in the figure).
|
|
\item The monitor proxies the reply back to the monitor on the client's core
|
|
\item The monitor on the client core proxies the reply back to the client,
|
|
providing the client's connection ID, which allows it to locate the
|
|
binding object and run the bind callback. The binding has now completed.
|
|
\end{enumerate}
|
|
|
|
The binding mechanisms for other interconnect drivers (e.g. LMP, BMP) are
|
|
similar, in that they involve an exchange of capabilities between client and
|
|
server mediated by the monitors. Once the binding is established, direct
|
|
communication can take place using the exchanged resources.
|
|
|
|
\section{Indirect capability transfer}
|
|
\label{sec:capxfer}
|
|
|
|
Because capabilities are maintained as references to per-core state in the
|
|
CPU drivers, only the LMP interconnect driver, which traverses kernel-mode
|
|
code, can directly deliver a capability along with untyped message payload.
|
|
For other interconnect drivers, such as UMP, capabilities travel out-of-band
|
|
from message payload through the monitors.
|
|
|
|
The process of indirect transmission of capabilities is as follows:
|
|
\begin{enumerate}
|
|
\item The binding object waits to acquire a mutex on its local monitor binding.
|
|
This is necessary, because it must send a message to its local monitor, and
|
|
the local monitor binding is shared by all bindings (and binding-related
|
|
code) executing on the same dispatcher. While waiting, it sends the
|
|
non-capability payload of the message as usual.
|
|
|
|
\item Upon receipt of the first message payload, the receiver sends back an
|
|
acknowledgement that it is ready to receive a capability. This handshake
|
|
is necessary to avoid over-running the receiver's buffers, and to ensure
|
|
that capabilities can be associated with the correct messages.
|
|
|
|
\item Once the monitor binding mutex is acquired, and the capability
|
|
acknowledgement has been seen, a \lstinline+cap_send_request+ message
|
|
is sent to the local monitor, containing the capability and an identifier
|
|
for the channel on which the capability is to be sent.
|
|
|
|
\item The monitor determines whether the cap may be sent to the remote core.
|
|
A full discussion of the rules used is beyond the scope of this document,
|
|
but in general capability types that refer to inherently local state (such
|
|
as LMP endpoints) may not be sent, nor may capabilities that are currently
|
|
being revoked. If the check fails, a \lstinline+cap_send_reply+ error is
|
|
sent back to the local dispatcher; if it succeeds, the capability is
|
|
serialised and proxied to the remote monitor as another
|
|
\lstinline+cap_send_request+ message on the inter-monitor channel.
|
|
|
|
\item The remote monitor reconstructs the capability from its serialised
|
|
representation, and forwards it on to the destination dispatcher with a
|
|
\lstinline+cap_receive_request+ message.
|
|
|
|
\item The receiver identifies the binding to which the capability belongs,
|
|
and invokes a callback on that binding. This in turn stores the capability
|
|
in the appropriate location.
|
|
|
|
\item When the last capability and message payload are received, the binding
|
|
object delivers the message to the user as usual.
|
|
\end{enumerate}
|
|
|
|
|
|
\chapter{Interconnect drivers}\label{cha:icds}
|
|
|
|
\section{LMP: local (intra-core) message passing}
|
|
\label{sec:lmp_icd}
|
|
|
|
IDC between dispatchers on the same core uses LMP (local message passing). LMP
|
|
uses endpoint capabilities for communication. In this case the channel struct
|
|
contains a reference to a remote endpoint cap (for the sender) and a local
|
|
endpoint cap (for the receiver). It also contains a reference to an endpoint
|
|
structure. This is a struct contained in the receiver's dispatcher and refers to
|
|
a buffer that is used to store incoming messages. The dispatcher can have
|
|
multiple such endpoint buffers.
|
|
|
|
\begin{figure}
|
|
\begin{center}
|
|
\includegraphics[width=0.5\columnwidth]{LMP.pdf}
|
|
\end{center}
|
|
\caption{Local Message Passing}
|
|
\label{fig:lmp}
|
|
\end{figure}
|
|
|
|
|
|
The sender's remote endpoint cap is derived from the receiver's dispatcher cap,
|
|
and contains a pointer back to the DCB and an offset into the associated
|
|
endpoint buffer.
|
|
|
|
When a message is sent, the sender invokes the remote endpoint cap with the
|
|
message to send. This causes the kernel to copy the message into the associated
|
|
endpoint buffer and then make the receiver dispatcher runnable (which will cause
|
|
it's \texttt{run()} upcall to be invoked when it is scheduled). The run function
|
|
then finds the endpoint with a message in it and invokes the trigger on the
|
|
appropriate waitset. The channel's event handler is responsible for getting the
|
|
rest of the message out of the buffer and invoking appropriate user-defined
|
|
handlers.
|
|
|
|
Sender: \texttt{lmp\_deliver\_payload (dispatch.c)}
|
|
|
|
Receiver: \texttt{disp\_run (dispatch.c)}
|
|
\texttt{lmp\_endpoints\_poll\_disabled (lmp\_endpoints.c)}
|
|
|
|
Event handler: \texttt{myappif\_lmp\_rx\_handler (myappif\_flounder\_bindings.c)}
|
|
|
|
\textbf{Binding:} The process of binding for LMP involves the sender creating
|
|
the endpoint capability and appropriate buffers, then invoking
|
|
\texttt{lmp\_bind\_request} on the monitor. The monitor sends the request to the
|
|
receiver, where it sets up its own endpoint cap and buffer and binding struct,
|
|
and returns the cap through the monitor to the sender.
|
|
|
|
\textbf{Passing capabilities - LMP:} When a capability is sent in a message, then
|
|
the kernel must additionally copy the cap to the receiver's cspace (a slot for
|
|
this is setup in the endpoint). The receive handler must ensure that it copies
|
|
the cap out of this cspace slot in order to free it for future transfers.
|
|
|
|
|
|
|
|
\subsection{Messaging with the local Monitor}
|
|
\label{sec:monitor}
|
|
|
|
|
|
\section{UMP: user-level message passing with coherent shared memory}
|
|
\label{sec:ump_icd}
|
|
|
|
IDC between dispatchers on different cores uses UMP (user-level message passing)
|
|
(on x86).
|
|
|
|
\begin{figure}
|
|
\begin{center}
|
|
\includegraphics[width=0.5\columnwidth]{UMP.pdf}
|
|
\end{center}
|
|
\caption{User-level Message Passing}
|
|
\label{fig:ump}
|
|
\end{figure}
|
|
|
|
UMP uses shared memory and polling and inter-processor interrupts for
|
|
communication. The shared memory is split into a send buffer and a receive
|
|
buffer (Figure~\ref{fig:ump}), with each entry in the buffers being the size of
|
|
a cache line. The sender writes into the send buffer, and the receiver reads
|
|
from it. The receiver polls to determine whether new messages have been
|
|
received.
|
|
|
|
The binding struct for a UMP channel contains UMP specific channel structs
|
|
(nested within various included structs) which contain a reference to the shared
|
|
memory, as well as a counter specifying the current read or write position.
|
|
|
|
In order to detect whether the write position has been reached when reading, the
|
|
channel also contains an epoch flag. Every buffer entry has an epoch bit that is
|
|
flipped every time a new entry is added. When reading a new entry the channels's
|
|
epoch is compared to the epoch bit of the buffer slot to be read. If it is the
|
|
same, then the entry is valid, if it is different then it is not valid. The
|
|
channel's epoch flag is flipped every time the counter wraps around.
|
|
|
|
The sender also has to know whether it is going to run up against the
|
|
receivers's read position. Rather than flip epoch bits on a read (in order to
|
|
avoid bouncing cache lines the buffer is kept write-only for the sender and
|
|
read-only for the receiver) each message has a sequence id. When replying to the
|
|
sender the receiver sends its latest read sequence id. The sender then knows how
|
|
many messages are outstanding and together with knowledge of the buffer size,
|
|
can avoid overwriting messages that haven't been read yet.
|
|
|
|
\textbf{Binding:} The UMP binding process involves the source creating the
|
|
channel buffers, then sending a cap to the buffer along with a bind request
|
|
through LMP to the monitor. The monitor serialises the cap and sends it through
|
|
to the destination monitor. The destination monitor recreates the cap, and sends
|
|
it on to the receiver. This sets up its channel struct accordingly and finalises
|
|
the binding.
|
|
|
|
\textbf{Passing capabilities - UMP:} UMP messages containing capabilities must
|
|
be sent in two phases. The non-cap message is sent as normal. The capability
|
|
must be sent through the monitor as only the monitor is able to invoke a syscall
|
|
to serialise and deserialise a capability. The sender sends the capability with
|
|
a request to the monitor, the monitor serialises it and sends it to the
|
|
destination monitor, where it is deserialised, and send through LMP to the
|
|
destination.
|
|
|
|
\section{RCK: message passing on the SCC}
|
|
\label{sec:rck_icd}
|
|
|
|
\section{BMP: Beehive message passing}
|
|
\label{sec:bmp_icd}
|
|
|
|
\chapter{Additional Flounder backends}
|
|
|
|
\section{Loopback}
|
|
|
|
\section{Message buffers}
|
|
|
|
\section{RPC Client}
|
|
\label{sec:rpcclient}
|
|
|
|
\section{THC}
|
|
\label{sec:thc}
|
|
|
|
\section{AHCI Command Translator}
|
|
\label{sec:ahci}
|
|
|
|
This backend is documented in the AHCI TN.
|
|
|
|
\chapter{Name service}
|
|
\label{cha:nameservice}
|
|
|
|
TODO
|
|
|
|
|
|
\chapter{Interaction with Hake build system}
|
|
\label{cha:hake}
|
|
|
|
TODO
|
|
|
|
\begin{itemize}
|
|
\item Configuration options
|
|
\item Contents of Hakefiles
|
|
\item Location/contents of generated files
|
|
\item Dependencies
|
|
\end{itemize}
|
|
|
|
|
|
\chapter{Unsupported features and future work}
|
|
|
|
TODO
|
|
|
|
\begin{itemize}
|
|
\item Connection/binding teardown
|
|
\item Variable-length arrays of types other than \lstinline+char+,
|
|
\lstinline+int8+ and \lstinline+uint8+
|
|
\item Types shared by multiple interfaces, control over C naming of generated
|
|
type definitions
|
|
\item Non-blocking variant of \lstinline+get_next_event()+
|
|
\item Fast LRPC optimisations (combines waitset, thread switch and send)
|
|
\end{itemize}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
\bibliographystyle{plain}
|
|
\bibliography{defs,barrelfish}
|
|
|
|
\end{document}
|