logging: Change stderr + file target to use non-blocking write

So far, we used blocking, buffered fwrite() to write to stderr
and file targets.  This causes problems if there are [slow] consumers
causing delays, such as gnome-terminal (when the program is started
interactively) or systemd/journald (where we observe 64..128ms blocks on
stderr).

This patch introduces stderr/file based logging via write_queue
and osmo_select_main(), i.e. switch from glibc-buffered, blocking
to internally buffered, non-blocking writes.

* when osmo_stderr_target is created via application.c, we create it
  in blocking stream mode for backwards compatibility, particularly
  for [smaller] programs that don't use osmo_select_main()

* when the VTY code encounters 'log stderr' or 'log file FILENAME',
  we switch that respective target to non-blocking write-queue mode,
  as this means the application is in fact using osmo_select_main()

* The config file can now state 'log stderr blocking-io' or
  'log file FILENAME blocking-io' to explicitly enforce using blocking
  stream based I/O

* The application can at any time use API functions to switch either way

Closes: OS#4311
Change-Id: Ia58fd78535c41b3da3aeb7733aadc785ace610da
diff --git a/include/osmocom/core/logging.h b/include/osmocom/core/logging.h
index 343f976..a554adc 100644
--- a/include/osmocom/core/logging.h
+++ b/include/osmocom/core/logging.h
@@ -297,8 +297,11 @@
 
 	union {
 		struct {
+			/* direct, blocking output via stdio */
 			FILE *out;
 			const char *fname;
+			/* indirect output via write_queue and osmo_select_main() */
+			struct osmo_wqueue *wqueue;
 		} tgt_file;
 
 		struct {
@@ -408,6 +411,8 @@
 struct log_target *log_target_create_systemd(bool raw);
 void log_target_systemd_set_raw(struct log_target *target, bool raw);
 int log_target_file_reopen(struct log_target *tgt);
+int log_target_file_switch_to_stream(struct log_target *tgt);
+int log_target_file_switch_to_wqueue(struct log_target *tgt);
 int log_targets_reopen(void);
 
 void log_add_target(struct log_target *target);