da79fa86de
* BUG: fix compilation on Windows/Cygwin. [GB.SIGNAL] * BUG: fix compilation on Windows/Cygwin. git-svn-id: svn://localhost/gambas/trunk@4564 867c0c6c-44f3-4631-809d-bfa615b0a4ec
327 lines
6.7 KiB
C
327 lines
6.7 KiB
C
/***************************************************************************
|
|
|
|
csignal.c
|
|
|
|
(c) 2000-2012 Benoît Minisini <gambas@users.sourceforge.net>
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2, or (at your option)
|
|
any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
MA 02110-1301, USA.
|
|
|
|
***************************************************************************/
|
|
|
|
#define __CSIGNAL_C
|
|
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include "main.h"
|
|
#include "csignal.h"
|
|
|
|
#ifndef SIGPOLL
|
|
#define SIGPOLL SIGIO
|
|
#endif
|
|
|
|
#ifndef SIGPWR
|
|
#define SIGPWR -1
|
|
#endif
|
|
|
|
#if !defined(OS_BSD) && !defined(OS_CYGWIN)
|
|
typedef
|
|
struct siginfo siginfo_t;
|
|
#endif
|
|
|
|
// The -1 signal is used for ignored signal numbers
|
|
|
|
/*#define DEBUG*/
|
|
|
|
#define SIGNAL_MAX 31
|
|
|
|
typedef
|
|
struct SIGNAL_HANDLER {
|
|
struct SIGNAL_HANDLER *next;
|
|
struct SIGNAL_HANDLER *prev;
|
|
int num;
|
|
bool catch;
|
|
struct sigaction action;
|
|
}
|
|
SIGNAL_HANDLER;
|
|
|
|
static int _signal = -1;
|
|
static SIGNAL_HANDLER *_handlers = NULL;
|
|
static bool _init_signal = FALSE;
|
|
static int _num_signal_watch = 0;
|
|
static int _pipe_signal[2];
|
|
static GB_FUNCTION _application_signal_func;
|
|
|
|
static void callback_signal(int fd, int type, void *data)
|
|
{
|
|
char num;
|
|
|
|
fprintf(stderr, "callback_signal\n");
|
|
if (read(fd, &num, 1) != 1)
|
|
return;
|
|
|
|
GB.Push(1, GB_T_INTEGER, num);
|
|
GB.Call(&_application_signal_func, 1, TRUE);
|
|
}
|
|
|
|
static void init_signal(void)
|
|
{
|
|
_num_signal_watch++;
|
|
if (_num_signal_watch > 1)
|
|
return;
|
|
|
|
if (GB.GetFunction(&_application_signal_func, (void *)GB.Application.StartupClass(), "Application_Signal", "i", ""))
|
|
{
|
|
GB.Error("No Application_Signal event handler defined in startup class");
|
|
return;
|
|
}
|
|
|
|
if (pipe(_pipe_signal) != 0)
|
|
{
|
|
GB.Error("Cannot create signal handler pipes");
|
|
return;
|
|
}
|
|
|
|
fcntl(_pipe_signal[0], F_SETFD, FD_CLOEXEC);
|
|
fcntl(_pipe_signal[1], F_SETFD, FD_CLOEXEC);
|
|
|
|
GB.Watch(_pipe_signal[0], GB_WATCH_READ, (void *)callback_signal, 0);
|
|
_init_signal = TRUE;
|
|
}
|
|
|
|
static void exit_signal(void)
|
|
{
|
|
if (_num_signal_watch <= 0)
|
|
return;
|
|
_num_signal_watch--;
|
|
if (_num_signal_watch)
|
|
return;
|
|
|
|
GB.Watch(_pipe_signal[0], GB_WATCH_NONE, NULL, 0);
|
|
close(_pipe_signal[0]);
|
|
close(_pipe_signal[1]);
|
|
|
|
_init_signal = FALSE;
|
|
}
|
|
|
|
static SIGNAL_HANDLER *find_handler(int num)
|
|
{
|
|
SIGNAL_HANDLER *sh;
|
|
|
|
sh = _handlers;
|
|
while (sh)
|
|
{
|
|
if (sh->num == num)
|
|
return sh;
|
|
sh = sh->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static void remove_handler(SIGNAL_HANDLER *handler)
|
|
{
|
|
if (handler->prev)
|
|
handler->prev->next = handler->next;
|
|
if (handler->next)
|
|
handler->next->prev = handler->prev;
|
|
if (handler == _handlers)
|
|
_handlers = handler->next;
|
|
|
|
if (handler->catch)
|
|
exit_signal();
|
|
|
|
GB.Free(POINTER(&handler));
|
|
}
|
|
|
|
static void add_handler(int num, struct sigaction *action)
|
|
{
|
|
SIGNAL_HANDLER *sh;
|
|
|
|
sh = find_handler(num);
|
|
if (sh)
|
|
{
|
|
sigaction(num, action, NULL);
|
|
return;
|
|
}
|
|
|
|
GB.Alloc(POINTER(&sh), sizeof(SIGNAL_HANDLER));
|
|
|
|
sh->num = num;
|
|
sh->next = _handlers;
|
|
sh->prev = NULL;
|
|
_handlers = sh;
|
|
|
|
sh->catch = (action->sa_flags & SA_SIGINFO) != 0;
|
|
if (sh->catch)
|
|
init_signal();
|
|
|
|
if (sigaction(num, action, &sh->action))
|
|
{
|
|
GB.Error("Unable to modify signal handler");
|
|
exit_signal();
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void handle_signal(int num, siginfo_t *info, void *context)
|
|
{
|
|
char cnum = (char)num;
|
|
if (write(_pipe_signal[1], &cnum, 1) != 1)
|
|
return;
|
|
}
|
|
|
|
BEGIN_METHOD_VOID(Signal_Reset)
|
|
|
|
SIGNAL_HANDLER *sh;
|
|
|
|
if (_signal < 0)
|
|
return;
|
|
|
|
sh = find_handler(_signal);
|
|
|
|
if (!sh)
|
|
return;
|
|
|
|
if (sigaction(_signal, &sh->action, NULL))
|
|
{
|
|
GB.Error("Unable to reset signal handler");
|
|
return;
|
|
}
|
|
|
|
remove_handler(sh);
|
|
|
|
END_METHOD
|
|
|
|
BEGIN_METHOD_VOID(Signal_Ignore)
|
|
|
|
struct sigaction action;
|
|
|
|
if (_signal < 0)
|
|
return;
|
|
|
|
action.sa_handler = SIG_IGN;
|
|
sigemptyset(&action.sa_mask);
|
|
action.sa_flags = 0;
|
|
|
|
add_handler(_signal, &action);
|
|
|
|
END_METHOD
|
|
|
|
BEGIN_METHOD_VOID(Signal_Catch)
|
|
|
|
struct sigaction action;
|
|
|
|
if (_signal < 0)
|
|
return;
|
|
|
|
action.sa_sigaction = handle_signal;
|
|
sigemptyset(&action.sa_mask);
|
|
action.sa_flags = SA_SIGINFO;
|
|
|
|
add_handler(_signal, &action);
|
|
|
|
END_METHOD
|
|
|
|
BEGIN_METHOD(Signal_get, GB_INTEGER num)
|
|
|
|
int num = VARG(num);
|
|
|
|
if (num < -1 || num > SIGNAL_MAX)
|
|
{
|
|
GB.Error("Bad signal number");
|
|
return;
|
|
}
|
|
|
|
_signal = num;
|
|
RETURN_SELF();
|
|
|
|
END_METHOD
|
|
|
|
BEGIN_METHOD_VOID(Signal_exit)
|
|
|
|
exit_signal();
|
|
|
|
while (_handlers)
|
|
remove_handler(_handlers);
|
|
|
|
END_METHOD
|
|
|
|
|
|
GB_DESC CSignalHandlerDesc[] =
|
|
{
|
|
GB_DECLARE(".SignalHandler", 0), GB_VIRTUAL_CLASS(),
|
|
|
|
GB_STATIC_METHOD("Reset", NULL, Signal_Reset, NULL),
|
|
GB_STATIC_METHOD("Ignore", NULL, Signal_Ignore, NULL),
|
|
GB_STATIC_METHOD("Catch", NULL, Signal_Catch, NULL),
|
|
|
|
GB_END_DECLARE
|
|
};
|
|
|
|
GB_DESC CSignalDesc[] =
|
|
{
|
|
GB_DECLARE("Signal", 0),
|
|
GB_VIRTUAL_CLASS(),
|
|
|
|
GB_CONSTANT("SIGHUP", "i", SIGHUP),
|
|
GB_CONSTANT("SIGINT", "i", SIGINT),
|
|
GB_CONSTANT("SIGQUIT", "i", SIGQUIT),
|
|
GB_CONSTANT("SIGILL", "i", SIGILL),
|
|
GB_CONSTANT("SIGTRAP", "i", SIGTRAP),
|
|
GB_CONSTANT("SIGABRT", "i", SIGABRT),
|
|
#ifndef OS_CYGWIN
|
|
// Cygwin doesn't define this SIGNAL
|
|
GB_CONSTANT("SIGIOT", "i", SIGIOT),
|
|
#endif
|
|
GB_CONSTANT("SIGBUS", "i", SIGBUS),
|
|
GB_CONSTANT("SIGFPE", "i", SIGFPE),
|
|
GB_CONSTANT("SIGKILL", "i", SIGKILL),
|
|
GB_CONSTANT("SIGUSR1", "i", SIGUSR1),
|
|
GB_CONSTANT("SIGSEGV", "i", SIGSEGV),
|
|
GB_CONSTANT("SIGUSR2", "i", SIGUSR2),
|
|
GB_CONSTANT("SIGPIPE", "i", SIGPIPE),
|
|
GB_CONSTANT("SIGALRM", "i", SIGALRM),
|
|
GB_CONSTANT("SIGTERM", "i", SIGTERM),
|
|
//GB_CONSTANT("SIGSTKFLT", "i", SIGSTKFLT),
|
|
//GB_CONSTANT("SIGCLD", "i", SIGCLD),
|
|
GB_CONSTANT("SIGCHLD", "i", SIGCHLD),
|
|
GB_CONSTANT("SIGCONT", "i", SIGCONT),
|
|
GB_CONSTANT("SIGSTOP", "i", SIGSTOP),
|
|
GB_CONSTANT("SIGTSTP", "i", SIGTSTP),
|
|
GB_CONSTANT("SIGTTIN", "i", SIGTTIN),
|
|
GB_CONSTANT("SIGTTOU", "i", SIGTTOU),
|
|
GB_CONSTANT("SIGURG", "i", SIGURG),
|
|
GB_CONSTANT("SIGXCPU", "i", SIGXCPU),
|
|
GB_CONSTANT("SIGXFSZ", "i", SIGXFSZ),
|
|
GB_CONSTANT("SIGVTALRM", "i", SIGVTALRM),
|
|
GB_CONSTANT("SIGPROF", "i", SIGPROF),
|
|
GB_CONSTANT("SIGWINCH", "i", SIGWINCH),
|
|
GB_CONSTANT("SIGPOLL", "i", SIGPOLL),
|
|
GB_CONSTANT("SIGIO", "i", SIGIO),
|
|
GB_CONSTANT("SIGPWR", "i", SIGPWR),
|
|
GB_CONSTANT("SIGSYS", "i", SIGSYS),
|
|
|
|
GB_STATIC_METHOD("_exit", NULL, Signal_exit, NULL),
|
|
|
|
GB_STATIC_METHOD("_get", ".SignalHandler", Signal_get, "(Signal)i"),
|
|
|
|
GB_END_DECLARE
|
|
};
|
|
|