\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.