SCO OpenServer


surf: SURFHOOK, SURF_ACTIVE, SURF_ENQUEUE -- SURF event logging monitor functions


cc -c -K -Zp4 -D_INKERNEL
   #include <surfstream.h>
   #include <surfd.h>


surf_moduel_entry_t mcb; if SURF_ACTIVE(mcb) { load event-specific fields of event structure SURF_ENQUEUE(mcb, event_record, sizeof(event_record)); }


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:

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

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

  3. Use SURFHOOK to call the SURF logging routine at the point in the code where the event of interest occurs.

  4. (Optional). Code routines to be called when this module is enabled, disabled, or at every clock interrupt.

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

  6. 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:

String name of the monitoring module. This identifier is used by the user-level utilities to identify the monitoring module.

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 names to ids.

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.

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.

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.

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.


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.

  1. 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_types that monitor incoming characters and the rise and fall of characters.

  2. The logging routine is:
       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)) } }

  3. 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:
    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.

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


Version applicability

oddi: 3, 3mp, 4, 4mp, 5, 5mp, 6, 6mp


``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