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