dlog_logger: extract some struct logger functions 41/289041/2
authorMichal Bloch <m.bloch@samsung.com>
Fri, 24 Feb 2023 21:18:55 +0000 (22:18 +0100)
committerMichal Bloch <m.bloch@samsung.com>
Tue, 28 Feb 2023 18:29:58 +0000 (19:29 +0100)
No logic change, just moving code around.

Change-Id: Ie1f95a4661c71839f75dedebf93eac4f94177d87
Signed-off-by: Michal Bloch <m.bloch@samsung.com>
Makefile.am
src/logger/logger.c
src/logger/logger_internal.c [new file with mode: 0644]
src/logger/logger_internal.h

index dfa8af8..1e92855 100644 (file)
@@ -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 \
index 9e71025..eabaa90 100644 (file)
@@ -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 (file)
index 0000000..aebbb65
--- /dev/null
@@ -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);
+}
+
index 686fbbd..7557dcb 100644 (file)
@@ -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