400 lines
20 KiB
TeX
400 lines
20 KiB
TeX
\chapter{Guide To SICS Kernel Facilities}
|
|
In this chapter the facilities of the SICS servers kernel will be examined
|
|
more closely. All the kernel modules and their function will be listed,
|
|
together with some explanatory information and an overview about the
|
|
application programmers interfaces (API) provided. This section should
|
|
answer the questions: What is available?, Where to find what?,
|
|
Why did they do that? Details of
|
|
the API's mentioned are given in the reference section.
|
|
|
|
|
|
The SICS servers kernel consists of the following objects and modules:
|
|
\begin{itemize}
|
|
\item The task manager , Files tasker.*.
|
|
\item The network reader, Files nread.*.
|
|
\item The network module, Files network.*.
|
|
\item The connection object, Files conman.*.
|
|
\item The SICS interpreter, Files SCinter.*.
|
|
\item The SICS macro facility, Files macro.*, script.*.
|
|
\item The device executor, Files devexec.*.
|
|
\item The environment monitor, Files emon.c.
|
|
\item The server himself, Files nserver.*
|
|
\item The serverlog, Files servlog.*.
|
|
\item A performance monitor, Files perfmon.*.
|
|
\item The object factory, Files ofac.*.
|
|
\item The options database, Files ifile.*.
|
|
\item The password database, Files passwd.*.
|
|
\item The main program, File SICSmain.c.
|
|
\end{itemize}
|
|
|
|
\section{The Task Manager}
|
|
The task manager implements cooperative multitasking in SICS. A task in the
|
|
SICS sense is defined by a function, the task function. It is of the type:
|
|
\begin{verbatim}
|
|
int TaskFunction(void *pData);
|
|
\end{verbatim}
|
|
When it is time for the task to execute this function is called, with a
|
|
pointer to the tasks own data structure as a parameter. This data
|
|
structure must have been defined by the user of this module. The task
|
|
function returns 1, if it shall continue to live, or 0 if it should be
|
|
deleted from the task list. These task functions are kept in a
|
|
list. The elements of this list are visited cyclically, when the
|
|
scheduler runs.
|
|
|
|
The API to this object consists of functions for creating a task manager,
|
|
adding tasks to the task list and to run the task list. Other functions
|
|
allow to put a task into a wait state. This means that the task will not
|
|
execute until another task has died (returned 0). Then the waiting task will
|
|
continue execution at the point where it has called the wait function.
|
|
For example, consider a task which wants to wait for say 10 seconds. This
|
|
tasks name shall be BedTask. It does so by starting a second task, called
|
|
ClockTask which checks if 10 seconds have passed and dies after this.
|
|
BedTask then waits for this task. This makes BedTask look like this:
|
|
\begin{verbatim}
|
|
int BedTask(void *pData)
|
|
{
|
|
/* Code block 1.
|
|
Fill in horrendously complex operations here.
|
|
*/
|
|
|
|
lID = TaskRegister(pTasker, ClockTask,....)
|
|
TaskWait(pTasker, lID, ....);
|
|
|
|
/* Code block 2.
|
|
More horrendous computations.
|
|
Will be executed after ClockTask died.
|
|
*/
|
|
|
|
/* Beds never die!!! */
|
|
return 1;
|
|
}
|
|
\end{verbatim}
|
|
and ClockTask:
|
|
\begin{verbatim}
|
|
int ClockTask(void *pData)
|
|
{
|
|
if(10 seconds are gone)
|
|
{
|
|
/* death is lurking */
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
/* continue running */
|
|
return 1;
|
|
}
|
|
}
|
|
\end{verbatim}
|
|
|
|
The task manager supports a primitive means of inter task communication as
|
|
well. Each registered task may not only have a task function associated with
|
|
it, but also a SignalFunction. When a task feels like it, it may advise the
|
|
task manager to send a signal and some data to all the other tasks. Signals
|
|
are identified by integer numbers. The SignalFunction of each task will then
|
|
be called. It has to check the signal and if it is of meaning to the task,
|
|
do something appropriate with it. SICS uses this facility to distribute
|
|
interrupts and broadcast messages to all tasks. Currently defined signal
|
|
IDs are defined in file event.h.
|
|
|
|
\section{The Network Reader and the Network Module}
|
|
The network module implements the mechanics of network connection. This
|
|
module is the one which needs heavy reworking if the network protocol for
|
|
SICS should be changed. For instance to Token--Ring or AppleTalk or
|
|
whatever.
|
|
The network reader implements the polling for network message in the SICS
|
|
server. It is organized as one of the SICS system tasks. Polling in a POSIX
|
|
environment is all about the select() system call. The select() system call
|
|
allows to enquire if an open TCP/IP socket has data pending to be read, can
|
|
be written to etc. For more details see the unix man pages for the select
|
|
system call. An earlier version of the SICS server had a list of connection
|
|
objects and each of them were checked for pending commands with a call to
|
|
select. This proved to be inefficient with the system spending two thirds
|
|
of its time in select. Then it was decided to make use of the fact that
|
|
select can check more then one socket in one call. This gave birth to the
|
|
network reader. Each network user in the SICS server can register his socket
|
|
with the network reader. When the network reader tasks executes, it checks
|
|
all registered sockets for pending data with one central select system call.
|
|
This scheme improved system performance by a factor of 900.
|
|
What happens when data is pending on a socket depends on the type of the
|
|
socket.
|
|
The network reader currently supports four types of sockets:
|
|
\begin{itemize}
|
|
\item Accept type sockets.
|
|
\item Normal client sockets.
|
|
\item UDP sockets.
|
|
\item User sockets.
|
|
\end{itemize}
|
|
|
|
The accept type of socket is the main server port to which clients try to
|
|
connect to. The network reader accepts the connection and tries to read a
|
|
username/password pair for a specified amount of time.
|
|
If the username/password is valid, the connection will be accepted,
|
|
else it will be broken again. The username/password pair will be verified
|
|
against the data in the password database. If a connection is accepted, a
|
|
new connection object is created, a new connection task is registered into
|
|
the system and the network reader registers a new client command port.
|
|
|
|
The normal client command ports are accepted connections from a client. The
|
|
SICS server expects commands to be sent from the clients. Thus any data
|
|
pending on such a socket will be read and split into single commands at
|
|
the newline character. Now the network reader checks if the command
|
|
represents an interrupt(see \ref{prot1}) and if so process the interrupt
|
|
immediately. If not then command is put into the connections command
|
|
stack for execution.
|
|
|
|
The SICS server accepts interrupts also on its UDP port. This will be checked
|
|
for when handling data pending on the servers UDP port. This feauture
|
|
is implemented but not well tested and not used in the moment.
|
|
|
|
User type sockets are a feature for dealing with extremely slow hardware
|
|
connections. Some hardware devices require a long time to answer requests.
|
|
For example the Dornier velocity selector. This would block the SICS server
|
|
or diminish its performance to unbearable levels. If situations like that
|
|
occur somewhere in SICS object code, the object may call a special wait
|
|
function which returns when data is pending on the socket. Thereby, other
|
|
clients requests would be served, as the task switcher would run.
|
|
This special wait facility is implemented in the network reader.
|
|
|
|
\section{The Connection Object}
|
|
The connection object holds the execution context of the current client
|
|
connection. Its data structure holds information about the network channel to
|
|
the client connection, the command stack which the network reader fills with
|
|
commands, a list of files where all I/O to and from this connection will be
|
|
logged, the user rights associated with this client connection, interrupts,
|
|
and flags which determine if the connection is currently executing in a
|
|
macro or is busy. Functions exist which allow to interact with this object.
|
|
Most of them will be discussed in section \ref{gow}. Associated with each
|
|
connection is a task and a task function. Whenever this task executes, it
|
|
will pop a command from the command stack and execute it in the
|
|
interpreter. More details about the usage of the connection object can be
|
|
found in the next chapter \ref{gow}.
|
|
|
|
\section{The SICS Interpreter and Macro Language}
|
|
In order to understand this section a knowledge of some aspects of the C
|
|
language interface to the Tcl interpreter helps. Interesting chapters include
|
|
the sections about defining new commands in Tcl and the Tcl unknown
|
|
mechanism. For more details see John Ousterhout's book.
|
|
|
|
In an earlier stage it was considered to use the Tcl interpreter as the SICS
|
|
interpreter. This idea was discarded for some reasons: One was the
|
|
difficulty of transporting the client execution context (i.e. the connection
|
|
object) through the Tcl interpreter. This reason has become invalid
|
|
now, with the advent of Tcl 8.+ which supports namespaces. The second
|
|
was security: the Tcl interpreter is very powerful and can be
|
|
abused. It was felt that the system had to be protected against such
|
|
problems. The third reasons was that the set of user commands should
|
|
not be cluttered with Tcl commands in order to prevent
|
|
confusion. Programming macros is anyway something which is done by
|
|
SICS managers or programmers. However, the SICS interpreter is still
|
|
modeled very much like the Tcl-interpreter. A Tcl interpreter is
|
|
still included in order to provide a full featured macro
|
|
language. The SICS interpreter and the Tcl macro interpreter are
|
|
still tightly coupled.
|
|
|
|
The SICS interpreter must forward commands to the SICS objects. For this the
|
|
interpreter needs some help from the objects themselves. Each SICS object
|
|
has to provide a wrapper function of the type:
|
|
\begin{verbatim}
|
|
int ObjectWrapper(SConnection *pCon, SicsInterp *pSics, void *pData,
|
|
int argc, char *argv[]);
|
|
\end{verbatim}
|
|
in order to be visible from the interpreter. The parameters to this function
|
|
are: a pointer to the client connection executing the command,
|
|
the interpreter in which the command
|
|
executes, a pointer to the objects data structure and an argc,
|
|
\verb+argv[]+ pair
|
|
like for an C language main program. This argc, \verb+argv[]+ pair contains the
|
|
arguments to the wrapper function. The wrapper function is responsible for
|
|
evaluating the arguments and do whatever is appropriate. It returns 0 on
|
|
failure and 1 on success. The SICS interpreter holds a list of such wrapper
|
|
functions. For each object the list holds:
|
|
\begin{itemize}
|
|
\item The name of the SICS object.
|
|
\item The address of the objects wrapper function.
|
|
\item The address of the objects data structure.
|
|
\item The address of a function which can remove the objects data structure
|
|
from memory cleanly. This is used when deleting an object/command from the
|
|
interpreter to clean up memory.
|
|
\end{itemize}
|
|
Command interpretation then involves the following steps:
|
|
\begin{enumerate}
|
|
\item The command is parsed into an argc, \verb+argv[]+ pair.
|
|
\item Using the first word of the command as a key, the list of objects is
|
|
searched for a match.
|
|
\item If a match is found, the objects wrapper function is invoked with the
|
|
appropriate parameters.
|
|
\item All the rest of command interpretation is done by the wrapper
|
|
function.
|
|
\end{enumerate}
|
|
The SICS interpreter interface offers functions which allow to add or remove
|
|
entries to and from the interpreters list of objects. Other functions allow
|
|
to find objects (and their data structures) in this list. And of course,
|
|
there is a function which executes a command in this interpreter.
|
|
|
|
|
|
The Tcl macro interpreter is invoked either through the FileEval command or
|
|
through commands made available through the Publish mechanism. Publish
|
|
is a SICS manager command which makes a Tcl command or procedure
|
|
visible in the SICS interpreter. Publish provides a special wrapper for a
|
|
Tcl command, which first checks the user rights of the client connection which
|
|
wants to execute the Tcl command. If the user rights are appropriate the
|
|
command is invoked in the Tcl--interpreter. The Tcl interpreter has access
|
|
to all normal SICS commands. This is implemented by using the Tcl
|
|
unknown mechanism. If Tcl cannot find a command it invokes a command named
|
|
unknown with the missing commands name as a parameter. Unknown is usually
|
|
implemented as a Tcl script, loaded at Tcl startup time. The unknown function
|
|
is then responsible for finding the missing command and execute it. The
|
|
usual Tcl mechanism tries to find the missing command in Tcl libraries and
|
|
as operating system commands. This mechanism has been modified for SICS such
|
|
that unknown tries to find missing commands in Tcl libraries or in the SICS
|
|
interpreter. This last bit is implemented as a special Tcl command
|
|
SISCUnknown defined in macro.c. In order to invoke SICS command a connection
|
|
object is needed. A suitable connection object is provided through a stack.
|
|
Before invoking the Tcl-interpreter, the connection object from which the
|
|
request has come is put at the bottom of a stack. The SICSUnknown routine
|
|
then uses the last element of the stack as the connection object for
|
|
invoking SICS. When control returns from the Tcl-interpreter, the connection
|
|
is popped from the stack.
|
|
|
|
%% Idea: simplify: use Tcl as interpreter, have a wrapper around SICS
|
|
%% objects which provide the SICS wrapper contexts. Add SICS commands to Tcl
|
|
%% in a special data structure:
|
|
%% struct TclSICS {
|
|
%% (*ObjectWrapper);
|
|
%% void *ObjectData;
|
|
%% (*KillObject)
|
|
%% };
|
|
%% The Tcl wrapper function gets the connection object from the stack and
|
|
%% invokes the SICS object function.
|
|
%% This does not solve the Tcl security issue, though.
|
|
%%
|
|
|
|
\section{The Device Executor}
|
|
The device executor is responsible for executing and monitoring requests to
|
|
the actual instrument hardware. In its current form the device executor can
|
|
do this for any variable which can be driven (motors, temperature, composite
|
|
variables) and counters (single counters, histogram memory). How this is
|
|
done is explained in some detail in the section about SICS interfaces (see
|
|
\ref{inter}) in the object writers guide. The interface to the device
|
|
executor includes functions for starting, pausing, continuing devices and
|
|
monitoring their status. Additionally there are some functions and SICS
|
|
commands which allow to enquire about the status of the executor. If
|
|
hardware is active, the device executor has a SICS system task running
|
|
which initiates monitoring of devices. The device executor is built around a
|
|
list of currently active hardware devices.
|
|
|
|
\section{The Environment Monitor}
|
|
For the SICS concept for handling sample environment devices see
|
|
\ref{evdev}.
|
|
|
|
\section{The Server}
|
|
The server module defines a server data structure. A pointer to this
|
|
data structure is the sole global variable in the SICS system. Its name is
|
|
{\bf pServ}. This data structure contains pointers to the most
|
|
important SICS components: the interpreter, the task switcher, the device
|
|
executor, the environment monitor and the network reader. This module also
|
|
contains the code for initializing, running and stopping the server.
|
|
|
|
|
|
\section{The Performance Monitor}
|
|
This facility provides the data for the ``Performance''
|
|
(see user documentation)
|
|
command. The Performance Monitor is a task which increments a counter each
|
|
time it is executed. After a predefined integration time (20 seconds) a new
|
|
value cycles/per second is calculated. This is the data retrievable by the
|
|
Performance command. This facility is not particularly necessary but proved
|
|
useful for judging the impact of various system conditions on server
|
|
performance. If at some stage performance needs to be boosted to the utmost
|
|
and it is no longer the hardware which makes things slow, the performance
|
|
monitor may well be removed from the system without harm.
|
|
|
|
\section{The Object Factory}
|
|
During SICS initialization the SICS interpreters command list needs to be
|
|
initialized. This is the task of the object factory. Its function
|
|
InitIniCommands initializes all fixed, general SICS commands and all object
|
|
creation commands. Then the server initialization file is processed from the
|
|
server initialization code. After this is done, the server initialization
|
|
code calls KillIniCommands which removes the now surplus object creation
|
|
commands from the SICS interpreter. If new commands get added to SICS the
|
|
object creation command or (for a permanent command) the object wrapper have
|
|
to be registered with these two functions.
|
|
|
|
\section{SICS Options}
|
|
Any system needs a way to configure itself. SICS uses options for internal
|
|
parameters which should or need not be visible from the SICS interpreter. An
|
|
option is a name value pair. For a definition of currently valid SICS
|
|
options and how to create them see the SICS manager documentation. In terms
|
|
of an interface this module allows to retrieve an option from the options
|
|
database.
|
|
|
|
\section{The Password Database}
|
|
The password database holds a triplet of username password and rights code
|
|
for each user. This information is currently initialized from the server
|
|
initialization file. This scheme is not very secure, as anybody with an
|
|
account on the DAQ computer may view the file and thus the list of valid
|
|
users. If this becomes a serious concern, this module has to be rewritten.
|
|
|
|
\section{The Server Main Function}
|
|
This does not do much, just initialize the server, run it, and stop it.
|
|
|
|
\section{Logging}
|
|
The SICS server offers multiple options for logging:
|
|
\begin{itemize}
|
|
\item There is a cyclical server log logging all traffic. This is
|
|
described below.
|
|
\item Per client connection log files can be configured. This is part
|
|
of the connection object interface.
|
|
\item A special module, the commandlog exists, which saves all traffic
|
|
issued on client connections with user or manager privilege. This is
|
|
the most useful log for finding problems. This facility can be
|
|
configured to create a log file per day. Or the user can demand to
|
|
have her very own log file.
|
|
\end{itemize}
|
|
|
|
|
|
\subsection{The ServerLog}
|
|
As part of the SICS kernel there exists a global server log file. This file
|
|
contains:
|
|
\begin{itemize}
|
|
\item All traffic on all client connections. Even messages suppressed by the
|
|
clients.
|
|
\item All internal error messages.
|
|
\item Notifications about important internal status changes.
|
|
\end{itemize}
|
|
This server log is meant as an aid in debugging the server. As the SICS
|
|
server may run for days, weeks and months uninterrupted this log file may
|
|
become very large. However, only the last thousand or so messages are really
|
|
of interest when tracking a problem. Therefore a scheme is implemented to
|
|
limit the disk space used by the server log. The server log writes
|
|
cyclically into a number of files. A count of the lines is kept which were
|
|
written to each file. Above a predefined count, a new file is started.
|
|
As an interface the server log provides a function which allows to write
|
|
a message to it. This can be used by any object in the system for
|
|
interesting messages. The number of files to cycle through and the length of
|
|
each file can be configured by defines at the top of servlog.c.
|
|
|
|
|
|
\section{Instrument Status Persistence}
|
|
Real programs do dump core (the SICS server is good, but is no
|
|
exception in this respect) and real computers fall over. In such cases
|
|
it would be useful if instrument configuration parameters such as
|
|
zero points , variable settings etc. are not lost. SICS achieves this
|
|
by writing a status file each time a parameter changes. This
|
|
status file is read back whenever the SICS server starts. The default
|
|
status file is configured in the instrument startup file as the SicsOption
|
|
statusfile. The user
|
|
can also request a status file to be written or recovered manually.
|
|
The status file is just a file with SICS commands which configure
|
|
relevant parameters. The actual writing of these commands is delegated
|
|
to each SICS object. Each SICS object which whishes to save data into
|
|
the status file has to implement a function which will
|
|
automatically be called when a status file is written. For details,
|
|
consult the chapter on SICS object implementation.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|