Table of Contents Previous Chapter Chapter 3: General Purpose Features

Chapter 3: General Purpose Features

1. Overview

This chapter describes two general purpose IOC features:

2. General Purpose Tasks

Callback Tasks

EPICS provides three general purpose IOC callback tasks. The only difference between the tasks is scheduling priority: Low, Medium, and High. The low priority task runs at a priority just higher than Channel Access, the medium at a priority about equal to the median of the periodic scan tasks, and the high at a priority higher than the event scan task. The callback tasks provide a service for any software component that needs a task under which to run. The callback tasks use the task watchdog (described below). They use a rather generous stack and can thus be used for invoking record processing. For example the I/O event scanner uses the general purpose callback tasks.

The following steps must be taken in order to use the general purpose callback tasks:

  1. Include callback definitions:
        #include <callback.h>
    
  2. Provide storage for a structure that is a private structure for the callback tasks:
        CALLBACK mycallback;
    
    It is permissible for this to be part of a larger structure, e.g.
        struct {
        ...
        CALLBACK mycallback;
        ...
        } ...
    
  3. Call routines (actually macros) to initialize fields in CALLBACK:
        callbackSetCallback(VOIDFUNCPTR, CALLBACK *)
    
    This defines the callers callback routine. The first argument is the address of a function returning VOID. The second argument is the address of the CALLBACK structure.
        callbackSetPriority(int, CALLBACK *)
    
    The first argument is the priority, which can have one of the values: priorityLow, priorityMedium, or priorityHigh. These values are defined in callback.h. The second argument is again the address of the CALLBACK structure.
        callbackSetUser(VOID *, CALLBACK *)
    
    This call is used to save a value that can be retrieved via a call to:
        callbackGetUser(VOID *,CALLBACK *)
    
  4. Whenever a callback request is desired just call:
        callbackRequest(CALLBACK *)
    
    This call can be made from interrupt level. The callback routine is passed a single argument, which is the same argument that was passed to callbackRequest, i.e., the address of the CALLBACK structure.
An example use of the callback tasks.

    #include <callback.h>
    static structure {
      char      begid[80];
      CALLBACK callback;
      char     endid[80];
    }myStruct;
    void myCallback(CALLBACK *pcallback)
    {
      struct myStruct *pmyStruct;
      callbackGetUser(pmyStruct,pcallback)
      printf("begid=%s endid=%s\n",&pmyStruct->begid[0],
&pmStruct->endid[0]); } example(char *pbegid, char*pendid) { strcpy(&myStruct.begid[0],pbegid); strcpy(&myStruct.endid[0],pendid); callbackSetCallback(myCallback,&myStruct.callback); callbackSetPriority(priorityLow,&myStruct.callback); callbackSetUser(&myStruct,&myStruct.callback); callbackRequest(&myStruct.callback); }
The example can be tested by issuing the following command to the vxWorks shell:

  example("begin","end")
This simple example shows how to use the callback tasks with your own structure that contains the CALLBACK structure at an arbitrary location. Note that things can be simplified if CALLBACK is located at the beginning of the structure.

Task Watchdog

EPICS provides an IOC task that is a watchdog for other tasks. Any task can make a request to be watched. The task watchdog runs periodically and checks each task in its task list. If any task is suspended, an error message is issued and, optionally, a callback task is invoked. The task watchdog provides the following features:

  1. Include module:
        #include <taskwd.h>
    
  2. Insert request:
        taskwdInsert (int tid, VOIDFUNCPTR callback, VOID *userarg);
    
    This is the request to include the task with the specified tid in the list of tasks to be watched. If callback is not NULL then if the task becomes suspended, the callback routine will be called with a single argument userarg.
  3. Remove request:
        taskwdRemove(int tid);
    
    This routine would typically be called from the callback routine invoked when the original task goes into the suspended state.
  4. Insert request to be notified in any task suspends:
        taskwdAnyInsert(void *userpvt,VOIDFUNCPTR callback,VOID *userarg);
    
    The callback routine will be called whenever any of the tasks being monitored by the task watchdog task suspends. userpvt must have a value unique to call to taskwdAnyInsert.
  5. Remove request for taskwdAnyInsert:
        taskwdAnyRemove(void *userpvt);
    
    userpvt is the value that was passed to taskwdAnyInsert.

3. Error Handling

Overview

The error handling facilities provided by the IOC include the following features:

Errors detected by an IOC can be divided into classes: Errors related to a particular client and errors not attributable to a particular client. An example of the first type of error is an illegal Channel Access request. For this type of error, a status value should be passed back to the client. An example of the second type of error is a device driver detecting a hardware error. This type of error should be reported to a system wide error handler.

Dividing errors into these two classes is complicated by a number of factors.

If used properly, the error handling facilities described in this chapter can process both types of errors.

Return Status Values

Whenever it makes sense, IOC routines return a long word status value encoded similar to the vxWorks error status encoding. The most significant short word indicates the subsystem module within which the error occurred. The low order short word is a subsystem status value. In order that status values do not conflict with the vxWorks error status values all subsystem numbers are greater than 500.

A file epics/share/epicsH/errMdef.h defines each subsystem number. For example the define for the database access routines is:

  #define M_dbAccess  (501 << 16)   /*Database Access Routines*/
Directory "epics/share/epicsH" contains an include library for every IOC subsystem that returns standard status values. The status values are encoded with lines of the following format:

  #define S_xxxxxxx value /*string value*/
For example:

  #define S_dbAccessBadDBR (M_dbAccess|3) /*Invalid Database Request*/
For example, when dbGetField detects a bad database request type, it executes the statement:

  return(S_dbAccessBadDBR);
The calling routine checks the return status as follows:

  status = dbGetField( ...);
  if(status) {/* Call was not successful */}

Interface to System Wide Error Handling System

Either errMessage or errPrintf can be used as an interface to the system wide error handling system. At the present time, they end up calling logMsg. Facilities have been added to EPICS to trap logMsg calls and direct them to a system wide log file. In the future, a more generalized system wide error handling system, which allows an error handling program to receive error messages from all or selected IOCs, can be provided.

errMessage

Routine errMessage (actually a macro that calls errPrintf) has the following format:

  void errMessage(
    long  status,
    char  *message);
Where status is defined as:

errMessage, via a call to errPrintf, prints the message, the status symbol and string values, and the name of the task which invoked errMessage. It also prints the name of the source file and the line number from which the call was issued.

The calling routine is expected to pass a descriptive message to this routine. Many subsystems provide routines built on top of errMessage which generate descriptive messages.

An IOC global variable errVerbose, defined as an external in errMdef.h, specifies verbose messages. If errVerbose is TRUE then errMessage should be called whenever an error is detected even if it is known that the error belongs to a specific client. If errVerbose is FALSE then errMessage should be called only for errors that are not caused by a specific client.

errPrintf

Routine errPrintf has the following format:

  void errPrintf(
    long  status,
    __FILE__,
    __LINE__,
    char  *fmtstring
    <arg1>,
    ...);
Where status is defined as:

FILE and LINE are defined as:

The remaining arguments are just like the arguments to the C printf routine. errVerbose determines if the filename and line number are shown.

 
Table of Contents Next Chapter