159 lines
3.2 KiB
C
159 lines
3.2 KiB
C
|
#include <signal.h>
|
||
|
#include "alloc.h"
|
||
|
#include "config.h"
|
||
|
#include "fail.h"
|
||
|
#include "interp.h"
|
||
|
#include "memory.h"
|
||
|
#include "misc.h"
|
||
|
#include "mlvalues.h"
|
||
|
#include "roots.h"
|
||
|
#include "signals.h"
|
||
|
|
||
|
static Volatile int async_signal_mode = 0;
|
||
|
Volatile int pending_signal = 0;
|
||
|
value signal_handlers = 0;
|
||
|
|
||
|
static void execute_signal(signal_number)
|
||
|
int signal_number;
|
||
|
{
|
||
|
Assert (!async_signal_mode);
|
||
|
callback(Field(signal_handlers, signal_number), Val_int(signal_number));
|
||
|
}
|
||
|
|
||
|
void handle_signal(signal_number)
|
||
|
int signal_number;
|
||
|
{
|
||
|
#ifndef BSD_SIGNALS
|
||
|
signal(signal_number, handle_signal);
|
||
|
#endif
|
||
|
if (async_signal_mode){
|
||
|
leave_blocking_section ();
|
||
|
execute_signal(signal_number);
|
||
|
enter_blocking_section ();
|
||
|
}else{
|
||
|
pending_signal = signal_number;
|
||
|
something_to_do = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void enter_blocking_section()
|
||
|
{
|
||
|
int temp;
|
||
|
|
||
|
while (1){
|
||
|
Assert (!async_signal_mode);
|
||
|
/* If a signal arrives between the next two instructions,
|
||
|
it will be lost. */
|
||
|
temp = pending_signal; pending_signal = 0;
|
||
|
if (temp) execute_signal(temp);
|
||
|
async_signal_mode = 1;
|
||
|
if (!pending_signal) break;
|
||
|
async_signal_mode = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* This function may be called from outside a blocking section. */
|
||
|
void leave_blocking_section()
|
||
|
{
|
||
|
async_signal_mode = 0;
|
||
|
}
|
||
|
|
||
|
#ifndef SIGABRT
|
||
|
#define SIGABRT 0
|
||
|
#endif
|
||
|
#ifndef SIGALRM
|
||
|
#define SIGALRM 0
|
||
|
#endif
|
||
|
#ifndef SIGFPE
|
||
|
#define SIGFPE 0
|
||
|
#endif
|
||
|
#ifndef SIGHUP
|
||
|
#define SIGHUP 0
|
||
|
#endif
|
||
|
#ifndef SIGILL
|
||
|
#define SIGILL 0
|
||
|
#endif
|
||
|
#ifndef SIGINT
|
||
|
#define SIGINT 0
|
||
|
#endif
|
||
|
#ifndef SIGKILL
|
||
|
#define SIGKILL 0
|
||
|
#endif
|
||
|
#ifndef SIGPIPE
|
||
|
#define SIGPIPE 0
|
||
|
#endif
|
||
|
#ifndef SIGQUIT
|
||
|
#define SIGQUIT 0
|
||
|
#endif
|
||
|
#ifndef SIGSEGV
|
||
|
#define SIGSEGV 0
|
||
|
#endif
|
||
|
#ifndef SIGTERM
|
||
|
#define SIGTERM 0
|
||
|
#endif
|
||
|
#ifndef SIGUSR1
|
||
|
#define SIGUSR1 0
|
||
|
#endif
|
||
|
#ifndef SIGUSR2
|
||
|
#define SIGUSR2 0
|
||
|
#endif
|
||
|
#ifndef SIGCHLD
|
||
|
#define SIGCHLD 0
|
||
|
#endif
|
||
|
#ifndef SIGCONT
|
||
|
#define SIGCONT 0
|
||
|
#endif
|
||
|
#ifndef SIGSTOP
|
||
|
#define SIGSTOP 0
|
||
|
#endif
|
||
|
#ifndef SIGTSTP
|
||
|
#define SIGTSTP 0
|
||
|
#endif
|
||
|
#ifndef SIGTTIN
|
||
|
#define SIGTTIN 0
|
||
|
#endif
|
||
|
#ifndef SIGTTOU
|
||
|
#define SIGTTOU 0
|
||
|
#endif
|
||
|
|
||
|
static int posix_signals[] = {
|
||
|
SIGABRT, SIGALRM, SIGFPE, SIGHUP, SIGILL, SIGINT, SIGKILL, SIGPIPE,
|
||
|
SIGQUIT, SIGSEGV, SIGTERM, SIGUSR1, SIGUSR2, SIGCHLD, SIGCONT,
|
||
|
SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU
|
||
|
};
|
||
|
|
||
|
value install_signal_handler(signal_number, action) /* ML */
|
||
|
value signal_number, action;
|
||
|
{
|
||
|
int sig = Int_val(signal_number);
|
||
|
if (sig < 0) {
|
||
|
sig = posix_signals[-sig-1];
|
||
|
if (sig == 0) invalid_argument("Sys.signal: unavailable signal");
|
||
|
}
|
||
|
switch(Tag_val(action)) {
|
||
|
case 0: /* Signal_default */
|
||
|
signal(sig, SIG_DFL);
|
||
|
break;
|
||
|
case 1: /* Signal_ignore */
|
||
|
signal(sig, SIG_IGN);
|
||
|
break;
|
||
|
case 2: /* Signal_handle */
|
||
|
if (signal_handlers == 0) {
|
||
|
int i;
|
||
|
Push_roots(r, 1);
|
||
|
r[0] = action;
|
||
|
signal_handlers = alloc_tuple(32);
|
||
|
action = r[0];
|
||
|
Pop_roots();
|
||
|
for (i = 0; i < 32; i++) Field(signal_handlers, i) = Val_int(0);
|
||
|
register_global_root(&signal_handlers);
|
||
|
}
|
||
|
modify(&Field(signal_handlers, sig), Field(action, 0));
|
||
|
signal(sig, handle_signal);
|
||
|
break;
|
||
|
default:
|
||
|
Assert(0);
|
||
|
}
|
||
|
return Val_unit;
|
||
|
}
|