PSI sics-cvs-psi_pre-ansto
This commit is contained in:
355
doc/programmer/kernelguide.tex
Normal file
355
doc/programmer/kernelguide.tex
Normal file
@@ -0,0 +1,355 @@
|
||||
\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
|
||||
parameter to a the tasks own data structure. 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 where 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, split into single commands at the \\n
|
||||
and put into the connections command stack for execution. At this place
|
||||
there is also the check for the special interrupt string on command
|
||||
connections (see \ref{prot1}).
|
||||
|
||||
The SICS server accepts only interrupts on its UDP port. This will be checked
|
||||
for when handling data pending on the servers UDP port.
|
||||
|
||||
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. There is no standard Tcl mechanism for
|
||||
doing that. 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 {\huge 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 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{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
|
||||
IniIniCommand 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.
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user