%
% x-kernel v3.3
%
% Copyright (c) 1996,1993,1991,1990  Arizona Board of Regents
%

\section{Data-Trace Library}\label{datatrace}

In addition to the trace facilities that print information to standard
output, as described in the previous section, the {\xk} also provides
a facility for saving detailed trace information about protocol
execution to disk. This data can later be processed by various
protocol-specific analysis tools. We anticipate most protocols using
the trace facility described in the previous section, rather than
the facility given in this section.

This data tracing facility supports operations for creating and
managing circular trace buffers, writing trace entries to a buffer,
saving traces to a file, and appending ``postamble'' information to
trace files..

\subsection{Type Definitions}\label{datatrace_type_defs}

The data tracing facility defines three data structures: {\var dt} is
the main object associated with a trace (it manages the trace buffers
and output file); {\var dthdr} keeps track of the numbers and sizes of
trace buffers written to the output file; and {\var dtpost} manages the
postamble list (postamble buffers are written to the trace file after
the trace has completed).

\var
\begin{tabbing}
xxxx \= xxxxxx \= xxxxxxxxxxxx \= \kill
\>typedef struct dt\_object\_struct \{\\
\>\>char                      \>*buffer;\\
\>\>char                      \>*current;\\
\>\>char                      \>*last;\\
\>\>char                      \>*traceName;\\
\>\>int                       \>fileSize;\\
\>\>dthdr                     \>fileHdr;\\
\>\>dtpost                    \>*post;\\
\>\>int                       \>numPost;\\
\>\>dtCloseFunc               \>closeFunc;\\
\>\>void                      \>*closeArg;\\
\>\>struct dt\_object\_struct \>*next;\\
\>\} dt;\\
\\
\>typedef struct dt\_filehdr\_struct \{\\
\>\>int \>version;\\
\>\>int \>bufferSize;\\
\>\>int \>numberBuffers;\\
\>\>int \>lastBufferIdx;\\
\>\>int \>lastBufferSize;\\
\>\} dthdr;\\
\\
\>typedef struct dt\_postamble\_struct \{\\
\>\>char                         \>*buffer;\\
\>\>int                          \>size;\\
\>\>struct dt\_postamble\_struct \>*next;\\
\>\} dtpost;\\
\end{tabbing}
\rm

\subsection{Operations}\label{datatrace_ops}

\subsubsection{dtCreateTraceObj}\label{dtCreateTraceObj}
\index{dtCreateTraceObj}

Creates and initializes a trace object with name {\var traceName}.
The {\var traceName} and {\var instName} fields are also used to
create the name of the trace output file.  If {\var instName} is NULL,
the output file is ``{\var traceName}.dt''; otherwise, it is 
``{\var traceName\_instName.dt}'' (substituting the appropriate values 
for the variable names).

The {\var logsize} parameter specifies the size of the trace buffer in
bytes, and {\var fileSize} states the maximum length of the trace file
in terms of trace buffers (e.g., {\var logsize} = 10000 and {\var
fileSize} = 3 means a trace buffer of approximately 10KB and a maximum
trace file size of 30KB).
\medskip
 
{\var dt *dtCreateTraceObj(char *traceName, char *instName, int logsize, int fileSize)}

Note that both the trace buffer and trace file are circular.  When the
trace buffer is full, it will be flushed to disk; when the trace file
is full, the next trace buffer written will overwrite the first one in
the file.

A list of all trace objects created by any protocol is maintained by
the datatrace tool.  The newly created trace object is put at the end
of this list.

\subsubsection{dtTrace}\label{dtTrace}
\index{dtTrace}

The {\var dtTrace}$n$ macros take $n$ arguments in addition to a
pointer to a {\var dt} object.  The effect of all of them is to save
the trace variables given as arguments to the trace buffer, and
advance the buffer pointer.  When the trace buffer becomes full, it is
flushed to disk and the buffer pointer is reset to the start of the
trace buffer.
\medskip

{\var void dtTrace$n$(dt *dtobj, args,...)}

\subsubsection{dtTraceBuf}\label{dtTraceBuf}
\index{dtTraceBuf}

The {\var dtTraceBuf} macro can be used instead of {\var dtTrace}$n$.
It copies a single buffer, pointed to by {\var buf} and of length
{\var len}, to the trace buffer, and advances the buffer pointer.
When the trace buffer becomes full, it is flushed to disk and the
buffer pointer is reset to the start of the trace buffer.
\medskip

