raise or siggen function.
This type of user signal requires no special coding, only the use of these
two functions. The default action for a user signal raised in this manner
is always to ignore the signal. Refer to the descriptions of the raise and
siggen functions for more information.
If, however, you want to raise a signal as a result of a software interrupt (such as an end-of-subtask notification) or a hardware interrupt (such as an I/O interrupt), you can do so by coding two or more routines to intercept these interrupts and make them known to the library. The first of the required routines, called the initialization routine, defines the signal to the library. The other required routine, called the signal-generating routine, is an operating system exit that is invoked to raise the signal for the library when the interrupt occurs. Both of these routines are normally written in assembler language. Most of the other routines that define how to handle the signal can be written in either C or assembler language. Routines for Adding Signals indicates the recommended language for each routine and describes how to write the routines that add user signals to the library.
Note: This book assumes that you are adding a signal that communicates to your C program when a software or hardware interrupt occurs. You may have other uses for this facility that are not explicitly discussed in this book.
Some familiarity with MVS or CMS interrupt handling facilities is assumed. Also, thorough familiarity with SAS/C signal functions and signal-handling techniques is assumed. Refer to Chapter 5, "Signal-Handling Functions," in SAS/C Library Reference, Volume 1 for more information.
siginfo, sigprocmask, and sigsuspend, can be used
in your program to control handling of the new signals. In some cases, you
may want to define the new signal so that it does not permit the use of
longjmp or return in a handler. Refer to
Executive Routine
for more information.
Synchronous signals must be assigned one of the signal numbers defined by the symbols SIGUSR1 through SIGUSR8. Asynchronous signals must be assigned one of the signal numbers defined by the symbols SIGASY1 through SIGASY8. When you write the routine to define the signal, you can rename it to have a more useful and mnemonic name.
There are no special requirements for defining asynchronous signals.
Additional considerations may apply, however, when defining
asynchronous signals for programs that use pause,
sigpause, sigsuspend, or
sleep; refer to the description of the ECBPP field of ZENQARGS in
Routine for Asynchronous Signals: L$CZENQ .
The following list describes the requirements for defining a signal as synchronous.
=optimize and =minimal
options.
longjmp,
the program must be able to resume execution at some point other than the
point of interrupt. (It is possible, though not recommended, to use the
executive routine, described later in this chapter, to prevent
using longjmp successfully by the handler.)
Assembler routines called by the SAS/C Library rather than by the operating
system can use the CENTRY and CEXIT macros for function linkage. (Refer to
Chapter 11, "Communication with Assembler Programs," in SAS/C Compiler and Library User's Guide, Fourth Edition , for
information on the CENTRY and CEXIT macros.)
Assembler routines that call C
functions must use the CENTRY and CEXIT macros to run successfully when
either the optimized or minimal form of function linkage is in use. Refer
to Chapter 9 of SAS/C Compiler and Library User's Guide, Fourth Edition for more information on the =optimize and
=minimal options.
Note: A routine that calls operating system macros is usually written in assembler language.
Table 12.1 Routines for Adding Signals
Routine Required?/ Recommended Description
Frequency of Language*
use?
initialization yes/always assembler calls sigdef to define the
routine new signal and identify
which of the following
routines are coded.
signal yes/always assembler intercepts the hardware
or software interrupt and
informs the library that
the signal occurred. The
routine is usually an
operating system exit.
default no/common C establishes default
actions that occur when no
handler is defined for
the new signal.
interrupt no/ seldom assembler communicates to the
operating system when a
signal is ignored,
blocked, or handled in
the default manner.
final routine no/ very assembler cancels signal handling at
common the end of the program.
The routine is invoked
after all files are closed.
executive no/seldom C supervises linkage to
routine handlers. For example, the
routine can prevent use
of longjmp or normal returns.
jump no/rare assembler notifies the operating
intercept system that the interrupt
routine has been handled; that
is, it clears the interrupt.
*Note that all of these routines except the jump intercept routine can be coded in either C
or assembler.
This table simply indicates which language is preferred.
sigdef function to define the signal. The
initialization routine also calls an operating system macro to establish
the address of the operating system exit that should be invoked when the
signal occurs. For example, to define a CMS I/O interrupt signal called
SIGIOI, the
initialization routine may issue calls similar to the ones here.
The call to
sigdef in assembler might look like the following:
LA R1,DEFPARMS
L R15,=V(SIGDEF)
BALR R14,R15 sigdef(SIGASY1,0,0,0,0,"IOI");
DEFPARMS DC A(SIGASY1) symbol definition obtained by
* "COPY SIGNALS"
DC 4A(0)
DC A(SIGNAME)
SIGNAME DC C'IOI',X'00'
The call to sigdef renames SIGASY1 to SIGIOI but does not define any
special routines for processing the signal (indicated by the 0s for the
second DC in the DEFPARMS area).
A sample call to the CMS HNDINT macro to handle the interrupt might look like the following:
HNDINT SET,(TAP1,EXIT,unit,ASAP)The call to HNDINT identifies the I/O unit number that causes the interrupt (
unit) and the address of the operating system exit routine
(EXIT) that you code to generate the signal for the library.
You can also use the initialization routine to save the C Run-Time Anchor Block (CRAB) address so that it can be accessed by the signal generator routine. (One way to do this is to request that the operating system provide the address as a user parameter to an exit routine.) Saving the address of the CRAB is frequently necessary because register 12 is dedicated to the CRAB address only during C program execution; it is usually not preserved by the operating system when an exit routine is called.
Note:
It is possible to raise, handle, or block a user signal before it has been
defined by a call to sigdef. When sigdef is called, it has no
effect on the signal's status; that is, the signal remains blocked or
unblocked, and any user handler remains in effect. However, if the call to
sigdef defines a default handler, this default replaces the previous
default handler.

