From 3e4b840acca69a17cb13c2752d076a6f61175885 Mon Sep 17 00:00:00 2001 From: Bui Nguyen Quoc Thanh Date: Thu, 6 Feb 2020 11:43:44 +0700 Subject: daemon: Alternative of timerfd in QNX There is no timerfd_create in QNX so try to use threads to sleep and notify to main thread via unamed pipes. Signed-off-by: Bui Nguyen Quoc Thanh --- src/daemon/dlt-daemon.c | 208 ++++++++++++++++++++++++++++++++++++++++-------- src/daemon/dlt-daemon.h | 8 +- 2 files changed, 184 insertions(+), 32 deletions(-) diff --git a/src/daemon/dlt-daemon.c b/src/daemon/dlt-daemon.c index d4a5e90..64135bd 100644 --- a/src/daemon/dlt-daemon.c +++ b/src/daemon/dlt-daemon.c @@ -98,6 +98,70 @@ int g_exit = 0; int g_signo = 0; +static char dlt_timer_conn_types[DLT_TIMER_UNKNOWN + 1] = { + [DLT_TIMER_PACKET] = DLT_CONNECTION_ONE_S_TIMER, + [DLT_TIMER_ECU] = DLT_CONNECTION_SIXTY_S_TIMER, +#ifdef DLT_SYSTEMD_WATCHDOG_ENABLE + [DLT_TIMER_SYSTEMD] = DLT_CONNECTION_SYSTEMD_TIMER, +#endif + [DLT_TIMER_GATEWAY] = DLT_CONNECTION_GATEWAY_TIMER, + [DLT_TIMER_UNKNOWN] = DLT_CONNECTION_TYPE_MAX +}; + +static char dlt_timer_names[DLT_TIMER_UNKNOWN + 1][32] = { + [DLT_TIMER_PACKET] = "Timing packet", + [DLT_TIMER_ECU] = "ECU version", +#ifdef DLT_SYSTEMD_WATCHDOG_ENABLE + [DLT_TIMER_SYSTEMD] = "Systemd watchdog", +#endif + [DLT_TIMER_GATEWAY] = "Gateway", + [DLT_TIMER_UNKNOWN] = "Unknown timer" +}; + +#ifdef __QNX__ +static int dlt_timer_pipes[DLT_TIMER_UNKNOWN][2] = { + /* [timer_id] = {read_pipe, write_pipe} */ + [DLT_TIMER_PACKET] = {DLT_FD_INIT, DLT_FD_INIT}, + [DLT_TIMER_ECU] = {DLT_FD_INIT, DLT_FD_INIT}, +#ifdef DLT_SYSTEMD_WATCHDOG_ENABLE + [DLT_TIMER_SYSTEMD] = {DLT_FD_INIT, DLT_FD_INIT}, +#endif + [DLT_TIMER_GATEWAY] = {DLT_FD_INIT, DLT_FD_INIT} +}; + +static pthread_t timer_threads[DLT_TIMER_UNKNOWN] = { + [DLT_TIMER_PACKET] = 0, + [DLT_TIMER_ECU] = 0, +#ifdef DLT_SYSTEMD_WATCHDOG_ENABLE + [DLT_TIMER_SYSTEMD] = 0, +#endif + [DLT_TIMER_GATEWAY] = 0 +}; + +static DltDaemonPeriodicData *timer_data[DLT_TIMER_UNKNOWN] = { + [DLT_TIMER_PACKET] = NULL, + [DLT_TIMER_ECU] = NULL, +#ifdef DLT_SYSTEMD_WATCHDOG_ENABLE + [DLT_TIMER_SYSTEMD] = NULL, +#endif + [DLT_TIMER_GATEWAY] = NULL +}; + +void close_pipes(int fds[2]) +{ + if (fds[0] > 0) { + close(fds[0]); + fds[0] = DLT_FD_INIT; + } + + if (fds[1] > 0) { + close(fds[1]); + fds[1] = DLT_FD_INIT; + } +} + +#endif // __QNX__ + /** * Print usage information of tool. */ @@ -1622,6 +1686,10 @@ void dlt_daemon_exit_trigger() (void)unlink(tmp); #endif +#ifdef __QNX__ + dlt_daemon_cleanup_timers(); +#endif + /* stop event loop */ g_exit = -1; } @@ -1651,6 +1719,30 @@ void dlt_daemon_signal_handler(int sig) } /* dlt_daemon_signal_handler() */ +#ifdef __QNX__ +void dlt_daemon_cleanup_timers() +{ + int i = 0; + while (i < DLT_TIMER_UNKNOWN) { + /* Remove FIFO of every timer and kill timer thread */ + if (0 != timer_threads[i]) { + pthread_kill(timer_threads[i], SIGUSR1); + pthread_join(timer_threads[i], NULL); + timer_threads[i] = 0; + + close_pipes(dlt_timer_pipes[i]); + + /* Free data of every timer */ + if (NULL != timer_data[i]) { + free(timer_data[i]); + timer_data[i] = NULL; + } + } + i++; + } +} +#endif + void dlt_daemon_daemonize(int verbose) { int i; @@ -3168,32 +3260,57 @@ int dlt_daemon_send_ringbuffer_to_client(DltDaemon *daemon, DltDaemonLocal *daem return DLT_DAEMON_ERROR_OK; } -static char dlt_timer_conn_types[DLT_TIMER_UNKNOWN + 1] = { - [DLT_TIMER_PACKET] = DLT_CONNECTION_ONE_S_TIMER, - [DLT_TIMER_ECU] = DLT_CONNECTION_SIXTY_S_TIMER, -#ifdef DLT_SYSTEMD_WATCHDOG_ENABLE - [DLT_TIMER_SYSTEMD] = DLT_CONNECTION_SYSTEMD_TIMER, -#endif - [DLT_TIMER_GATEWAY] = DLT_CONNECTION_GATEWAY_TIMER, - [DLT_TIMER_UNKNOWN] = DLT_CONNECTION_TYPE_MAX -}; +#ifdef __QNX__ +static void *timer_thread(void *data) +{ + sigset_t set; + sigset_t pset; + int pexit = 0; -static char dlt_timer_names[DLT_TIMER_UNKNOWN + 1][32] = { - [DLT_TIMER_PACKET] = "Timing packet", - [DLT_TIMER_ECU] = "ECU version", -#ifdef DLT_SYSTEMD_WATCHDOG_ENABLE - [DLT_TIMER_SYSTEMD] = "Systemd watchdog", + /* + * In timer thread, it is only expecting to receive SIGUSR1 + */ + sigemptyset(&set); + sigaddset(&set, SIGUSR1); + sigprocmask(SIG_BLOCK, &set, NULL); + + DltDaemonPeriodicData* timer_data = (DltDaemonPeriodicData*) data; + + /* Timer will start in starts_in sec*/ + sleep(timer_data->starts_in); + while (1) { + if (0 > write(dlt_timer_pipes[timer_data->timer_id][1], "1", 1)) { + dlt_vlog(LOG_ERR, "Failed to send notification for timer [%s]!\n", + dlt_timer_names[timer_data->timer_id]); + pexit = 1; + } + + if (sigpending(&pset)) { + dlt_log(LOG_ERR, "sigpending error!\n"); + pexit = 1; + } + + if (sigismember(&pset, SIGUSR1)) { + dlt_log(LOG_NOTICE, "Received SIGUSR1! Stop thread\n"); + pexit = 1; + } + + if (pexit) { + close_pipes(dlt_timer_pipes[timer_data->timer_id]); + return NULL; + } + + sleep(timer_data->period_sec); + } +} #endif - [DLT_TIMER_GATEWAY] = "Gateway", - [DLT_TIMER_UNKNOWN] = "Unknown timer" -}; int create_timer_fd(DltDaemonLocal *daemon_local, int period_sec, int starts_in, DltTimers timer_id) { - int local_fd = -1; + int local_fd = DLT_FD_INIT; char *timer_name = NULL; if (timer_id >= DLT_TIMER_UNKNOWN) { @@ -3204,18 +3321,17 @@ int create_timer_fd(DltDaemonLocal *daemon_local, timer_name = dlt_timer_names[timer_id]; if (daemon_local == NULL) { - dlt_log(DLT_LOG_ERROR, "Daemaon local structure is NULL"); + dlt_log(DLT_LOG_ERROR, "Daemon local structure is NULL"); return -1; } if ((period_sec <= 0) || (starts_in <= 0)) { /* timer not activated via the service file */ dlt_vlog(LOG_INFO, "<%s> not set: period=0\n", timer_name); - local_fd = -1; + local_fd = DLT_FD_INIT; } - -#ifdef linux else { +#ifdef linux struct itimerspec l_timer_spec; local_fd = timerfd_create(CLOCK_MONOTONIC, 0); @@ -3231,17 +3347,47 @@ int create_timer_fd(DltDaemonLocal *daemon_local, if (timerfd_settime(local_fd, 0, &l_timer_spec, NULL) < 0) { dlt_vlog(LOG_WARNING, "<%s> timerfd_settime failed: %s\n", timer_name, strerror(errno)); - local_fd = -1; + local_fd = DLT_FD_INIT; + } +#elif __QNX__ + /* + * Since timerfd is not valid in QNX, new threads are introduced + * to manage timers and communicate with main thread when timer expires. + */ + if(0 != pipe(dlt_timer_pipes[timer_id])) { + dlt_vlog(LOG_ERR, "Failed to create pipe for timer [%s]", + dlt_timer_names[timer_id]); + return -1; + } + if (NULL == timer_data[timer_id]) { + timer_data[timer_id] = calloc(1, sizeof(DltDaemonPeriodicData)); + if (NULL == timer_data[timer_id]) { + dlt_vlog(LOG_ERR, "Failed to allocate memory for timer_data [%s]!\n", + dlt_timer_names[timer_id]); + close_pipes(dlt_timer_pipes[timer_id]); + return -1; + } } - } -#endif - /* If fully initialized we are done. - * Event handling registration is done later on with other connections. - */ - if (local_fd > 0) - dlt_vlog(LOG_INFO, "<%s> initialized with %d timer\n", timer_name, - period_sec); + timer_data[timer_id]->timer_id = timer_id; + timer_data[timer_id]->period_sec = period_sec; + timer_data[timer_id]->starts_in = starts_in; + timer_data[timer_id]->wakeups_missed = 0; + + if (0 != pthread_create(&timer_threads[timer_id], NULL, + &timer_thread, (void*)timer_data[timer_id])) { + dlt_vlog(LOG_ERR, "Failed to create new thread for timer [%s]!\n", + dlt_timer_names[timer_id]); + /* Clean up timer before returning */ + close_pipes(dlt_timer_pipes[timer_id]); + free(timer_data[timer_id]); + timer_data[timer_id] = NULL; + + return -1; + } + local_fd = dlt_timer_pipes[timer_id][0]; +#endif + } return dlt_connection_create(daemon_local, &daemon_local->pEvent, diff --git a/src/daemon/dlt-daemon.h b/src/daemon/dlt-daemon.h index 4095cf3..7a4b29c 100644 --- a/src/daemon/dlt-daemon.h +++ b/src/daemon/dlt-daemon.h @@ -169,8 +169,10 @@ typedef struct typedef struct { - int timer_fd; unsigned long long wakeups_missed; + int period_sec; + int starts_in; + int timer_id; } DltDaemonPeriodicData; typedef struct @@ -197,6 +199,10 @@ int dlt_daemon_local_ecu_version_init(DltDaemon *daemon, DltDaemonLocal *daemon_ void dlt_daemon_daemonize(int verbose); void dlt_daemon_exit_trigger(); void dlt_daemon_signal_handler(int sig); +#ifdef __QNX__ +void dlt_daemon_cleanup_timers(); +void close_pipes(int fds[2]); +#endif int dlt_daemon_process_client_connect(DltDaemon *daemon, DltDaemonLocal *daemon_local, DltReceiver *recv, int verbose); int dlt_daemon_process_client_messages(DltDaemon *daemon, DltDaemonLocal *daemon_local, DltReceiver *revc, int verbose); int dlt_daemon_process_client_messages_serial(DltDaemon *daemon, -- cgit v1.2.1