diff options
author | José Bollo <jose.bollo@iot.bzh> | 2016-05-11 15:32:42 +0200 |
---|---|---|
committer | José Bollo <jose.bollo@iot.bzh> | 2016-05-11 15:32:42 +0200 |
commit | 36a165503297903204be32a07e0440ca56dac7f0 (patch) | |
tree | 3f7f24ecdcb8157fa0c58b685cbd715e2411fed5 | |
parent | 3b0d4962f64f546474fa033ffa4e3d067194c888 (diff) |
improves signal handling & call monitoring
Change-Id: Ia37c70ffbb9122b2d53ec93baf203cd141613dc6
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
-rw-r--r-- | src/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/afb-api-so.c | 60 | ||||
-rw-r--r-- | src/afb-sig-handler.c | 118 | ||||
-rw-r--r-- | src/afb-sig-handler.h | 24 | ||||
-rw-r--r-- | src/main.c | 53 |
5 files changed, 161 insertions, 95 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 707b2e09..bad60b34 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,6 +10,7 @@ ADD_LIBRARY(src OBJECT afb-hswitch.c afb-method.c afb-msg-json.c + afb-sig-handler.c afb-websock.c afb-ws-json.c afb-ws.c diff --git a/src/afb-api-so.c b/src/afb-api-so.c index 07d0a5f2..6ac5070f 100644 --- a/src/afb-api-so.c +++ b/src/afb-api-so.c @@ -26,10 +26,6 @@ #include <limits.h> #include <sys/types.h> #include <sys/stat.h> -#include <signal.h> -#include <time.h> -#include <sys/syscall.h> -#include <setjmp.h> #include "afb-plugin.h" #include "afb-req-itf.h" @@ -40,10 +36,9 @@ #include "afb-context.h" #include "afb-apis.h" #include "afb-api-so.h" +#include "afb-sig-handler.h" #include "verbose.h" -extern __thread sigjmp_buf *error_handler; - struct api_so_desc { struct AFB_plugin *plugin; /* descriptor */ size_t apilength; @@ -85,50 +80,23 @@ static const struct afb_daemon_itf daemon_itf = { .get_system_bus = (void*)afb_common_get_system_bus }; +struct monitoring { + struct afb_req req; + void (*action)(struct afb_req); +}; -static void trapping_call(struct afb_req req, void(*cb)(struct afb_req)) +static void monitored_call(int signum, struct monitoring *data) { - volatile int signum, timerset; - timer_t timerid; - sigjmp_buf jmpbuf, *older; - struct sigevent sevp; - struct itimerspec its; - - timerset = 0; - older = error_handler; - signum = setjmp(jmpbuf); - if (signum != 0) { - afb_req_fail_f(req, "aborted", "signal %d caught", signum); - } - else { - error_handler = &jmpbuf; - if (api_timeout > 0) { - timerset = 1; /* TODO: check statuses */ - sevp.sigev_notify = SIGEV_THREAD_ID; - sevp.sigev_signo = SIGALRM; - sevp.sigev_value.sival_ptr = NULL; -#if defined(sigev_notify_thread_id) - sevp.sigev_notify_thread_id = (pid_t)syscall(SYS_gettid); -#else - sevp._sigev_un._tid = (pid_t)syscall(SYS_gettid); -#endif - timer_create(CLOCK_THREAD_CPUTIME_ID, &sevp, &timerid); - its.it_interval.tv_sec = 0; - its.it_interval.tv_nsec = 0; - its.it_value.tv_sec = api_timeout; - its.it_value.tv_nsec = 0; - timer_settime(timerid, 0, &its, NULL); - } - - cb(req); - } - if (timerset) - timer_delete(timerid); - error_handler = older; + if (signum != 0) + afb_req_fail_f(data->req, "aborted", "signal %s(%d) caught", strsignal(signum), signum); + else + data->action(data->req); } static void call_check(struct afb_req req, struct afb_context *context, const struct AFB_restapi *verb) { + struct monitoring data; + int stag = (int)(verb->session & AFB_SESSION_MASK); if (stag != AFB_SESSION_NONE) { @@ -153,7 +121,9 @@ static void call_check(struct afb_req req, struct afb_context *context, const st if ((stag & AFB_SESSION_CLOSE) != 0) afb_context_close(context); - trapping_call(req, verb->callback); + data.req = req; + data.action = verb->callback; + afb_sig_monitor((void*)monitored_call, &data, api_timeout); } static void call(struct api_so_desc *desc, struct afb_req req, struct afb_context *context, const char *verb, size_t lenverb) diff --git a/src/afb-sig-handler.c b/src/afb-sig-handler.c new file mode 100644 index 00000000..127bf0c9 --- /dev/null +++ b/src/afb-sig-handler.c @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2015 "IoT.bzh" + * Author "Fulup Ar Foll" + * Author José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include <stdlib.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <sys/syscall.h> +#include <setjmp.h> + +#include "afb-sig-handler.h" +#include "verbose.h" + +static _Thread_local sigjmp_buf *error_handler; + +static void on_signal_terminate (int signum) +{ + ERROR("Terminating signal received %s", strsignal(signum)); + exit(1); +} + +static void on_signal_error(int signum) +{ + sigset_t sigset; + + // unlock signal to allow a new signal to come + if (error_handler != NULL) { + sigemptyset(&sigset); + sigaddset(&sigset, signum); + sigprocmask(SIG_UNBLOCK, &sigset, 0); + longjmp(*error_handler, signum); + } + if (signum == SIGALRM) + return; + ERROR("Unmonitored signal received %s", strsignal(signum)); + exit(2); +} + +static int install(void (*handler)(int), int *signals) +{ + int result = 1; + while(*signals > 0) { + if (signal(*signals, handler) == SIG_ERR) { + ERROR("failed to install signal handler for signal %s", strsignal(*signals)); + result = 0; + } + signals++; + } + return result; +} + +int afb_sig_handler_init() +{ + static int sigerr[] = { SIGALRM, SIGSEGV, SIGFPE, 0 }; + static int sigterm[] = { SIGINT, SIGABRT, 0 }; + + return (install(on_signal_error, sigerr) & install(on_signal_terminate, sigterm)) - 1; +} + +void afb_sig_monitor(void (*function)(int sig, void*), void *closure, int timeout) +{ + volatile int signum, timerset; + timer_t timerid; + sigjmp_buf jmpbuf, *older; + struct sigevent sevp; + struct itimerspec its; + + timerset = 0; + older = error_handler; + signum = setjmp(jmpbuf); + if (signum != 0) { + function(signum, closure); + } + else { + error_handler = &jmpbuf; + if (timeout > 0) { + timerset = 1; /* TODO: check statuses */ + sevp.sigev_notify = SIGEV_THREAD_ID; + sevp.sigev_signo = SIGALRM; + sevp.sigev_value.sival_ptr = NULL; +#if defined(sigev_notify_thread_id) + sevp.sigev_notify_thread_id = (pid_t)syscall(SYS_gettid); +#else + sevp._sigev_un._tid = (pid_t)syscall(SYS_gettid); +#endif + timer_create(CLOCK_THREAD_CPUTIME_ID, &sevp, &timerid); + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + its.it_value.tv_sec = timeout; + its.it_value.tv_nsec = 0; + timer_settime(timerid, 0, &its, NULL); + } + + function(0, closure); + } + if (timerset) + timer_delete(timerid); + error_handler = older; +} + diff --git a/src/afb-sig-handler.h b/src/afb-sig-handler.h new file mode 100644 index 00000000..3d0249a2 --- /dev/null +++ b/src/afb-sig-handler.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2015 "IoT.bzh" + * Author "Fulup Ar Foll" + * Author José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +extern int afb_sig_handler_init(); + +extern void afb_sig_monitor(void (*function)(int sig, void*), void *closure, int timeout); + @@ -42,6 +42,7 @@ #include "afb-hsrv.h" #include "afb-context.h" #include "afb-hreq.h" +#include "afb-sig-handler.h" #include "session.h" #include "verbose.h" #include "afb-common.h" @@ -127,8 +128,6 @@ static AFB_options cliOptions [] = { {0, 0, NULL, NULL} }; - - /*---------------------------------------------------------- | printversion | print version and copyright @@ -429,49 +428,6 @@ static void closeSession (int status, void *data) { } /*---------------------------------------------------------- - | timeout signalQuit - +--------------------------------------------------------- */ -void signalQuit (int signum) -{ - ERROR("Terminating signal received %s", strsignal(signum)); - exit(1); -} - -/*---------------------------------------------------------- - | Error signals - | - +--------------------------------------------------------- */ -__thread sigjmp_buf *error_handler; -static void signalError(int signum) -{ - sigset_t sigset; - - // unlock signal to allow a new signal to come - if (error_handler != NULL) { - sigemptyset(&sigset); - sigaddset(&sigset, signum); - sigprocmask(SIG_UNBLOCK, &sigset, 0); - longjmp(*error_handler, signum); - } - if (signum == SIGALRM) - return; - ERROR("Unmonitored signal received %s", strsignal(signum)); - exit(2); -} - -static void install_error_handlers() -{ - int i, signals[] = { SIGALRM, SIGSEGV, SIGFPE, 0 }; - - for (i = 0; signals[i] != 0; i++) { - if (signal(signals[i], signalError) == SIG_ERR) { - ERROR("Signal handler error"); - exit(1); - } - } -} - -/*---------------------------------------------------------- | daemonize | set the process in background +--------------------------------------------------------- */ @@ -647,11 +603,8 @@ int main(int argc, char *argv[]) { exit (1); } - install_error_handlers(); - - // ------------------ clean exit on CTR-C signal ------------------------ - if (signal (SIGINT, signalQuit) == SIG_ERR || signal (SIGABRT, signalQuit) == SIG_ERR) { - ERROR("main fail to install Signal handler"); + if (afb_sig_handler_init() < 0) { + ERROR("main fail to initialise signal handlers"); return 1; } |