<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>