gambas-source-code/main/lib/signal/csignal.c
Benoît Minisini f0d3f2e8c3 'Signal[].Send()' is a new method for sending a signal.
[GB.SIGNAL]
* NEW: 'Signal[].Send()' is a new method for sending a signal. It's an alternative syntax to the 'Signal.Send()' method.
2022-06-20 01:37:54 +02:00

269 lines
5.7 KiB
C

/***************************************************************************
csignal.c
(c) 2000-2017 Benoît Minisini <g4mba5@gmail.com>
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
// The "-1" signal is used for ignoring signal numbers
#ifndef SIGPWR
#define SIGPWR -1
#endif
#ifdef OS_CYGWIN
#define SIGIOT -1
#endif
#define NUM_SIGNALS 32
enum {
SH_DEFAULT = 0,
SH_IGNORE = 1,
SH_CATCH = 2
};
typedef
struct SIGNAL_HANDLER {
GB_SIGNAL_CALLBACK *handler;
struct sigaction action;
char state;
}
SIGNAL_HANDLER;
static SIGNAL_HANDLER _signals[NUM_SIGNALS] = { { 0 } };
static int _signal = -1;
static GB_FUNCTION _application_signal_func;
static bool _init_signal = FALSE;
static void init_signal(void)
{
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;
}
_init_signal = TRUE;
}
static void catch_signal(int num, intptr_t data)
{
GB.Push(1, GB_T_INTEGER, num);
GB.Call(&_application_signal_func, 1, TRUE);
}
static void handle_signal(int num, char state)
{
struct sigaction action;
SIGNAL_HANDLER *sh;
if (num < 0)
return;
sh = &_signals[num];
if (sh->state == state)
return;
if (sh->state == SH_IGNORE)
{
if (sigaction(num, &sh->action, NULL))
{
GB.Error("Unable to reset signal handler");
return;
}
}
else if (sh->state == SH_CATCH)
{
if (sh->handler)
{
GB.Signal.Unregister(num, sh->handler);
sh->handler = NULL;
}
}
if (state == SH_IGNORE)
{
action.sa_handler = SIG_IGN;
sigemptyset(&action.sa_mask);
action.sa_flags = 0;
if (sigaction(num, &action, &sh->action))
{
GB.Error("Unable to modify signal handler");
return;
}
}
else if (state == SH_CATCH)
{
if (num == SIGKILL || num == SIGSTOP)
{
GB.Error("SIGKILL and SIGSTOP cannot be caught");
return;
}
if (!_init_signal)
init_signal();
sh->handler = GB.Signal.Register(num, catch_signal, 0);
}
sh->state = state;
}
static void exit_signal(void)
{
int i;
for (i = 0; i < NUM_SIGNALS; i++)
handle_signal(i, SH_DEFAULT);
}
BEGIN_METHOD_VOID(Signal_Reset)
handle_signal(_signal, SH_DEFAULT);
END_METHOD
BEGIN_METHOD_VOID(Signal_Ignore)
handle_signal(_signal, SH_IGNORE);
END_METHOD
BEGIN_METHOD_VOID(Signal_Catch)
handle_signal(_signal, SH_CATCH);
END_METHOD
BEGIN_METHOD(Signal_get, GB_INTEGER num)
int num = VARG(num);
if (num < -1 || num >= NUM_SIGNALS)
{
GB.Error("Bad signal number");
return;
}
_signal = num;
RETURN_SELF();
END_METHOD
BEGIN_METHOD_VOID(Signal_exit)
exit_signal();
END_METHOD
BEGIN_METHOD(Signal_Send, GB_INTEGER pid)
if (kill(VARG(pid), _signal))
GB.Error("Unable to send signal: &1", strerror(errno));
END_METHOD
BEGIN_METHOD(Signal_SendOld, GB_INTEGER pid; GB_INTEGER sig)
if (kill(VARG(pid), VARG(sig)))
GB.Error("Unable to send signal: &1", strerror(errno));
END_METHOD
GB_DESC CSignalHandlerDesc[] =
{
GB_DECLARE_VIRTUAL(".SignalHandler"),
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_STATIC_METHOD("Send", NULL, Signal_Send, "(Process)i"),
GB_END_DECLARE
};
GB_DESC CSignalDesc[] =
{
GB_DECLARE_STATIC("Signal"),
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),
GB_CONSTANT("SIGIOT", "i", SIGIOT),
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_STATIC_METHOD("Send", NULL, Signal_SendOld, "(Process)i(Signal)i"),
GB_END_DECLARE
};