From 341b1f883a05e1bb10107b99e4a588a28528a69b Mon Sep 17 00:00:00 2001 From: Michal Bloch Date: Fri, 24 Feb 2023 22:18:55 +0100 Subject: [PATCH] dlog_logger: extract some struct logger functions No logic change, just moving code around. Change-Id: Ie1f95a4661c71839f75dedebf93eac4f94177d87 Signed-off-by: Michal Bloch --- Makefile.am | 1 + src/logger/logger.c | 157 --------------------------------------- src/logger/logger_internal.c | 170 +++++++++++++++++++++++++++++++++++++++++++ src/logger/logger_internal.h | 6 ++ 4 files changed, 177 insertions(+), 157 deletions(-) create mode 100644 src/logger/logger_internal.c diff --git a/Makefile.am b/Makefile.am index dfa8af8..1e92855 100644 --- a/Makefile.am +++ b/Makefile.am @@ -137,6 +137,7 @@ dlog_logger_SOURCES = \ external/fastlz/fastlz.c \ external/miniz/miniz.c \ src/logger/logger.c \ + src/logger/logger_internal.c \ src/logger/logger_privileges.c \ src/logger/compression_fastlz.c \ src/logger/compression_miniz.c \ diff --git a/src/logger/logger.c b/src/logger/logger.c index 9e71025..eabaa90 100644 --- a/src/logger/logger.c +++ b/src/logger/logger.c @@ -47,18 +47,8 @@ static const int DEFAULT_EPOLL_TIME_MS = 1000; static const int DEFAULT_LAZY_POLLING_TOTAL_MS = 0; static const int DEFAULT_LAZY_POLLING_SLEEP_MS = 1000; -static const int S_TO_MS = 1000; -static const int MS_TO_NS = 1000000; - struct backend_data g_backend = {}; -static void reader_logger_free(void *ptr, void *user_data) -{ - struct reader_logger *reader = (struct reader_logger *)ptr; - assert(reader); - reader_free(&reader->common); -} - // TODO: Consider inlining struct now_t everywhere int get_now(struct now_t *now) { @@ -481,51 +471,6 @@ int service_writer_kmsg(struct logger *server, struct writer *wr, struct epoll_e return 0; } -static void service_reader_common(void *ptr, void *user_data) -{ - struct reader_common *reader = (struct reader_common *)ptr; - struct logger *logger = (struct logger *)user_data; - - assert(reader); - assert(logger); - - struct now_t now; - int r = get_now(&now); - if (r < 0) { - reader_free(reader); - return; - } - - r = reader->service_reader(reader, now); - if (r > 0) { - reader_free(reader); - return; - } - - /* `service_reader()` returns -1 if everything was flushed, or 0 if - * a mild error happened that can be recovered from simply by waiting, - * the prime example being the pipe getting clogged. As soon as the - * reader is available again, we'd like to know about it to ensure - * logs are flushed as quickly as possible, which is why the EPOLLOUT. - * - * On the other hand, we don't want to remove readers from epoll even - * if they successfully flushed and have no logs to wait for. Consider - * the case where a buffer is unused (for example through libdlog's - * buffer disabling feature). If we relied on receiving an error on - * calling `write()` to learn that the connection had been closed, - * we would never learn about it because there would be no incoming - * logs to trigger the flush and so any FDs representing connections - * to such buffer would leak until a log finally arrived (which could - * be never). This is why waiting is also done on EPOLLHUP. */ - if (modify_fd_entity(&logger->epoll_common, &reader->fd_entity_sink, (r == 0) ? EPOLLOUT : EPOLLHUP) < 0) { - /* ignore, can't really happen and it's not - * like we can do anything about it either */ - } - - // Ditto, can't do much about it - (void) reader_flush(reader, now.mono, logger->buf_params.time); -} - /** * @brief Service syslog * @details Read from the syslog socket @@ -570,24 +515,6 @@ int service_writer_syslog(struct logger *server, struct writer *wr, struct epoll } /** - * @brief Service all readers - * @details Update all readers with latest data - * @param[in] server The logger server - * @param[in] force_push Whether to force logs to be pushed to the readers - */ -static void service_all_readers(struct logger *server) -{ - for (int i = 0; i < LOG_ID_MAX; i++) { - struct log_buffer *const buffer = server->buffers[i]; - if (!buffer) - continue; - - list_foreach(buffer->readers_pipe, server, service_reader_common); - } - list_foreach(server->readers_logger, server, service_reader_common); -} - -/** * @brief Add writer to server * @details Adds a writer to the server's witers list and registers its event to epoll loop * @param[in] l The server to add the writer to @@ -714,32 +641,6 @@ int logger_create(struct logger_config_data *data, struct logger *l) } /** - * @brief Free logger - * @details Deallocate the logger and its auxiliary structures - * @param[in] l The logger server - */ -#ifndef UNIT_TEST -static -#endif -void logger_free(struct logger *l) -{ - assert(l); - - list_foreach(l->writers, l, foreach_writer_free); - list_foreach(l->readers_logger, l, reader_logger_free); - - int j; - for (j = 0; j < LOG_ID_MAX; j++) - if (l->buffers[j]) - buffer_free(l->buffers[j]); - - epoll_metadata_destroy(&l->epoll_common); - epoll_metadata_destroy(&l->epoll_socket); - - qos_free(l->qos); -} - -/** * @brief Handle interrupting/terminating signals * @details Clears global flag to stop main loop * @param[in] signo signal number @@ -750,64 +651,6 @@ static void handle_signals(int signo) g_logger_run = 0; } -static void ensure_epoll_size(struct epoll_event **events, unsigned *size, unsigned wanted_size) -{ - assert(events); - assert(size); - - if (wanted_size <= *size) - return; - - typeof(*events) temp = realloc(*events, wanted_size * sizeof **events); - if (!temp) - return; - - *events = temp; - *size = wanted_size; -} - -void dispatch_epoll_event(struct logger *server, struct epoll_event *event) -{ - struct fd_entity *const entity = (struct fd_entity *) event->data.ptr; - assert(entity->dispatch_event); - entity->dispatch_event(server, event, entity->dispatch_data); -} - -int handle_epoll_events(struct logger *server, struct epoll_metadata *metadata, int timeout) -{ - ensure_epoll_size(&metadata->events, &metadata->events_size, metadata->cnt); - - int nfds = epoll_wait(metadata->fd, metadata->events, metadata->events_size, timeout); - if (nfds < 0) - return errno == EINTR ? 0 : -errno; - - for (int i = 0; i < nfds; i++) - dispatch_epoll_event(server, metadata->events + i); - - return 0; -} - -int sleep_while_handling_socket(struct logger *server, struct epoll_metadata *metadata, int timeout) -{ - struct timespec ts_start; - if (clock_gettime(CLOCK_MONOTONIC, &ts_start)) - return -errno; - struct timespec ts_current; - - do { - int r = handle_epoll_events(server, metadata, timeout); - if (r < 0) - return r; - if (clock_gettime(CLOCK_MONOTONIC, &ts_current)) - return -errno; - } while ( - timeout > (ts_current.tv_sec - ts_start.tv_sec ) * S_TO_MS - + (ts_current.tv_nsec - ts_start.tv_nsec) / MS_TO_NS - ); - - return 0; -} - void setup_signals(struct logger *server) { struct sigaction action = { diff --git a/src/logger/logger_internal.c b/src/logger/logger_internal.c new file mode 100644 index 0000000..aebbb65 --- /dev/null +++ b/src/logger/logger_internal.c @@ -0,0 +1,170 @@ +/* Copyright (c) 2016-2023, Samsung Electronics Co., Ltd. All rights reserved. + * + * 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. */ + +#include "logger_internal.h" + +static const int S_TO_MS = 1000; +static const int MS_TO_NS = 1000000; + +static void ensure_epoll_size(struct epoll_event **events, unsigned *size, unsigned wanted_size) +{ + assert(events); + assert(size); + + if (wanted_size <= *size) + return; + + typeof(*events) temp = realloc(*events, wanted_size * sizeof **events); + if (!temp) + return; + + *events = temp; + *size = wanted_size; +} + +static void dispatch_epoll_event(struct logger *server, struct epoll_event *event) +{ + struct fd_entity *const entity = (struct fd_entity *) event->data.ptr; + assert(entity->dispatch_event); + entity->dispatch_event(server, event, entity->dispatch_data); +} + +int handle_epoll_events(struct logger *server, struct epoll_metadata *metadata, int timeout) +{ + ensure_epoll_size(&metadata->events, &metadata->events_size, metadata->cnt); + + int nfds = epoll_wait(metadata->fd, metadata->events, metadata->events_size, timeout); + if (nfds < 0) + return errno == EINTR ? 0 : -errno; + + for (int i = 0; i < nfds; i++) + dispatch_epoll_event(server, metadata->events + i); + + return 0; +} + +int sleep_while_handling_socket(struct logger *server, struct epoll_metadata *metadata, int timeout) +{ + struct timespec ts_start; + if (clock_gettime(CLOCK_MONOTONIC, &ts_start)) + return -errno; + struct timespec ts_current; + + do { + int r = handle_epoll_events(server, metadata, timeout); + if (r < 0) + return r; + if (clock_gettime(CLOCK_MONOTONIC, &ts_current)) + return -errno; + } while ( + timeout > (ts_current.tv_sec - ts_start.tv_sec ) * S_TO_MS + + (ts_current.tv_nsec - ts_start.tv_nsec) / MS_TO_NS + ); + + return 0; +} + +static void service_reader_common(void *ptr, void *user_data) +{ + struct reader_common *reader = (struct reader_common *)ptr; + struct logger *logger = (struct logger *)user_data; + + assert(reader); + assert(logger); + + struct now_t now; + int r = get_now(&now); + if (r < 0) { + reader_free(reader); + return; + } + + r = reader->service_reader(reader, now); + if (r > 0) { + reader_free(reader); + return; + } + + /* `service_reader()` returns -1 if everything was flushed, or 0 if + * a mild error happened that can be recovered from simply by waiting, + * the prime example being the pipe getting clogged. As soon as the + * reader is available again, we'd like to know about it to ensure + * logs are flushed as quickly as possible, which is why the EPOLLOUT. + * + * On the other hand, we don't want to remove readers from epoll even + * if they successfully flushed and have no logs to wait for. Consider + * the case where a buffer is unused (for example through libdlog's + * buffer disabling feature). If we relied on receiving an error on + * calling `write()` to learn that the connection had been closed, + * we would never learn about it because there would be no incoming + * logs to trigger the flush and so any FDs representing connections + * to such buffer would leak until a log finally arrived (which could + * be never). This is why waiting is also done on EPOLLHUP. */ + if (modify_fd_entity(&logger->epoll_common, &reader->fd_entity_sink, (r == 0) ? EPOLLOUT : EPOLLHUP) < 0) { + /* ignore, can't really happen and it's not + * like we can do anything about it either */ + } + + // Ditto, can't do much about it + (void) reader_flush(reader, now.mono, logger->buf_params.time); +} + +/** + * @brief Service all readers + * @details Update all readers with latest data + * @param[in] server The logger server + * @param[in] force_push Whether to force logs to be pushed to the readers + */ +void service_all_readers(struct logger *server) +{ + for (int i = 0; i < LOG_ID_MAX; i++) { + struct log_buffer *const buffer = server->buffers[i]; + if (!buffer) + continue; + + list_foreach(buffer->readers_pipe, server, service_reader_common); + } + list_foreach(server->readers_logger, server, service_reader_common); +} + +static void reader_logger_free(void *ptr, void *user_data) +{ + struct reader_logger *reader = (struct reader_logger *)ptr; + assert(reader); + reader_free(&reader->common); +} + +/** + * @brief Free logger + * @details Deallocate the logger and its auxiliary structures + * @param[in] l The logger server + */ +void logger_free(struct logger *l) +{ + assert(l); + + list_foreach(l->writers, l, foreach_writer_free); + list_foreach(l->readers_logger, l, reader_logger_free); + + int j; + for (j = 0; j < LOG_ID_MAX; j++) + if (l->buffers[j]) + buffer_free(l->buffers[j]); + + epoll_metadata_destroy(&l->epoll_common); + epoll_metadata_destroy(&l->epoll_socket); + + qos_free(l->qos); +} + diff --git a/src/logger/logger_internal.h b/src/logger/logger_internal.h index 686fbbd..7557dcb 100644 --- a/src/logger/logger_internal.h +++ b/src/logger/logger_internal.h @@ -174,6 +174,12 @@ int add_reader_memory(struct logger *server, struct reader_memory *reader); void flush_logfile_timely(struct log_file *file, struct timespec ts, int flush_time); int get_now(struct now_t *now); +// these live in `logger_internal.c`, the earlier ones are scattered in various others +int handle_epoll_events(struct logger *server, struct epoll_metadata *metadata, int timeout); +void service_all_readers(struct logger *server); +int sleep_while_handling_socket(struct logger *server, struct epoll_metadata *metadata, int timeout); +void logger_free(struct logger *l); + #ifdef __cplusplus } #endif -- 2.7.4