=========================================================================
M I C R O F O C U S C O B O L
V4.0.5
Running Under The DG/UX
Operating System Version 5.4R3.10
On The AViiON
=========================================================================
SIGNAL HANDLING
===============
This document should be considered as additional information for the
section "Mixing C and COBOL Programs" in the Chapter "Mixed Language
Programming" in the COBOL User Guide. It describes the Micro Focus
support for two routines, cobpostsighandler and cobremovesighandler,
that you can use to complement or override the signal handling used by
the run-time system.
TABLE OF CONTENTS
=================
OVERVIEW
OPERATION
Example
Writing signal handlers
Coping with more than one handler for the same signal
Converting signal handlers written for signal()
Coping with Third Party software that uses signals
signal() vs sigaction()
OVERVIEW
========
This chapter describes the calls you need to make if you want to use
signal handling in your application, especially if you are mixing COBOL
and C in your application.
The run-time system (RTS) sets up default signal handlers for all signals
whose OS default action would be to cause termination. These default
handlers make sure that the COBOL system is properly cleaned up before
terminating. Hence, any open files are closed (to prevent file
corruption), the terminal is reset to a sane state, user posted exit and
error procedures are executed, and so on.
The RTS also uses signal handling to provide various functionality. For
example, interrupt key detection, Animator Zoom interrupt key, Job
Control, ALT/CTRL detection, and so on.
This COBOL system provides two routines that you can use to complement or
override the signal handling used by the run-time system (RTS):
cobpostsighandler and cobremovesighandler.
These routines allow multiple handlers per signal and allow you to
prioritize use of these handlers. They should only be used from inside a
C program, not least of because, you will need to #include <signal.h> for
the signal values, which vary between platforms.
These routines should be used instead of the OS signal calls (signal(),
sigaction(), etc) which only provide the ability to post a single signal
handler for each call which often prevents more than one application
being able to work together reliably.
For example, if you used one of the OS signal calls to post a signal
handler before invoking a COBOL program, then your signal handler would
be overridden. Whereas, if you used one of the OS signal calls after
invoking a COBOL program, the default RTS handler, additional COBOL
functionality and user posted signal handlers would all be overridden,
causing unexpected results.
OPERATION
=========
These routines have the form:
sighandler = cobpostsighandler (signal, priority, handler) ;
where:
signal specifies the signal, as defined in the <signal.h>
include file.
Type: integer.
priority specifies the priority of <handler>. The range of
possible priority values is 1 to 254, with 254 being of
the highest priority. Values 127 and 129 - 139 are
reserved for use by Micro Focus. Also see below.
Type: integer.
handler is the name of your signal handler.
Type: This must be a C function returning an integer
value.
returning:
sighandler is a pointer that can be used to remove your signal
handler later. If this value is NULL, then you can not
post a signal handler for this signal. This could be due
to lack of memory or the signal being "disabled" by the
tunable signal_regime - Also see below.
Type: (void *) pointer.
cobremovesighandler (sighandler) ;
where:
sighandler is the pointer returned when posting your signal handler
using a previous cobpostsighandler call.
returning:
(Nothing) There is no return value from this call.
The cobpostsighandler() call adds your specified handler into the list of
handlers for the specified signal, at the specified priority. A pointer
is returned which should be used in any subsequent cobremovesighandler()
call. If the handler can not be posted for the signal for any reason,
then NULL is returned.
The cobremovesighandler() call removes a posted handler from the list of
handlers for the appropriate signal. The <sighandler> passed must be the
value returned from a previous cobpostsighandler() call.
You should be aware of the following when using the cobpostsighandler()
routine:
o The RTS also uses cobpostsighandler() to post all of its signal
handling.
o The default RTS signal handlers are posted with priority 127. Default
handlers are posted for all signals whose OS default action would
cause termination. The RTS default handlers either make sure that
the COBOL system has been cleaned up before terminating, or cause the
signal to be ignored.
These default signal handlers assume that the signals were generated
by the OS due to a serious error or that a signal has been
unexpectedly raised. Hence, they usually produce an RTS message,
such as 114 or 115.
o The RTS provides various functionality via the use of signal handlers.
These handlers are posted with a priority in the range of 129 to 139.
o Hence, you should post a signal handler with priority 128 if you want
it to override (or be processed before) the default RTS handler for
that signal. You should use a priority of 126 (or less) if you want
to make sure that your handler is processed after the default RTS
handler (if the default RTS handler does not exit).
o When a signal is received, the handler posted with the highest
priority, for that signal, is called. The signal handler should take
any appropriate action (eg. setting a flag to be acted upon later)
and then either return a value of 0 or non-zero.
If the signal handler returns 0, then no further signal handlers will
be processed.
If the signal handler returns a non-zero value, then the handler with
the next highest priority, for that signal, will be called. This
continues until all the handlers, for that signal, have been called
or until one of the handlers returns a value of 0.
o If two handlers are posted with the same priority, the last one
posted will be executed first.
o If the same handler is posted twice, and neither of them are removed
via cobremovesighandler(), then the handler will be executed twice
(assuming the handler, and all handlers executed in between, do not
return a value of 0).
o Once you have posted a handler, you do not need to re-post it. The
handler will be called each time that signal is received (assuming
that the first receipt of the signal does not cause termination). If
you only want your handler to be executed once, then you must remove
it, via cobremovesighandler(), in your signal handler.
o Whilst processing signal handlers, the signal will be blocked. This
prevents recursion if the same signal is received in rapid succession.
o A signal handler must return normally. That is, it should return a
value using the C syntax
return(num) ;
and should not use any other function that terminates a signal
handler function, such as longjmp(). Doing so will cause the signal
to remain blocked, preventing any further signal to be processed
successfully.
o Certain signals are generated by the operating system when a serious
error has occurred. Catching these signals could cause unexpected
and potentially dangerous results. You should not catch any of the
following signals:
SIGBUS
SIGSEGV
SIGEMT
SIGILL
SIGIOT / SIGABRT
SIGSYS
SIGFPE
SIGTRAP
o Preventing the RTS from processing certain signals could stop certain
RTS functionality working. If you catch any of these signals (with
a priority of 140 or more), then your signal handler should return a
non-zero value so that the RTS's handler is also executed. The
signals concerned include:
SIGCHLD
SIGPIPE
SIGUSR1
SIGUSR2
SIGVTALRM
SIGWINCH
SIGCONT
SIGTSTP
SIGTTIN
SIGTTOU
o The cobpostsighandler and cobremovesighandler functions are only
! available with Micro Focus COBOL for 32bit systems, which include
! all Micro Focus COBOL for UNIX systems.
o Micro Focus reserves the right to change their default signal
handlers or use extra signals in the future.
Example
=======
The following example illustrates how a handler for the SIGALRM signal
could be set up.
#include <stdio.h>
#include <signal.h>
int
mysigcatch(sig)
int sig;
{
cobprintf("Here is new signal handler\n");
return(0); /* Do not process any further handlers */
}
void
mysigexit(sighand)
void *sighand;
{
cobprintf("Cancelling handler\n");
cobremovesighandler(sighand); /* Remove the handler */
}
main(argc, argv)
int argc;
char *argv[];
{
void *sighandle;
extern void *cobpostsighandler();
sighandle = cobpostsighandler(SIGALRM, 128, mysigcatch);
cobfunc("cobolprog", argc, argv); /* call a cobol program
using cobfunc function */
alarm(1); /* raise the signal */
pause(); /* wait for the signal */
sleep(4);
mysigexit(sighandle);
cobexit(0); /* Cobexit - close down COBOL
run-time environment */
}
Writing signal handlers
=======================
A signal handler should do very little. A signal can be generated at any
time so the routine that was being executed could be in an "unsafe"
state (eg. in the middle of modifying global variables) and so trying to
execute it in your signal handler could cause problems. The routine
being executed could be a C system routine such as malloc().
There are a small subset of system C routines that are safe to call
from signal handlers. You should not try and call any other C system
routines, or any COBOL routines, from your signal handler. See your
system documentation for more information on the safe C system routines.
Coping with more than one handler for the same signal
-----------------------------------------------------
The cobpostsighandler() call provides the ability for two or more
handlers to be posted for the same signal. When that signal is generated
by the OS (eg. a SIGINT generated when the interrupt key is pressed),
then each handler can take appropriate action and then let other handlers
be executed (by returning a non-zero value). Alternatively, they can
decide to make the signal "ignored" by returning a value 0 to prevent
other handlers from being executed. However, so that your handler can
work with other handlers for the same signal, a handler of priority 140
(or more) should return non-zero to let other handlers have the
opportunity to also be notified. A handler of priority 128 can return 0
if you do not want the RTS default action to be executed (which may cause
termination).
When you raise a signal (eg. by using alarm() to raise a SIGALRM signal,
or when raising a signal to a different run-unit or application), then it
is probable that only your signal handler(s) wants to be called and other
posted signal handlers are not expecting the signal. Hence, in this
case, you should set a global resource before raising the signal and then
check that resource in your signal handler. If the resource is set
(as expected), then the signal was raised by you, so you can take the
appropriate action and return 0 to prevent other handlers from being
unexpectedly called. If the resource is unset, then someone else (or
something else, such as the OS) raised the signal and so you can take no
action and should let other handlers execute by returning a non-zero
value.
Examples of global resources are global variables (if in the same
run-unit), shared memory, pipes, files, and so on. Hence, in the above
example, we could have set a global variable before raising the alarm()
signal. We would then need to check the global variable in the signal
handler, mysigcatch. If it was set, we would carry out our action, reset
the variable and return 0. However, if the global variable had not been
set, then some other code is likely to have raised the signal. Hence, we
would have not wanted to carry out our action and would instead need to
return a non-zero value immediately. This allows the appropriate action
to be taken in some other handler.
Converting signal handlers written for signal()
-----------------------------------------------
If you have any signal handlers which are posted using an OS signal call,
such as signal() or sigaction(), then they should be changed to use
cobpostsighandler(). This is so that your handler and any default RTS
handler, additional COBOL functionality and user posted signal handlers
can all co-exist without one overriding the other, causing unexpected
results.
The cobpostsighandler() interface is very similar to the signal()
interface. The two parameters you pass to signal() are also passed to
cobpostsighandler(), plus a priority.
However, the following differences apply:
o The return value from signal() is the previous signal handler that
was posted for the signal. This is returned because signal() only
allows one handler per signal. The cobpostsighandler() routine
allows multiple handlers per signal.
The return value from cobpostsighandler() is either a pointer or
NULL. If non-NULL, the pointer returned can later be used to remove
the handler using cobremovesighandler(). If NULL, then the handler
could not be posted for the signal.
o The signal handler function needs to return an integer value, instead
of no value.
o A signal handler function, posted via OS signal calls, can be
terminated by functions such as longjmp() and siglongjmp(). These
routines can not be used to terminate a signal handler function
posted via cobpostsighandler(). Doing so would cause the signal to
remain blocked, preventing any further signal from being processed
successfully.
o A signal handler function, posted via signal(), needs to re-post
itself, using another signal() call, if it wants to catch any
subsequent signals. This is because the OS resets the signal to the
OS default handler before the signal handler function is called.
Once you have posted a handler, via cobpostsighandler(), it stays
posted, you do not need to re-post it. If you only want your handler
to be executed once, then you must remove it, via
cobremovesighandler().
Coping with Third Party software that uses signals
==================================================
If you are using any Third Party software that posts a signal handler
using an OS signal call, such as signal() or sigaction(), then unexpected
results may occur. For example, if the Third Party software posts its
handler before COBOL has been invoked, then when COBOL is invoked the
Third Parties handler may be overridden by an RTS/COBOL handler. If the
the Third Party subsequently raises a signal, then a 115 error may occur.
The Run-Time tunable 'signal_regime' can be used to overcome this. This
tunable will prevent handlers from being posted for the specified signal
if a signal handler is posted before the first COBOL invocation. For more
information on this tunable see the chapter "Run-Time Configuration",
in the COBOL System Reference.
If handlers are prevented from being posted for a signal, due to this
tunable, then cobpostsighandler() will return NULL. Hence, the default
RTS handlers and any additional COBOL functionality achieved using the
signal will not be available. It also means that you should check the
value returned from any cobpostsighandler() calls for NULL.
Use of the 'signal_regime' tunable is only recommended for use with
Third Party software. You should always use cobpostsighandler() in your
own code.
signal() vs sigaction()
=======================
On some platforms, the OS function sigaction() is available. It is more
robust than signal() when signals are being received in rapid succession
or when a machine is heavily loaded. The cobpostsighandler() call will
use sigaction() by default.
The cobpostsighandler() function can be forced to use signal() instead of
sigaction() if the signal_interface tunable is used. For more information
on this tunable see the chapter "Run-Time Configuration", in the COBOL
System Reference.
=========================================================================
Micro Focus is a registered trademark of Micro Focus Limited.
UNIX is a registered trademark of X/Open Company Ltd.
=========================================================================
@(#)Vrn/signals.1/4.0.00/06Sep95/nrV
Copyright (C) 1993-95 Micro Focus Limited