Files
sics/doc/programmer/kernelguide.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.