signal: simple implementation (DONE)

This version of signal (which does not rely on a notion of userland
processes and is thus excluded from Vhex) follows C99 semantics but does
not generate any signals by default.

Basically, the signal function sets up function pointers and the signal
function calls them. Termination signals call exit() while other signals
call _Exit(), which is a quicker program termination similar to abort().

C99 allows programs to long jump out of signal handlers (!) which is
unbelievably scary because it would bypass stack switching code in Vhex
as well as normal interrupt handler termination in gint.
This commit is contained in:
Lephenixnoir 2021-05-29 18:26:33 +02:00
parent 04e910441a
commit cd7fe7a329
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
10 changed files with 127 additions and 20 deletions

View File

@ -106,6 +106,9 @@ set(SOURCES
# locale
src/libc/locale/setlocale.c
src/libc/locale/localeconv.c
# signal
src/libc/signal/signal.c
src/libc/signal/raise.c
# stdio
src/libc/stdio/vsnprintf.c
src/libc/stdio/sprintf.c
@ -121,6 +124,7 @@ set(SOURCES
src/libc/stdio/vdprintf.c
src/libc/stdio/printf.c
# stdlib
src/libc/stdlib/abort.c
src/libc/stdlib/abs.c
src/libc/stdlib/atof.c
src/libc/stdlib/atoi.c

11
STATUS
View File

@ -34,7 +34,7 @@ TEST: Function/symbol/macro needs to be tested
DONE: Function/symbol/macro is defined, builds, links, and is tested
7.2 <assert.h>
! 7.2.1 assert: LDEPS(fprintf,stderr,abort)
! 7.2.1 assert: LDEPS(fprintf,stderr)
7.3 <complex.h> => OpenLibm
@ -72,9 +72,10 @@ DONE: Function/symbol/macro is defined, builds, links, and is tested
7.13.2 longjmp: DONE
7.14 <signal.h>
! 7.14.1 Macros and stuff: TODO
! 7.14.1.1 signal: TODO
! 7.14.1.2 raise: TODO
7.14 sig_atomic_t SIG_DFL SIG_ERR SIG_IGN: DONE
7.14 SIGABRT SIGFPE SIGILL SIGINT SIGSEGV SIGTERM: DONE
7.14.1.1 signal: DONE
7.14.1.2 raise: DONE
7.15 <stdarg.h> => GCC
@ -102,7 +103,7 @@ DONE: Function/symbol/macro is defined, builds, links, and is tested
7.20.1.4 strtol, strtoul, strtoll, strtoull: DONE
! 7.20.2 Pseudo-random sequence generation functions: TODO
! 7.20.3 Memory management functions: TODO (check existing code first)
! 7.20.4.1 abort: BDEPS(raise)
7.20.4.1 abort: DONE
! 7.20.4.2 atexit: TODO
7.20.4.3 exit: DONE (missing stream flushing/closing/etc)
7.20.4.4 _Exit: DONE (gint only)

View File

@ -3,38 +3,49 @@
#include <stddef.h>
#include <stdint.h>
#include <stdatomic.h>
/* C99 API. */
typedef volatile atomic_int sig_atomic_t;
/* Type of a signal handler.*/
typedef void (*__sighandler_t)(int);
#include <bits/signum.h>
/* Set the handler for __signum. */
extern __sighandler_t signal(int __signum, __sighandler_t __handler);
/* Raise signal __signum. */
extern int raise(int __signum);
/* POSIX API (Vhex only). */
#ifdef _POSIX_C_SOURCE
/* Type of signal set */
typedef uint32_t sigset_t;
typedef uint32_t kernel_sigset_t;
/* Type of a signal handler.*/
typedef void (*__sighandler_t)(int);
typedef __sighandler_t sighandler_t;
/*
** Get the system-specific definitions of `struct sigaction' and the `SA_*'
** and `SIG_*'. constants.
*/
#include <bits/sigaction.h>
#include <sys/types.h>
/* Get and/or change the set of blocked signals. */
extern int sigprocmask (int how, const sigset_t *restrict set,
sigset_t *restrict oldset);
extern int sigprocmask (int __how, const sigset_t *restrict __set,
sigset_t *restrict __oldset);
/*
** Send signal SIG to process number PID. If PID is zero, send SIG to all
** processes in the current process's process group. If PID is < -1, send SIG to
** all processes in process group - PID.
*/
extern int kill(pid_t pid, int sig);
extern int kill(pid_t __pid, int __sig);
/*
** Set the handler for the signal SIG to HANDLER, returning the old handler, or
** SIG_ERR on error. By default `signal' has the BSD semantic.
*/
extern void (*signal(int signum, void (*handler)(int)))(int);
#endif /*_POSIX_C_SOURCE*/
#endif /*__SIGNAL_H__*/

View File

@ -30,6 +30,9 @@ extern void free(void *__ptr);
/* Communication with the environment. */
/* Abort execution; raises SIGABRT and leaves quickly with _Exit(). */
void abort(void);
/* Exit; calls handlers, flushes and closes streams and temporary files. */
void exit(int __status);

View File

@ -0,0 +1,20 @@
#ifndef __BITS_SIGNUM_H__
# define __BITS_SIGNUM_H__
// Define the number of signals
#define _NSIG 16
/* Fake signal functions. */
#define SIG_ERR ((__sighandler_t) -1) /* Error return. */
#define SIG_DFL ((__sighandler_t) 0) /* Default action. */
#define SIG_IGN ((__sighandler_t) 1) /* Ignore signal. */
/* ISO C99 signals. */
#define SIGINT 2 /* Interactive attention signal. */
#define SIGILL 4 /* Illegal instruction. */
#define SIGABRT 6 /* Abnormal termination. */
#define SIGFPE 8 /* Erroneous arithmetic operation. */
#define SIGSEGV 11 /* Invalid access to storage. */
#define SIGTERM 15 /* Termination request. */
#endif /*__BITS_SIGNUM_H__*/

View File

@ -2,7 +2,7 @@
# define __BITS_SIGNUM_H__
// Define the number of signals
#define NSIG 32
#define _NSIG 32
// Vhex kernel internal define used to indicate
// if the signal is implemented or not

35
src/libc/signal/raise.c Normal file
View File

@ -0,0 +1,35 @@
#include <signal.h>
#include <bits/signum.h>
#include <stdlib.h>
#include "signal_p.h"
#ifndef __SUPPORT_VHEX_KERNEL
int raise(int sig)
{
if(sig < 0 || sig >= _NSIG)
return 1;
/* TODO: libc/signal: support signal masks? */
__sighandler_t handler = signal(sig, SIG_DFL);
if(handler == SIG_DFL) {
/* Signals that terminate */
if(sig == SIGINT || sig == SIGTERM) {
exit(128 + sig);
}
/* Signals that abort */
if(sig == SIGILL || sig == SIGABRT || sig == SIGFPE ||
sig == SIGSEGV) {
_Exit(128 + sig);
}
}
else if(handler != SIG_IGN) {
(*handler)(sig);
}
signal(sig, handler);
return 0;
}
#endif /*! __SUPPORT_VHEX_KERNEL*/

19
src/libc/signal/signal.c Normal file
View File

@ -0,0 +1,19 @@
#include <signal.h>
#include <bits/signum.h>
#include "signal_p.h"
#ifndef __SUPPORT_VHEX_KERNEL
__sighandler_t __signal_handlers[_NSIG] = { 0 };
__sighandler_t signal(int signum, __sighandler_t handler)
{
if(signum < 0 || signum >= _NSIG)
return SIG_ERR;
__sighandler_t prev = __signal_handlers[signum];
__signal_handlers[signum] = handler;
return prev;
}
#endif /*! __SUPPORT_VHEX_KERNEL*/

View File

@ -0,0 +1,13 @@
#ifndef __SIGNAL_P_H__
# define __SIGNAL_P_H__
#ifdef __SUPPORT_VHEX_KERNEL
#include <bits/signum.h>
/* Handlers for all signals. */
extern __sighandler_t __signal_handlers[_NSIG];
#endif /*! __SUPPORT_VHEX_KERNEL*/
#endif /*__SIGNAL_P_H__*/

View File

@ -1,10 +1,11 @@
#include <stdlib.h>
#include <bits/stdlib.h>
#include <signal.h>
void abort(int rc)
void abort(void)
{
/* TODO: Close BFile handles (essential) */
raise(SIGABRT);
/* If the signal handler ever returns, leave on our own */
_Exit(EXIT_FAILURE);
}