#include <lcsignal.h>
int sigdef(int signum, void (*dfl)(int),
int (*intcntl)(int, int, int, int),
void (*executive)(int, char **, _HANDLER),
void (*final)(int, char *name));
signum argument is the signal number. Specify the signal number
as one of the codes, SIGUSR1 through SIGUSR8 or SIGASY1 through SIGASY8.
Only one definition of each signal number is allowed.
Note:
In an OpenEdition MVS application, SIGUSR1 and SIGUSR2 may
be treated as OpenEdition signals rather than as SAS/C signals,
depending on the use of the oesigsetup function and the way the
program is run. Attempting to define a signal controlled by OpenEdition
MVS will cause sigdef to fail. Note that if oesigsetup
has not been called when sigdef is invoked, a default call to
oesigsetup will be generated, as described in the
oesigsetup
function description.
The name argument enables you to rename the signal. name
is the address of a null-terminated string with a maximum of five
characters. The library appends these five characters to the SIG
prefix to create the new name. For example, if the name argument
specifies EXT, the signal name appears in messages and traces as
SIGEXT.
The dfl, intcntl, executive, and final
arguments indicate the addresses of functions that provide special
processing for the signal. Each of these routines is described in
detail later in this appendix. Coding a 0 for any of these arguments
indicates that no function is supplied for that type of processing.
Note:
If you specify 0 for the dfl argument, the signal is ignored
when default handling is in effect.
sigdef returns 0 if it completes successfully or nonzero if it
cannot complete. Specifying an invalid signal number or one that has
already been defined is the most common reason for failure.
The signal generator routine raises the signal so that the library can detect it by calling the L$CZSYN routine (for synchronous signals) or the L$CZENQ routine (for asynchronous signals). These routines expect calls from assembler code and fully support them. The restrictions described in Restrictions on Synchronous and Asynchronous Signals apply when you can issue calls to L$CZSYN. There are no restrictions on when you can call L$CZENQ. These routines are described in more detail in SAS/C Library Routines for Adding New Signals .
The signal generator routine can build information that is passed to you
when the user-defined handler calls siginfo. Refer to the SIGINFO
field description in Routine for Synchronous Signals: L$CZSYN for more information.
sigdef. If you do not
define this routine, the default action is to ignore the signal. If you
prefer to have the program ABEND by default, code this routine to call the
abort function.
Note:
Refer to the siggen or abend
function to specify a particular
ABEND code.
sigdef. This routine is called on the
following occasions:
sigblock, sigsetmask, or
sigprocmask changes the mask for
the signal.
signal or sigaction
requests default or ignore handling, or
replaces default or ignore handling with a user-defined handler. If the
call to signal merely replaces one user-defined handler function
with another, the interrupt control routine may not be called.
signal
with a second argument of SIG_IGN, the interrupt control function can
cause the operating system to ignore the signal when it occurs instead
of calling an operating system exit. This saves the processing time required
to transfer control to the default handler and produces the same results.
The linkage to the interrupt control routine is defined as follows:
int intcntl(int signum, int ignore, int default, int block,
int context, struct sigaction *action)
The signum argument to the interrupt control routine specifies the
signal number. The ignore and default arguments indicate how
your program handles the signal. If ignore is 0, the program has
either defined a signal handler or default handling is in effect. If
ignore is not 0, the signal is ignored. If default is 0, the
program has either defined a signal handler or the signal is to be ignored. If
default is not 0, default handling is in effect. (Both ignore
and default are nonzero if default handling is in effect and the
default action is to ignore the signal.) The block argument is
nonzero if the signal is blocked or 0 if the signal is not blocked.
The context
argument is an integer indicating the reason that the
interrupt control routine was called. The possible values are
SC_ACTION, SC_PROCMASK, SC_DEF and
SC_COPROCSWT. (These are
symbolic values defined in <lcsignal.h>.) SC_ACTION
indicates a
call as the result of a user call to signal
or sigaction,
SC_PROCMASK indicates a call as the result of a user call to
sigblock, sigsetmask or sigprocmask,
SC_DEF indicates a call
as the result of the call to sigdef, and
SC_COPROCSWT indicates
a call as the result of a coprocess switch.
The action argument is meaningful only for calls with context
SC_ACTION or SC_DEF.
In these cases, action is a pointer to information
about the current handling as defined by sigaction. The
sa_handler
field of the action should be ignored, as it may be different from
the current handler. However, the sa_mask and
sa_flags fields are
guaranteed to be correct. In particular, this functionality allows
the interrupt control routine to take special action based on the
SA_USRFLAG n flags settings.
The interrupt control routine should return a negative number to
indicate an error. If a negative number
is returned, the call to signal or sigaction
that caused the
interrupt control routine to be called returns SIG_ERR.
A return code of 1,
when the context
is SC_BLOCK, indicates that the interrupt control routine
takes no
action for changes to blocking status. This enables the performance
of signal processing to be improved by avoid calls to the interrupt
control routine during
sigblock, sigsetmask, or sigprocmask processing.
Any other positive return code (or a 1 returned when the context is
not SC_PROCMASK) is treated as a success.
Note: An interrupt control routine is rarely required for correct operation of signal code; this routine simply provides improved performance for signals that can be ignored or blocked by the operating system. There may be times, however, when the interrupt control routine actually increases overhead. For example, signals are blocked while I/O is performed, so the interrupt control routine is called several times for each I/O operation.
raise or siggen; thus, the executive
routine is entered only when a signal occurs naturally.
The executive routine is usually coded in C. If you code this routine in
assembler language, use the CENTRY and CEXIT macros to avoid problems calling
the user-defined handler. The initialization routine specifies the address
of this routine as the fourth argument in the call to sigdef. The
linkage to the executive routine is defined as follows:
void executive(int signum, char **infop, void (*handler)(int))The
signum argument is the number of the defined signal. The
infop pointer addresses the pointer that the signal handler in the
program can access by a call to siginfo. The executive routine may
modify the information addressed by this pointer. The handler
argument addresses the user-defined handler or contains 0 if the signal is
to be ignored. This address can be used to call the user-defined handler
from the executive routine.
The executive routine can be used to monitor or prevent certain handler
activity. For instance, you can use blkjmp to prevent successful
use of longjmp by the handler, or you can refuse to allow normal
return from the handler by calling abort if the handler returns. It
is assumed that the executive routine will call the handler using the normal
handler linkage, but this cannot be enforced.
The final routine is usually coded in assembler language. The initialization
routine specifies the address of this routine as the fifth argument in the
call to sigdef. The linkage to the final routine is defined as follows:
void final(int signum)The
signum argument is the number of the signal whose handling will
be terminated.
The final routine is called after all files have been closed by the library. Therefore, this routine is not permitted to use I/O.
longjmp. This routine must be coded in assembler
language. The jump intercept routine can inform the operating system that
handling of the interrupt is complete but that control should not return to
the point of interrupt. This is sometimes called clearing the interrupt.
The jump intercept routine may need to be called before performing the
longjmp because the longjmp routine prevents return to the
signal generation routine from the handler and, therefore, also prevents
normal return to the operating system.
The jump intercept routine is rarely coded because it is frequently
impossible to correctly clear the interrupt. If you expect a user-defined
handler to call longjmp, you can disallow longjmp or define
the signal as asynchronous. The jump intercept routine should not attempt to
prevent a longjmp. If you want to disallow jumps, use the executive
routine to block them.
The jump intercept routine is not included as an argument in the call to
sigdef. To indicate that you want to provide this routine, set the
JUMPINT field of the ZSYNARGS DSECT to the address of the jump
intercept routine. The jump intercept routine is called using standard MVS
linkage. Register 1 addresses the save area where registers have been saved (except
for register 14 and register 15, which are not available).
ZSYNARGS DSECT
SIGNUM DS F signal number
SIGINFO DS A address of associated information
ABCODE DS A pointer to associated ABEND code (null-terminated),
if any
SIGNAME DS A pointer to five-character signal name
SIGLOC DS A pointer to the interrupted instruction
JUMPINT DS A address of a jump intercept routine, if needed
You must provide all of the information for these fields.
The fields are described as follows:
SIGNUM
SIGINFO
siginfo function. Refer to Chapter 5,
"Signal-Handling Functions," in
SAS/C Library Reference, Volume 1 for more information on siginfo.
The signal-generating routine builds this information and stores the address in this field. Then the address is passed to the executive routine for the signal, if any. The executive routine may want to modify or make a copy of this information. For example, you might pass L$CZSYN the address of a system control block. The executive routine can make a copy of it to pass to the user-defined handler. This stops the user from attempting to modify the control block.
ABCODE
'U'
if it is a user ABEND rather than a system ABEND.
For example, if you define a signal associated with exceeding a
CPU-time
quota, you probably would define ABCODE as "322"
because that is the ABEND
code normally produced by this condition.
SIGNAME
sigdef. These five characters are appended to SIG to form a new name
that replaces the standard name, SIGUSR1 - 8.
SIGLOC
where command is used. If you cannot provide this information, set
this field to NULL.
JUMPINT
longjmp, in
which case no return occurs. If L$CZSYN returns a 4, the signal
cannot be processed because one or more of the restrictions
on the timing of synchronous signals is violated. Refer to
Restrictions on Synchronous and Asynchronous Signals for more information. If L$CZSYN returns a 0,
the signal is accepted, and a user-defined signal handler is called
and returned. In either case, the signal generation routine should
return to the operating system.
The address of L$CZENQ is located at offset X'1F4' (decimal 500) from the start of the CRAB. Linkage to L$CZENQ should be effected using this CRAB field, not a V-type address constant. Using a V-type constant works only if the calling routine is linked with the main load module of the application program.
The following shows the use of various registers by L$CZENQ:
Register Use
1 addresses parameter list ZENQARGS 2 - 6 work registers; save contents before calling L$CZENQ 12 must address CRAB 13 ignored; no registers saved by L$CZENQ 14 contains return address 15 contains address of L$CZENQThe parameter list addressed by register 1 is described by the following DSECT:
ZENQARGS DSECT
SIGNUM DS F signal number
SIGINFO DS A address of associated information
ABCODE DS A pointer to associated ABEND code (null-terminated),
if any
SIGNAME DS A pointer to five-character signal name
SIGELEM DS A address of an interrupt element
ECBPP DS A address of a word in which to store an ECB address
The first four fields have the same meaning as the corresponding fields in L$CZSYN. The SIGELEM and ECBPP fields should be used as follows:
SIGELEM
ECBPP
pause, sigpause,
sigsuspend, or sleep at
the time of the call to L$CZENQ, the address of the
Event Control Block (ECG)
used by pause, sigpause,
sigsuspend, and sleep is
stored in the word addressed by ECBPP. If ECBPP is 0,
the ECB address is not stored; instead, the ECB is posted
using SVC 2. Therefore, if you call L$CZENQ in a
situation where SVC's cannot be issued (such as from an SRB
routine or I/O appendage), you must provide an ECBPP value.
Note that pause, sigpause, sigsuspend,
and sleep do
not complete until this ECB is posted. For this reason, in such cases
you would normally call a branch entry to POST to awaken the C program.
Copyright (c) 1998 SAS Institute Inc. Cary, NC, USA. All rights reserved.