{\var dtTraceBuf(dt *dtobj, char *buf, int len)}

\subsubsection{dtFlushTraceObj}\label{dtFlushTraceObj}
\index{dtFlushTraceObj}

Flushes the data in the buffers to the data file.  Also flushes the
postamble data if {\var flush\_post} is non-zero.
\medskip

{\var void dtFlushTraceObj(dt *dtobj, int flush\_post)}

\subsubsection{dtRegisterCloseFunc}\label{dtRegisterCloseFunc}
\index{dtRegisterCloseFunc}

Associate {\var closefunc} with trace object {\var dtobj}.  Function
{\var closefunc} is invoked with argument {\var closearg} when 
{\var dtClose()} is called.
\medskip

{\var void dtRegisterCloseFunc(dt *dtobj, dtCloseFunc closefunc, void *closearg)}

\subsubsection{dtClose}\label{dtClose}
\index{dtClose}

This function first calls the function registered with {\var dtobj} by
{\var dtRegisterCloseFunc()}, if there is one.  It then removes the
trace object from the trace object list, flushes the trace buffer to
disk, and frees all storage associated with the object.
\medskip

{\var void dtClose(dt *dtobj)}

\subsubsection{dtCloseAll}\label{dtCloseAll}
\index{dtCloseAll}

Invokes {\var dtClose()} on all trace objects.  This function should
be called at the end of the program.
\medskip

{\var void dtCloseAll()}

\subsubsection{dtAppendPostAmble}\label{dtAppendPostAmble}
\index{dtAppendPostAmble}

Adds a buffer to the trace object {\var dtobj}, which is flushed to
the end of the file when {\var dtClose()} is called.  Assumes that the
buffer has been preallocated.  The buffer is placed at the end of the
postamble list.
\medskip

{\var XkReturn dtAppendPostAmble(dt *dtobj, char *buffer, int size)}

\subsubsection{dtInsertPostAmble}\label{dtInsertPostAmble}
\index{dtInsertPostAmble}

Adds a buffer to the trace object {\var dtobj}, which is flushed to
the end of the file when {\var dtClose()} is called.  Assumes that the
buffer has been preallocated.  The buffer is placed at the beginning
of the postamble list.
\medskip

{\var XkReturn dtInsertPostAmble(dt *dtobj, char *buffer, int size)}

\subsubsection{dtPostAmbleLocation}\label{dtPostAmbleLocation}
\index{dtPostAmbleLocation}

Returns the offset from the beginning of the file to the beginning of
the postamble information.
\medskip

{\var long dtPostAmbleLocation(dthdr *FileHdr)}

\subsubsection{dtGetTraceObj}\label{dtGetTraceObj}
\index{dtGetTraceObj}

Returns the trace object that was created with name {\var traceName}.
\medskip

{\var dt *dtGetTraceObj(char *traceName)}

\subsubsection{dtGetTopTraceObj}\label{dtGetTopTraceObj}
\index{dtGetTopTraceObj}

Returns the first trace objects in the list of trace objects.  
\medskip

{\var dt *dtGetTopTraceObj()}

\subsubsection{dtLoadXObjRomOpts}\label{dtLoadXObjRomOpts}
\index{dtLoadXObjRomOpts}

This routine would typically be called in a protocol's initialization
routine, if the protocol supports tracing.  See Section~\ref{dtUsage}
for more information.
\medskip

{\var void dtLoadXObjRomOpts(Protl prot)}

\subsection{Usage Rules}\label{dtUsage}

A romfile entry can be used to create a trace object for a protocol
that supports tracing.  The protocol's initialization routine should
include a call to {\var dtLoadXObjRomOpts()}; when this function is
invoked, the romfile is scanned looking for entries that bear the name
of that protocol and that have meaning to the datatrace facility.

A romfile entry to create a trace object for the IP protocol would
look like:

\begin{verbatim}
    ip   trace   name=ip_trace   logsize=10000   filesize=3;
\end{verbatim}

\noindent
The first argument in the romfile entry must be the protocol name, and
the second is ``{\tt trace}''.  The ``{\tt name}'' argument is
optional; if not specified, the trace object is given no name.  The
above romfile entry would result in a call to 
{\var dtCreateTraceObj()} with the specified parameters when the 
{\var dtLoadXObjRomOpts()} function was invoked.

