SCO OpenServer
surf(D3oddi)
surf: SURFHOOK, SURF_ACTIVE, SURF_ENQUEUE --
SURF event logging monitor functions
Synopsis
cc -c -K -Zp4 -D_INKERNEL
#include <surfstream.h>
#include <surfd.h>
SURFHOOK(logging_routine(args_to_logging_routine));
surf_moduel_entry_t mcb;
if SURF_ACTIVE(mcb) {
load event-specific fields of event structure
SURF_ENQUEUE(mcb, event_record, sizeof(event_record));
}
Description
The SURF macros
are used for adding a monitoring module to the kernel.
Such a module can be added to a driver
or any other kernel component;
once the module is added,
surfd(SURF)
outputs information about those events.
You can view this information with
with an analysis routine you write
with the functions described on the
surfconnect(SURF)
and
surfevent(SURF)
manual pages.
A monitoring module is the glue between
an existing piece of kernel code,
type of event being studied,
and the reporting facility.
The code in a monitoring module is small
and trivial to write,
but it is shaped by the code being hooked
and the information to be reported.
To hook a piece of kernel code:
-
Declare an event record to be used
to log the events for the driver
or other kernel component.
This structure should be defined
in a separate header file
and have definitions that apply only to kernel space
protected by the preprocessor
#ifdef _INKERNEL directive
so that the record is accessible
to user-level programs that process
SURF data.
The structure must have the form:
typedef struct structname_s {
surf_header_t hdr;
other members
} structname_t
The header must be the first member declared.
Use surf_header_t
for structures
that are no larger than 256 bytes,
and surf_long_header
for structures
that are larger than 256 bytes.
Its member name must be ``hdr''.
All event structures should be defined as
#pragma pack(1).
The data of every event is copied at least three times:
once to enqueue it, once for the surfd daemon
to consume it and output it,
and once more, at least, in a device driver
or processing program.
Any gains due to aligned structure access
would be lost in extra bytes copied during transportation.
-
Define a SURF logging routine
to which the information is logged.
This routine calls the SURF_ACTIVE
and SURF_ENQUEUE macros.
This routine must allocate stack space for its event structure,
call a macro to load the header,
load the event-specific fields,
and calls the SURF_ENQUEUE macro
to enqueue the record.
-
Use SURFHOOK to
call the SURF logging routine
at the point in the code where the
event of interest occurs.
-
(Optional).
Code routines to be called when this module
is enabled, disabled, or at every clock interrupt.
-
Declare an extern instance that will be used
to populate the surf_modules table
in SURF's space.c file
with a pointer to the module's control block.
-
Use the functions documented on the
surfconnect(SURF)
and
surfevent(SURF)
manual pages to create a user-level program
that reads and reports the enqueued events.
Ideally, this program will be run
on a different system than the one being monitored
so it does not impact the data being enqueued.
Data structures
To add a monitoring module to the SURF system,
a pointer to the module's control block
needs to be added to the surf_modules table
in SURF's space.c file.
The control block itself is part of the individual module.
The table is an array of pointers
to structures of this type:
#define MAX_SURF_MODULE_NAME 16
typedef struct surf_module_entry {
char name[MAX_SURF_MODULE_NAME];
int id;
int enable;
int (*init)();
int (*deinit)();
int (*tick)();
} surf_module_entry_t;
The members are defined as:
name
-
String name of the monitoring module.
This identifier is used by the
user-level utilities to identify the monitoring module.
id
-
Module's ID.
The SURF driver will allocate an ID
for that module at driver init time
and load the
id
member with that value.
The SURF_ENQUEUE macro
uses this id
value
to populate the module_id
member
in the event header.
The initialization record outputs a mapping
of name
s to id
s.
enable
-
Flag that controls whether this module
should write records into the event queue.
If there are several monitoring packages in the kernel,
the user can specify which modules to enable.
The SURF_ACTIVE macro
checks the enable flag before writing
each event into the event queue.
init
-
Routine to be called when the module is enabled.
The init routine allows
a monitor module to initialize itself
and insert any startup information it wants
near the front of the event queue.
The init routine should not check
if the enable flag is set before enqueuing data;
the flag is not set until after the
init routine returns so that other events for this module
do not preceed any initialization events in the queue.
Set this to NULL
if the SURF module is not interested
in being informed when it is enabled.
deinit
-
Name of the routine to be called
whenever the module is disabled
or the queue is shut down.
The deinit routine should not check
whether the
enable
flag is set
before enqueing data;
the flag is cleared before any function is called
in an atempt to prevent other events for this module
from following any deinit events in the queue.
Set this to NULL
if the SURF module is not interested
in being informed when it is disabled.
tick
-
Name of the routine to be called
on every clock tick by the SURF driver's
poll routine.
This can be used by monitoring modules
that want to record some sort of event record periodically.
This can be used to record
a high-resolution histogram of some very active statistic,
such as number of
spl(D3oddi)
calls or TBL misses.
Set this to NULL
if the SURF module is not interested in
being informed of each clock tick.
Examples
As an example of how to implement a SURF
monitoring module,
this section shows how one might hook the
sio driver to measure
every time a character is output.
The steps are shown in the same order
as discussed above.
-
The event record logs character output events
in the sio driver:
typedef struct sio_putchar_event_s {
surf_header_t hdr;
char sio_type;
char databyte;
char portnumber;
} sio_putchar_event_t;
#define SIO_PUTCHAR_EVENT 1
The routine in this example records the character
being output in the databyte
routine,
the serial port number in portnumber
and SIO_PUTCHAR_EVENT in sio_type
.
The sio_type
field denotes
which type of sio event record this is.
This could be used to allow one monitoring module
to measure many events for this driver.
For example, in addition to monitoring
outgoing characters, this module could
define other sio_type
s that
monitor incoming characters and
the rise and fall of characters.
-
The logging routine is:
sio_surf_putchar(c,dev)
char c;
int dev;
{
sio_putchar_event_t se;
if (SURF_ACTIVE (sio_surf_module)) {
se.sio_type=SIO_PUTCHAR_EVENT;
se.databyte = c;
se.portnumber=dev;
SURF_ENQUEUE(sio_surf_module, se, sizeof(se))
}
}
-
To hook the driver,
the following line is inserted
into every location of code that is executed
when the event of interest occurs:
SURFHOOK(sio_surf_putchar(c, dev));
This macro call expands to:
if(surfsup)
sio_surf_putchar(c,dev);
surfsup is a global variable
that is only true when
the surfd daemon
has an event queue open.
This provides for the fastest possible execution speed
of a hooked subsystem
when it is not being measured.
-
The follwoing code in sio_surf_module
is used to populate the surf_modules table
in SURF's space.c file:
surf_module_entry_t {
"sio", 0, 0, &sio_init, NULL, NULL
} sio_surf_module
This sets the name
field to ``sio''.
The id
and enable
members
are always initialized to 0;
the surf driver
allocates an ID when
the driver's init routine executes,
and will set enable
when
the surfd daemon
is initialized.
The
sio_init( )
routine will be called when the module is initialized;
no routine is called when the module is disabled
or at each clock tick.
SURF will use this information
to add an entry to the space.c file,
which might look like this:
#include "sys/surf.h"
extern surf_module_entry_t surftimer_module;
extern surf_module_entry_t sio_surf_module:
surf_module_entry_t *surf_modules[] = {
&surftimer_module,
&surf_sio_surf_module
};
int num_surf_modules=sizeof(surf_modules)/sizeof(surf_module_entry_t*);
Hardware applicability
All
Version applicability
oddi:
3, 3mp, 4, 4mp, 5, 5mp, 6, 6mp
References
``ODDI driver interface version for SCO OpenServer 5'' in HDK Technical Reference
See also
surfconnect(SURF),
surfevent(SURF),
surfd(SURF)
Section SURF manual pages in Section SURF manual pages
``SURF kernel monitor'' in Developing SCO OpenServer 5 kernel drivers
19 June 2005
© 2005 The SCO Group, Inc. All rights reserved.
OpenServer 5 HDK - June 2005