No logic change, just moving code around.
Change-Id: Ie1f95a4661c71839f75dedebf93eac4f94177d87
Signed-off-by: Michal Bloch <m.bloch@samsung.com>
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 \
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)
{
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
}
/**
- * @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
}
/**
- * @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
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 = {
--- /dev/null
+/* 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);
+}
+
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