diff --git a/sys/include/libc.h b/sys/include/libc.h index 079c7eb..bb0756f 100644 --- a/sys/include/libc.h +++ b/sys/include/libc.h @@ -355,7 +355,7 @@ extern int32_t jehanne_strtol(const char*, char**, int); extern uint32_t jehanne_strtoul(const char*, char**, int); extern int64_t jehanne_strtoll(const char*, char**, int); extern uint64_t jehanne_strtoull(const char*, char**, int); -extern void jehanne_sysfatal(const char*, ...); +extern void jehanne_sysfatal(const char*, ...) __attribute__ ((noreturn)); extern void jehanne_syslog(int, const char*, const char*, ...); extern int32_t jehanne_time(int32_t*); extern int jehanne_tolower(int); diff --git a/sys/include/posix.h b/sys/include/posix.h index 98e6e64..7b7bb65 100644 --- a/sys/include/posix.h +++ b/sys/include/posix.h @@ -64,30 +64,62 @@ extern void POSIX_free(void *ptr); extern unsigned int POSIX_sleep(unsigned int seconds); extern int POSIX_pipe(int *errnop, int fildes[2]); -typedef enum PosixSignalDisposition -{ - SignalHandled = 0, /* the application handled the signal */ - TerminateTheProcess, - TerminateTheProcessAndCoreDump, - StopTheProcess, - ResumeTheProcess -} PosixSignalDisposition; - -/* Executes a PosixSignalDisposition for pid. - * - * MUST be called instead of POSIX_kill for unblockable signals. - */ -extern int POSIX_signal_execute(int sig, PosixSignalDisposition action, int pid); - /* Library initialization */ #define _ERRNO_H // skip the Posix part, we just need the enum #include +typedef enum PosixSignals +{ + PosixSIGABRT = 1, + PosixSIGALRM, + PosixSIGBUS, + PosixSIGCHLD, + PosixSIGCONT, + PosixSIGFPE, + PosixSIGHUP, + PosixSIGILL, + PosixSIGINT, + PosixSIGKILL, + PosixSIGPIPE, + PosixSIGQUIT, + PosixSIGSEGV, + PosixSIGSTOP, + PosixSIGTERM, + PosixSIGTSTP, + PosixSIGTTIN, + PosixSIGTTOU, + PosixSIGUSR1, + PosixSIGUSR2, + PosixSIGPOLL, + PosixSIGPROF, + PosixSIGSYS, + PosixSIGTRAP, + PosixSIGURG, + PosixSIGVTALRM, + PosixSIGXCPU, + PosixSIGXFSZ, + + /* Optional Signals */ + PosixSIGIOT, + PosixSIGEMT, + PosixSIGSTKFLT, + PosixSIGIO, + PosixSIGCLD, + PosixSIGPWR, + PosixSIGINFO, + PosixSIGLOST, + PosixSIGWINCH, + PosixSIGUNUSED, + + PosixNumberOfSignals +} PosixSignals; + /* Initialize libposix. Should call * * libposix_define_errno to set the value of each PosixError + * libposix_define_signal to set the value of each PosixSignal * libposix_translate_error to translate error strings to PosixError * libposix_set_signal_trampoline to dispatch signal received as notes * libposix_set_stat_reader @@ -181,10 +213,14 @@ extern int libposix_translate_exit_status(PosixExitStatusTranslator translator); /* Dispatch the signal to the registered handlers. */ -typedef PosixSignalDisposition (*PosixSignalTrampoline)(int signal); +typedef int (*PosixSignalTrampoline)(int signal); extern int libposix_set_signal_trampoline(PosixSignalTrampoline trampoline); +extern int libposix_define_signal(PosixSignals signal, int code); + +extern int libposix_define_realtime_signals(int sigrtmin, int sigrtmax); + /* Define of WCONTINUED, WNOHANG and WUNTRACED bit flags. * * Note that WCONTINUED and WUNTRACED are not yet supported by libposix diff --git a/sys/src/lib/posix/initlib.c b/sys/src/lib/posix/initlib.c index 74f769e..da40f33 100644 --- a/sys/src/lib/posix/initlib.c +++ b/sys/src/lib/posix/initlib.c @@ -37,9 +37,16 @@ void libposix_init(int argc, char *argv[], PosixInit init) { extern int main(int, char**); + extern unsigned char *__signals_to_code_map; + extern unsigned char *__code_to_signal_map; + extern int *__handling_external_signal; + WaitList *wait_list; int status; int error_codes[ERRNO_LAST-ERRNO_FIRST]; + unsigned char signals_to_code[256]; + unsigned char code_to_signal[256]; + int handling_signal; assert(__initialized == 0); @@ -51,6 +58,13 @@ libposix_init(int argc, char *argv[], PosixInit init) wait_list = nil; __libposix_wait_list = &wait_list; + /* initialize signal handling */ + memset(signals_to_code, 0, sizeof(signals_to_code)); + memset(code_to_signal, 0, sizeof(code_to_signal)); + handling_signal = 0; + __signals_to_code_map = signals_to_code; + __code_to_signal_map = code_to_signal; + __handling_external_signal = &handling_signal; if(!atnotify(__libposix_note_handler, 1)) sysfatal("libposix: atnotify"); diff --git a/sys/src/lib/posix/internal.h b/sys/src/lib/posix/internal.h index 19ca01d..20c1346 100644 --- a/sys/src/lib/posix/internal.h +++ b/sys/src/lib/posix/internal.h @@ -38,3 +38,6 @@ extern int __libposix_translate_errstr(uintptr_t caller); extern int __libposix_note_handler(void *ureg, char *note); extern void __libposix_free_wait_list(void); + + + diff --git a/sys/src/lib/posix/signals.c b/sys/src/lib/posix/signals.c index 3bfab8f..ab3ef09 100644 --- a/sys/src/lib/posix/signals.c +++ b/sys/src/lib/posix/signals.c @@ -22,8 +22,25 @@ #define __POSIX_SIGNAL_PREFIX_LEN (sizeof(__POSIX_SIGNAL_PREFIX)-1) +unsigned char *__signals_to_code_map; +unsigned char *__code_to_signal_map; +int *__handling_external_signal; + +static int __sigrtmin; +static int __sigrtmax; +static int __min_known_sig; +static int __max_known_sig; static PosixSignalTrampoline __libposix_signal_trampoline; +typedef enum PosixSignalDisposition +{ + SignalHandled = 0, /* the application handled the signal */ + TerminateTheProcess, + TerminateTheProcessAndCoreDump, + StopTheProcess, + ResumeTheProcess +} PosixSignalDisposition; + static int note_all_writable_processes(int *errnop, char *note) { @@ -32,52 +49,6 @@ note_all_writable_processes(int *errnop, char *note) return -1; } -int -POSIX_kill(int *errnop, int pid, int sig) -{ - char msg[64], file[128]; - int mode; - int ret; - - snprint(msg, sizeof(msg), __POSIX_SIGNAL_PREFIX "%d", sig); - switch(pid){ - case 0: - mode = PNGROUP; - break; - case -1: - return note_all_writable_processes(errnop, msg); - default: - if(pid < 0){ - mode = PNGROUP; - pid = -pid; - } else { - mode = PNPROC; - } - } - - snprint(file, sizeof(file), "/proc/%d/note", pid); - if(access(file, AWRITE) != 0){ - if(access(file, AEXIST) == 0) - *errnop = __libposix_get_errno(PosixEPERM); - else - *errnop = __libposix_get_errno(PosixESRCH); - return -1; - } - ret = postnote(mode, pid, msg); - if(ret != 0){ - *errnop = __libposix_translate_errstr((uintptr_t)POSIX_kill); - return -1; - } - return 0; -} - -static int -translate_jehanne_note(char *note) -{ - // TODO: implement - return 0; -} - static void terminated_by_signal(int sig) { @@ -115,8 +86,12 @@ ErrorBeforeOpen: return 0; } -int -POSIX_signal_execute(int sig, PosixSignalDisposition action, int pid) +/* Executes a PosixSignalDisposition for pid. + * + * MUST be called by POSIX_kill for unblockable signals. + */ +static int +execute_disposition(int sig, PosixSignalDisposition action, int pid) { switch(action){ case SignalHandled: @@ -137,16 +112,203 @@ POSIX_signal_execute(int sig, PosixSignalDisposition action, int pid) return 0; } +static int +send_signal(int *errnop, int pid, int signal) +{ + char msg[64], file[128]; + int mode; + int ret; + + snprint(msg, sizeof(msg), __POSIX_SIGNAL_PREFIX "%d", signal); + switch(pid){ + case 0: + mode = PNGROUP; + break; + case -1: + return note_all_writable_processes(errnop, msg); + default: + if(pid < 0){ + mode = PNGROUP; + pid = -pid; + } else { + mode = PNPROC; + } + } + + snprint(file, sizeof(file), "/proc/%d/note", pid); + if(access(file, AWRITE) != 0){ + if(access(file, AEXIST) == 0) + *errnop = __libposix_get_errno(PosixEPERM); + else + *errnop = __libposix_get_errno(PosixESRCH); + return -1; + } + ret = postnote(mode, pid, msg); + if(ret != 0){ + *errnop = __libposix_translate_errstr((uintptr_t)POSIX_kill); + return -1; + } + return 0; +} + + +static PosixSignalDisposition +default_signal_disposition(int signal) +{ + // see http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/signal.h.html + switch(signal){ + default: + if(signal >= __sigrtmin || signal <= __sigrtmin) + return TerminateTheProcess; + break; + + case PosixSIGALRM: + case PosixSIGHUP: + case PosixSIGINT: + case PosixSIGKILL: + case PosixSIGPIPE: + case PosixSIGTERM: + case PosixSIGUSR1: + case PosixSIGUSR2: + case PosixSIGPOLL: + case PosixSIGPROF: + case PosixSIGVTALRM: + return TerminateTheProcess; + case PosixSIGSTOP: + case PosixSIGTSTP: + case PosixSIGTTIN: + case PosixSIGTTOU: + return StopTheProcess; + case PosixSIGABRT: + case PosixSIGILL: + case PosixSIGFPE: + case PosixSIGBUS: + case PosixSIGQUIT: + case PosixSIGSEGV: + case PosixSIGSYS: + case PosixSIGTRAP: + case PosixSIGXCPU: + case PosixSIGXFSZ: + return TerminateTheProcessAndCoreDump; + case PosixSIGCHLD: + case PosixSIGURG: + return SignalHandled; + case PosixSIGCONT: + return ResumeTheProcess; + } + sysfatal("libposix: unknown PosixSignal %d", signal); +} + +int +POSIX_kill(int *errnop, int pid, int sig) +{ + PosixSignals signal; + PosixSignalDisposition action; + + signal = __code_to_signal_map[sig]; + if(signal == 0 + &&(sig < __sigrtmin || sig > __sigrtmax)) + sysfatal("libposix: undefined signal %d", sig); + if(pid == getpid()){ + if(__libposix_signal_trampoline(sig)) + action = SignalHandled; + else + action = default_signal_disposition(sig); + if(!execute_disposition(sig, action, -1)){ + *errnop = __libposix_get_errno(PosixEPERM); + return -1; + } + } + + switch(signal){ + case PosixSIGKILL: + if(pid > 0) + if(!send_control_msg(pid, "kill")){ + *errnop = __libposix_get_errno(PosixEPERM); + return -1; + } + break; + case PosixSIGSTOP: + if(pid > 0) + if(!send_control_msg(pid, "stop")){ + *errnop = __libposix_get_errno(PosixEPERM); + return -1; + } + break; + case PosixSIGCONT: + if(pid > 0) + if(!send_control_msg(pid, "start")){ + *errnop = __libposix_get_errno(PosixEPERM); + return -1; + } + break; + default: + break; + } + return send_signal(errnop, pid, sig); +} + +static int +translate_jehanne_note(char *note) +{ + // TODO: implement + return 0; +} + + int __libposix_note_handler(void *ureg, char *note) { - int sig; + int sig, ret; PosixSignalDisposition action; if(strncmp(note, __POSIX_SIGNAL_PREFIX, __POSIX_SIGNAL_PREFIX_LEN) != 0) return translate_jehanne_note(note); // TODO: should we translate common notes? sig = atoi(note+__POSIX_SIGNAL_PREFIX_LEN); + if(sig < __min_known_sig || sig > __max_known_sig) + sysfatal("libposix: '%s' does not carry a signal", note); + *__handling_external_signal = 1; action = __libposix_signal_trampoline(sig); - return POSIX_signal_execute(sig, action, -1); + ret = execute_disposition(sig, action, -1); + *__handling_external_signal = 0; + return ret; +} + +int +libposix_define_realtime_signals(int sigrtmin, int sigrtmax) +{ + if(sigrtmin >= 256 || sigrtmin <=0) + sysfatal("libposix: invalid SIGRTMIN %d (must be positive and less then 256)", sigrtmin); + if(sigrtmax >= 256 || sigrtmax <=0) + sysfatal("libposix: invalid SIGRTMAX %d (must be positive and less then 256)", sigrtmax); + if(sigrtmax <= sigrtmin) + sysfatal("libposix: invalid SIGRTMAX %d (must be greater than SIGRTMIN %d)", sigrtmax, sigrtmin); + if(__libposix_initialized()) + return 0; + __sigrtmin = sigrtmin; + __sigrtmax = sigrtmax; + if(sigrtmin < __min_known_sig || __min_known_sig == 0) + __min_known_sig = sigrtmin; + if(sigrtmax > __max_known_sig || __max_known_sig == 0) + __max_known_sig = sigrtmax; + return 1; +} + +int +libposix_define_signal(PosixSignals signal, int code) +{ + if(signal >= PosixNumberOfSignals) + sysfatal("libposix: unknown PosixSignal %d", signal); + if(code >= 256 || code <=0) + sysfatal("libposix: invalid signal number %d (must be positive and less then 256)", code); + if(__libposix_initialized()) + return 0; + __signals_to_code_map[signal] = (unsigned char)code; + __code_to_signal_map[code] = (unsigned char)signal; + if(code < __min_known_sig || __min_known_sig == 0) + __min_known_sig = code; + if(code > __max_known_sig || __max_known_sig == 0) + __max_known_sig = code; + return 1; } int