From 384c195faa6988a4b9b0ffb2f52ba0658ed40152 Mon Sep 17 00:00:00 2001 From: Liu Xinwu Date: Wed, 9 May 2018 18:19:16 +0800 Subject: [PATCH] tools: acrn-crashlog: event handler thread for acrnprobe Event handler is the thread to handle events detected by channel. It's awakened by a enqueued event. Signed-off-by: Liu Xinwu Reviewed-by: Zhang Yanmin Reviewed-by: Liu Chuansheng Reviewed-by: Zhao Yakui Reviewed-by: Geoffroy Van Cutsem Acked-by: Eddie Dong --- tools/acrn-crashlog/acrnprobe/event_handler.c | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) diff --git a/tools/acrn-crashlog/acrnprobe/event_handler.c b/tools/acrn-crashlog/acrnprobe/event_handler.c index 2393a657f..3314bf441 100644 --- a/tools/acrn-crashlog/acrnprobe/event_handler.c +++ b/tools/acrn-crashlog/acrnprobe/event_handler.c @@ -3,9 +3,187 @@ * SPDX-License-Identifier: BSD-3-Clause */ +#include +#include +#include +#include +#include +#include +#include "event_queue.h" +#include "load_conf.h" +#include "channels.h" +#include "fsutils.h" +#include "log_sys.h" #include "event_handler.h" +/* Watchdog timeout in second*/ +#define WDT_TIMEOUT 300 + +static struct event_t *last_e; +static int event_processing; + +/** + * Handle watchdog expire. + * + * @param signal Signal which triggered this function. + */ +static void wdt_timeout(int signal) +{ + struct event_t *e; + struct crash_t *crash; + struct info_t *info; + int count; + + if (signal == SIGALRM) { + LOGE("haven't received heart beat(%ds) for %ds, killing self\n", + HEART_BEAT, WDT_TIMEOUT); + + if (event_processing) { + LOGE("event (%d, %s) processing...\n", + last_e->event_type, last_e->path); + free(last_e); + } + + count = events_count(); + LOGE("total %d unhandled events :\n", count); + + while (count-- && (e = event_dequeue())) { + switch (e->event_type) { + case CRASH: + crash = (struct crash_t *)e->private; + LOGE("CRASH (%s, %s)\n", (char *)crash->name, + e->path); + break; + case INFO: + info = (struct info_t *)e->private; + LOGE("INFO (%s)\n", (char *)info->name); + break; + case UPTIME: + LOGE("UPTIME\n"); + break; + case HEART_BEAT: + LOGE("HEART_BEAT\n"); + break; + case REBOOT: + LOGE("REBOOT\n"); + break; + default: + LOGE("error event type %d\n", e->event_type); + } + free(e); + } + + raise(SIGKILL); + } +} + +/** + * Fed watchdog. + * + * @param timeout in second When the watchdog expire next time. + */ +static void watchdog_fed(int timeout) +{ + struct itimerval new_value; + int ret; + + memset(&new_value, 0, sizeof(new_value)); + + new_value.it_value.tv_sec = timeout; + ret = setitimer(ITIMER_REAL, &new_value, NULL); + if (ret < 0) { + LOGE("setitimer failed, error (%s)\n", strerror(errno)); + exit(EXIT_FAILURE); + } +} + +/** + * Initialize watchdog. This watchdog is used to monitor event handler. + * + * @param timeout in second When the watchdog expire next time. + */ +static void watchdog_init(int timeout) +{ + struct itimerval new_value; + int ret; + sighandler_t ohdlr; + + ohdlr = signal(SIGALRM, wdt_timeout); + if (ohdlr == SIG_ERR) { + LOGE("signal failed, error (%s)\n", strerror(errno)); + exit(EXIT_FAILURE); + } + + memset(&new_value, 0, sizeof(new_value)); + + new_value.it_value.tv_sec = timeout; + ret = setitimer(ITIMER_REAL, &new_value, NULL); + if (ret < 0) { + LOGE("setitimer failed, error (%s)\n", strerror(errno)); + exit(EXIT_FAILURE); + } +} + +/** + * Process each event in event queue. + * Note that currently event handler is single threaded. + */ +static void *event_handle(void *unused __attribute__((unused))) +{ + int id; + struct sender_t *sender; + struct event_t *e; + + while ((e = event_dequeue())) { + /* here we only handle internal event */ + if (e->event_type == HEART_BEAT) { + watchdog_fed(WDT_TIMEOUT); + free(e); + continue; + } + + /* last_e is allocated for debug purpose, the information + * will be dumped if watchdog expire. + */ + last_e = malloc(sizeof(*e) + e->len); + if (last_e == NULL) { + LOGE("malloc failed, error (%s)\n", strerror(errno)); + exit(EXIT_FAILURE); + } + event_processing = 1; + memcpy(last_e, e, sizeof(*e) + e->len); + + for_each_sender(id, sender, conf) { + if (!sender) + continue; + + sender->send(e); + } + + if ((e->dir)) + free(e->dir); + free(e); + event_processing = 0; + free(last_e); + } + + LOGE("something goes error, %s exit\n", __func__); + return NULL; +} + +/** + * Initialize event handler. + */ int init_event_handler(void) { + int ret; + pthread_t pid; + + watchdog_init(WDT_TIMEOUT); + ret = create_detached_thread(&pid, &event_handle, NULL); + if (ret) { + LOGE("create event handler failed (%s)\n", strerror(errno)); + return -1; + } return 0; }