<p>laforge has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/libosmocore/+/20296">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">logging: Change stderr + file target to use non-blocking write<br><br>So far, we used blocking, buffered fwrite() to write to stderr<br>and file targets. This causes problems if there are [slow] consumers<br>causing delays, such as gnome-terminal (when the program is started<br>interactively) or systemd/journald (where we observe 64..128ms blocks on<br>stderr).<br><br>This patch introduces stderr/file based logging via write_queue<br>and osmo_select_main(), i.e. switch from glibc-buffered, blocking<br>to internally buffered, non-blocking writes.<br><br>Closes: OS#4311<br>Change-Id: Ia58fd78535c41b3da3aeb7733aadc785ace610da<br>---<br>M include/osmocom/core/logging.h<br>M src/logging.c<br>M src/select.c<br>3 files changed, 208 insertions(+), 15 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/96/20296/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/core/logging.h b/include/osmocom/core/logging.h</span><br><span>index 36ce941..6c1199a 100644</span><br><span>--- a/include/osmocom/core/logging.h</span><br><span>+++ b/include/osmocom/core/logging.h</span><br><span>@@ -289,8 +289,11 @@</span><br><span> </span><br><span> union {</span><br><span> struct {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* direct, blocking output via stdio */</span><br><span> FILE *out;</span><br><span> const char *fname;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* indirect output via write_queue and osmo_select_main() */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_wqueue *wqueue;</span><br><span> } tgt_file;</span><br><span> </span><br><span> struct {</span><br><span>@@ -393,6 +396,7 @@</span><br><span> bool ofd_wq_mode,</span><br><span> bool add_sink);</span><br><span> int log_target_file_reopen(struct log_target *tgt);</span><br><span style="color: hsl(120, 100%, 40%);">+int log_target_file_switch_to_wqueue(struct log_target *tgt);</span><br><span> int log_targets_reopen(void);</span><br><span> </span><br><span> void log_add_target(struct log_target *target);</span><br><span>diff --git a/src/logging.c b/src/logging.c</span><br><span>index 212b0b9..6bab54e 100644</span><br><span>--- a/src/logging.c</span><br><span>+++ b/src/logging.c</span><br><span>@@ -35,6 +35,7 @@</span><br><span> #include <stdlib.h></span><br><span> #include <stdio.h></span><br><span> #include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <unistd.h></span><br><span> </span><br><span> #ifdef HAVE_STRINGS_H</span><br><span> #include <strings.h></span><br><span>@@ -46,6 +47,9 @@</span><br><span> </span><br><span> #include <time.h></span><br><span> #include <sys/time.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/types.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/stat.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <fcntl.h></span><br><span> #include <errno.h></span><br><span> #include <pthread.h></span><br><span> </span><br><span>@@ -53,9 +57,14 @@</span><br><span> #include <osmocom/core/utils.h></span><br><span> #include <osmocom/core/logging.h></span><br><span> #include <osmocom/core/timer.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/write_queue.h></span><br><span> </span><br><span> #include <osmocom/vty/logging.h> /* for LOGGING_STR. */</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* maximum number of log statements we queue in file/stderr target write queue */</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOG_WQUEUE_LEN 1024</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> osmo_static_assert(_LOG_CTX_COUNT <= ARRAY_SIZE(((struct log_context*)NULL)->ctx),</span><br><span> enum_logging_ctx_items_fit_in_struct_log_context);</span><br><span> osmo_static_assert(_LOG_FLT_COUNT <= ARRAY_SIZE(((struct log_target*)NULL)->filter_data),</span><br><span>@@ -831,11 +840,33 @@</span><br><span> }</span><br><span> </span><br><span> #if (!EMBEDDED)</span><br><span style="color: hsl(120, 100%, 40%);">+/* output via buffered, blocking stdio streams */</span><br><span style="color: hsl(120, 100%, 40%);">+static void _file_output_stream(struct log_target *target, unsigned int level,</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *log)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(target->tgt_file.out);</span><br><span style="color: hsl(120, 100%, 40%);">+ fprintf(target->tgt_file.out, "%s", log);</span><br><span style="color: hsl(120, 100%, 40%);">+ fflush(target->tgt_file.out);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* output via non-blocking write_queue, doing internal buffering */</span><br><span> static void _file_output(struct log_target *target, unsigned int level,</span><br><span> const char *log)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- fprintf(target->tgt_file.out, "%s", log);</span><br><span style="color: hsl(0, 100%, 40%);">- fflush(target->tgt_file.out);</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int len = strlen(log);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(target->tgt_file.wqueue);</span><br><span style="color: hsl(120, 100%, 40%);">+ msg = msgb_alloc_c(target->tgt_file.wqueue, len, "log_file_msg");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* we simply enqueue the log message to a write queue here, to avoid any blocking</span><br><span style="color: hsl(120, 100%, 40%);">+ * writes on the output file. The write queue will tell us once the file is writable</span><br><span style="color: hsl(120, 100%, 40%);">+ * and call _file_wq_write_cb() */</span><br><span style="color: hsl(120, 100%, 40%);">+ memcpy(msg->data, log, len);</span><br><span style="color: hsl(120, 100%, 40%);">+ msgb_put(msg, len);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_wqueue_enqueue_quiet(target->tgt_file.wqueue, msg);</span><br><span> }</span><br><span> #endif</span><br><span> </span><br><span>@@ -884,6 +915,83 @@</span><br><span> return target;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* write-queue tells us we should write another msgb (log line) to the output fd */</span><br><span style="color: hsl(120, 100%, 40%);">+static int _file_wq_write_cb(struct osmo_fd *ofd, struct msgb *msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = write(ofd->fd, msgb_data(msg), msgb_length(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc != msgb_length(msg))</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! switch from blocking + buffered file output to non-blocking write-queue based output.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] target log target which we should switch</span><br><span style="color: hsl(120, 100%, 40%);">+ * \return 0 on success; 1 if already switched before; negative on error */</span><br><span style="color: hsl(120, 100%, 40%);">+int log_target_file_switch_to_wqueue(struct log_target *target)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_wqueue *wq;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!target)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -ENODEV;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* this only works for file/stderr targets */</span><br><span style="color: hsl(120, 100%, 40%);">+ switch (target->type) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case LOG_TGT_TYPE_FILE:</span><br><span style="color: hsl(120, 100%, 40%);">+ case LOG_TGT_TYPE_STDERR:</span><br><span style="color: hsl(120, 100%, 40%);">+ break;</span><br><span style="color: hsl(120, 100%, 40%);">+ default:</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!target->tgt_file.out) {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* target has already been switched over */</span><br><span style="color: hsl(120, 100%, 40%);">+ return 1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* we create a ~640kB sized talloc pool within the write-queue to ensure individual</span><br><span style="color: hsl(120, 100%, 40%);">+ * log lines (stored as msgbs) will not put result in malloc() calls, and also to</span><br><span style="color: hsl(120, 100%, 40%);">+ * reduce the OOM probability within logging, as the pool is already allocated */</span><br><span style="color: hsl(120, 100%, 40%);">+ wq = talloc_pooled_object(target, struct osmo_wqueue, LOG_WQUEUE_LEN,</span><br><span style="color: hsl(120, 100%, 40%);">+ LOG_WQUEUE_LEN*(sizeof(struct msgb)+512));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!wq)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_wqueue_init(wq, LOG_WQUEUE_LEN);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ fflush(target->tgt_file.out);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (target->type == LOG_TGT_TYPE_FILE) {</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = open(target->tgt_file.fname, O_WRONLY|O_APPEND|O_NONBLOCK, 0660);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(wq);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -errno;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = STDERR_FILENO;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ wq->bfd.fd = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ wq->bfd.when = OSMO_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+ wq->write_cb = _file_wq_write_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_fd_register(&wq->bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(wq);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ target->tgt_file.wqueue = wq;</span><br><span style="color: hsl(120, 100%, 40%);">+ target->output = _file_output;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* now that everything succeeded, we can finally close the old output stream */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (target->type == LOG_TGT_TYPE_FILE)</span><br><span style="color: hsl(120, 100%, 40%);">+ fclose(target->tgt_file.out);</span><br><span style="color: hsl(120, 100%, 40%);">+ target->tgt_file.out = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*! Create the STDERR log target</span><br><span> * \returns dynamically-allocated \ref log_target for STDERR */</span><br><span> struct log_target *log_target_create_stderr(void)</span><br><span>@@ -898,7 +1006,7 @@</span><br><span> </span><br><span> target->type = LOG_TGT_TYPE_STDERR;</span><br><span> target->tgt_file.out = stderr;</span><br><span style="color: hsl(0, 100%, 40%);">- target->output = _file_output;</span><br><span style="color: hsl(120, 100%, 40%);">+ target->output = _file_output_stream;</span><br><span> return target;</span><br><span> #else</span><br><span> return NULL;</span><br><span>@@ -906,11 +1014,11 @@</span><br><span> }</span><br><span> </span><br><span> #if (!EMBEDDED)</span><br><span style="color: hsl(0, 100%, 40%);">-/*! Create a new file-based log target</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Create a new file-based log target using buffered, blocking stream output</span><br><span> * \param[in] fname File name of the new log file</span><br><span> * \returns Log target in case of success, NULL otherwise</span><br><span> */</span><br><span style="color: hsl(0, 100%, 40%);">-struct log_target *log_target_create_file(const char *fname)</span><br><span style="color: hsl(120, 100%, 40%);">+struct log_target *log_target_create_file_stream(const char *fname)</span><br><span> {</span><br><span> struct log_target *target;</span><br><span> </span><br><span>@@ -924,9 +1032,55 @@</span><br><span> log_target_destroy(target);</span><br><span> return NULL;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+ target->output = _file_output_stream;</span><br><span style="color: hsl(120, 100%, 40%);">+ target->tgt_file.fname = talloc_strdup(target, fname);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ return target;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Create a new file-based log target using non-blocking write_queue</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] fname File name of the new log file</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns Log target in case of success, NULL otherwise</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct log_target *log_target_create_file(const char *fname)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct log_target *target;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_wqueue *wq;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ target = log_target_create();</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!target)</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ target->type = LOG_TGT_TYPE_FILE;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* we create a ~640kB sized talloc pool within the write-queue to ensure individual</span><br><span style="color: hsl(120, 100%, 40%);">+ * log lines (stored as msgbs) will not put result in malloc() calls, and also to</span><br><span style="color: hsl(120, 100%, 40%);">+ * reduce the OOM probability within logging, as the pool is already allocated */</span><br><span style="color: hsl(120, 100%, 40%);">+ wq = talloc_pooled_object(target, struct osmo_wqueue, LOG_WQUEUE_LEN,</span><br><span style="color: hsl(120, 100%, 40%);">+ LOG_WQUEUE_LEN*(sizeof(struct msgb)+512));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!wq) {</span><br><span style="color: hsl(120, 100%, 40%);">+ log_target_destroy(target);</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_wqueue_init(wq, LOG_WQUEUE_LEN);</span><br><span style="color: hsl(120, 100%, 40%);">+ wq->bfd.fd = open(fname, O_WRONLY|O_APPEND|O_NONBLOCK, 0660);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (wq->bfd.fd < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(wq);</span><br><span style="color: hsl(120, 100%, 40%);">+ log_target_destroy(target);</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ wq->bfd.when = OSMO_FD_WRITE;</span><br><span style="color: hsl(120, 100%, 40%);">+ wq->write_cb = _file_wq_write_cb;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_fd_register(&wq->bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(wq);</span><br><span style="color: hsl(120, 100%, 40%);">+ log_target_destroy(target);</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ target->tgt_file.wqueue = wq;</span><br><span> target->output = _file_output;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span> target->tgt_file.fname = talloc_strdup(target, fname);</span><br><span> </span><br><span> return target;</span><br><span>@@ -966,6 +1120,7 @@</span><br><span> * \param[in] target log target to unregister, close and delete */</span><br><span> void log_target_destroy(struct log_target *target)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_wqueue *wq;</span><br><span> </span><br><span> /* just in case, to make sure we don't have any references */</span><br><span> log_del_target(target);</span><br><span>@@ -973,10 +1128,20 @@</span><br><span> #if (!EMBEDDED)</span><br><span> switch (target->type) {</span><br><span> case LOG_TGT_TYPE_FILE:</span><br><span style="color: hsl(0, 100%, 40%);">- if (target->tgt_file.out == NULL)</span><br><span style="color: hsl(0, 100%, 40%);">- break;</span><br><span style="color: hsl(0, 100%, 40%);">- fclose(target->tgt_file.out);</span><br><span style="color: hsl(0, 100%, 40%);">- target->tgt_file.out = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (target->tgt_file.out) {</span><br><span style="color: hsl(120, 100%, 40%);">+ fclose(target->tgt_file.out);</span><br><span style="color: hsl(120, 100%, 40%);">+ target->tgt_file.out = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ wq = target->tgt_file.wqueue;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (wq) {</span><br><span style="color: hsl(120, 100%, 40%);">+ close(wq->bfd.fd);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fd_unregister(&wq->bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_wqueue_clear(wq);</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free(wq);</span><br><span style="color: hsl(120, 100%, 40%);">+ target->tgt_file.wqueue = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ talloc_free((void *)target->tgt_file.fname);</span><br><span style="color: hsl(120, 100%, 40%);">+ target->tgt_file.fname = NULL;</span><br><span> break;</span><br><span> #ifdef HAVE_SYSLOG_H</span><br><span> case LOG_TGT_TYPE_SYSLOG:</span><br><span>@@ -997,13 +1162,33 @@</span><br><span> * \returns 0 in case of success; negative otherwise */</span><br><span> int log_target_file_reopen(struct log_target *target)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- fclose(target->tgt_file.out);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_wqueue *wq;</span><br><span style="color: hsl(120, 100%, 40%);">+ int rc;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- target->tgt_file.out = fopen(target->tgt_file.fname, "a");</span><br><span style="color: hsl(0, 100%, 40%);">- if (!target->tgt_file.out)</span><br><span style="color: hsl(0, 100%, 40%);">- return -errno;</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(target->type == LOG_TGT_TYPE_FILE || target->type == LOG_TGT_TYPE_STDERR);</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(target->tgt_file.out || target->tgt_file.wqueue);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- /* we assume target->output already to be set */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (target->tgt_file.out) {</span><br><span style="color: hsl(120, 100%, 40%);">+ fclose(target->tgt_file.out);</span><br><span style="color: hsl(120, 100%, 40%);">+ target->tgt_file.out = fopen(target->tgt_file.fname, "a");</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!target->tgt_file.out)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -errno;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ wq = target->tgt_file.wqueue;</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_fd_unregister(&wq->bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (wq->bfd.fd >= 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ close(wq->bfd.fd);</span><br><span style="color: hsl(120, 100%, 40%);">+ wq->bfd.fd = -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = open(target->tgt_file.fname, O_WRONLY|O_APPEND|O_NONBLOCK, 0660);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return -errno;</span><br><span style="color: hsl(120, 100%, 40%);">+ wq->bfd.fd = rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_fd_register(&wq->bfd);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+ return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span> </span><br><span> return 0;</span><br><span> }</span><br><span>diff --git a/src/select.c b/src/select.c</span><br><span>index 496beea..17f409f 100644</span><br><span>--- a/src/select.c</span><br><span>+++ b/src/select.c</span><br><span>@@ -38,6 +38,7 @@</span><br><span> #include <osmocom/core/logging.h></span><br><span> #include <osmocom/core/talloc.h></span><br><span> #include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/application.h></span><br><span> </span><br><span> #include "../config.h"</span><br><span> </span><br><span>@@ -277,6 +278,9 @@</span><br><span> osmo_panic("You cannot use the 'select' volatile "</span><br><span> "context if you don't use osmo_select_main_ctx()!\n");</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We now know this application is using osmo_select_main() and hence can switch the stderr</span><br><span style="color: hsl(120, 100%, 40%);">+ * log target from buffered, stream based I/O to non-blocking write-queue */</span><br><span style="color: hsl(120, 100%, 40%);">+ log_target_file_switch_to_wqueue(osmo_stderr_target);</span><br><span> #endif</span><br><span> return rc;</span><br><span> }</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/libosmocore/+/20296">change 20296</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/libosmocore/+/20296"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: libosmocore </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Ia58fd78535c41b3da3aeb7733aadc785ace610da </div>
<div style="display:none"> Gerrit-Change-Number: 20296 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>