1 /*------------------------------------------------------------------------------
2  *
3  * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4  * The YADIFA TM software product is provided under the BSD 3-clause license:
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *        * Redistributions in binary form must reproduce the above copyright
13  *          notice, this list of conditions and the following disclaimer in the
14  *          documentation and/or other materials provided with the distribution.
15  *        * Neither the name of EURid nor the names of its contributors may be
16  *          used to endorse or promote products derived from this software
17  *          without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  *------------------------------------------------------------------------------
32  *
33  */
34 
35 /** @defgroup logger Logging functions
36  *  @ingroup dnscore
37  *  @brief
38  *
39  *
40  *
41  * @{
42  *
43  *----------------------------------------------------------------------------*/
44 
45 #include "dnscore/dnscore-config.h"
46 
47 #if HAS_PTHREAD_SETNAME_NP
48 #if DEBUG
49 #define _GNU_SOURCE 1
50 #endif
51 #endif
52 
53 #include <stdio.h>
54 #include <stdlib.h>
55 
56 #include <time.h>
57 #include <signal.h>
58 #include <sys/types.h>
59 #include <sys/time.h>
60 #include <unistd.h>
61 #include <stddef.h>
62 
63 #include <dnscore/thread.h>
64 #include <sys/mman.h>
65 
66 #include "dnscore/logger_handle.h"
67 #include "dnscore/logger_channel_stream.h"
68 #include "dnscore/ptr_vector.h"
69 #include "dnscore/zalloc.h"
70 
71 #include "dnscore/file_output_stream.h"
72 #include "dnscore/file_input_stream.h"
73 #include "dnscore/bytearray_output_stream.h"
74 
75 #include "dnscore/format.h"
76 #include "dnscore/dnscore.h"
77 #include "dnscore/process.h"
78 
79 #include "dnscore/async.h"
80 
81 #include "dnscore/ptr_set.h"
82 #include "dnscore/thread_pool.h"
83 
84 #if HAS_SHARED_QUEUE_SUPPORT
85 #include "dnscore/shared-circular-buffer.h"
86 #include "dnscore/shared-heap.h"
87 #include "dnscore/shared-heap-bytearray-output-stream.h"
88 #else
89 #include "dnscore/bytezarray_output_stream.h"
90 #include "dnscore/threaded_queue.h"
91 #include "dnscore/ipc.h"
92 #endif
93 
94 #include "dnscore/buffer_output_stream.h"
95 #include "dnscore/buffer_input_stream.h"
96 
97 #define LOGGER_HANDLE_TAG 0x4c444e48474f4c /* LOGHNDL */
98 #define LOGCHAN_TAG 0x4e414843474f4c /* LOGCHAN */
99 
100 // If the logger thread queues a log message, and the log queue is full (ie: because the disk is full) a dead-lock may ensue.
101 // So queued-logging is to be avoided in the logger thread
102 // That being said, DEBUG_LOG_HANDLER and DEBUG_LOG_MESSAGES may trigger this issue as it is a debug, dev-only, feature.
103 
104 #if DNSCORE_HAS_LOG_THREAD_TAG
105 void thread_tag_push_tags();
106 #endif
107 
108 #define DEBUG_LOG_HANDLER 0     // can be: 0 1 2, don't use for production
109 #define DEBUG_LOG_MESSAGES 0
110 #define DEBUG_LOG_REGISTRATIONS 0
111 
112 #if DEBUG_LOG_MESSAGES
113 # pragma message("DEBUG_LOG_MESSAGES") // the space after the '#' is to ignore it on #pragma search
114 #endif
115 
116 #define COLUMN_SEPARATOR " | "
117 #define COLUMN_SEPARATOR_SIZE 3
118 
119 #define MODULE_MSG_HANDLE g_system_logger
120 
121 #define LOGRMSG_TAG 0x47534d52474f4c
122 #define LOGRTEXT_TAG 0x5458455452474f4c
123 
124 struct logger_handle;
125 
126 #define LOGGER_MESSAGE_TYPE_TEXT                        0 // send a text to output
127 #define LOGGER_MESSAGE_TYPE_STOP                        1 // stop the service
128 #define LOGGER_MESSAGE_TYPE_CHANNEL_FLUSH_ALL           2 // flush all channels
129 #define LOGGER_MESSAGE_TYPE_CHANNEL_REOPEN_ALL          3 // reopen all channels
130 #define LOGGER_MESSAGE_TYPE_CHANNEL_CLOSE_ALL           4 // close all channels
131 #define LOGGER_MESSAGE_TYPE_CHANNEL_SINK_ALL            5 // sink all channels
132 #define LOGGER_MESSAGE_TYPE_IGNORE                      6 // no operation
133 
134 #define LOGGER_MESSAGE_TYPE_CHANNEL_GET_USAGE_COUNT     7 // grabs the number of uses of the channel, or -1 if not registered
135 #define LOGGER_MESSAGE_TYPE_CHANNEL_REGISTER            8 // register a new channel
136 #define LOGGER_MESSAGE_TYPE_CHANNEL_UNREGISTER          9 // unregister a channel
137 
138 #define LOGGER_MESSAGE_TYPE_HANDLE_CREATE              10 // open a new handle
139 #define LOGGER_MESSAGE_TYPE_HANDLE_CLOSE               11 // close a handle
140 #define LOGGER_MESSAGE_TYPE_HANDLE_NAME_ADD_CHANNEL    12 // add a channel to a handle identified by its name
141 #define LOGGER_MESSAGE_TYPE_HANDLE_NAME_REMOVE_CHANNEL 13 // remove a channel from a handle identified by its name
142 #define LOGGER_MESSAGE_TYPE_HANDLE_NAME_COUNT_CHANNELS 14 // return the number of channels linked to this logger
143 
144 #define LOGGER_MESSAGE_TYPE_THREAD_SET_TAG             15 // sets the tag for a thread ( + pid)
145 #define LOGGER_MESSAGE_TYPE_THREAD_CLEAR_TAG           16 // clears the tag for a thread ( + pid)
146 
147 #define LOGGER_DISPATCHED_THREAD_STOPPED    0
148 #define LOGGER_DISPATCHED_THREAD_STARTED    1
149 #define LOGGER_DISPATCHED_THREAD_READY      2
150 #define LOGGER_DISPATCHED_THREAD_STOPPING   3
151 
152 #define LOGGER_MESSAGE_SINK_FAKE ((logger_message*) 1)
153 
154 #define LOGGER_HANDLE_COUNT_MAX 16
155 #define LOGGER_HANDLE_SHARED_TABLE_SIZE (((sizeof(logger_handle) + 63) & ~63) * LOGGER_HANDLE_COUNT_MAX)
156 
157 static smp_int logger_thread_state = SMP_INT_INITIALIZER;
158 
159 struct logger_handle LOGGER_HANDLE_SINK_;
160 
161 struct logger_handle *LOGGER_HANDLE_SINK_PTR = &LOGGER_HANDLE_SINK_;
162 
163 static logger_handle *g_logger_handle_shared_table = NULL;
164 
165 struct logger_handle LOGGER_HANDLE_SINK_ =
166 {
167     {0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U},
168     {
169         PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY,
170         PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY,
171         PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY,
172         PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY, PTR_VECTOR_EMPTY
173     },
174     "SINK",
175     "sink",
176     4,
177     &LOGGER_HANDLE_SINK_PTR
178 #if DEBUG
179     , LOGGER_HANDLE_MAGIC_CHECK
180 #endif
181     };
182 
183 struct logger_message_text_s
184 {
185     u8  type;                       //  0  0
186     u8  level;                      //
187     u16 flags;                      //
188     u16 text_length;                //
189     u16 text_buffer_length;         // align 64
190     struct logger_handle *handle;   //  8  8
191 
192     u8 *text;                       // 12 16
193 
194 #if SIZEOF_TIMEVAL <= 8
195     struct timeval tv;              // 16 24
196 #else
197     s64 timestamp;
198 #endif
199 
200     const u8* prefix;               // 24 32
201     u16 prefix_length;              // 28 40
202 #if !HAS_SHARED_QUEUE_SUPPORT
203     s16 rc;                         // 30 42   reference count for the repeats
204 
205 #if DEBUG || HAS_LOG_PID
206     pid_t pid;                      // 32 44
207 #endif
208 #endif
209 
210 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
211     thread_t thread_id;            // 36 48
212 #endif
213                                     // 40 56
214 };
215 
216 struct logger_message_channel_flush_all_s
217 {
218     u8 type;
219     u8 val8;
220     u16 val16;
221     u32 val32;  // align 64
222 
223     async_wait_s *aw;
224 
225     thread_t tid;  // only used for debugging purposes
226 };
227 
228 struct logger_message_channel_reopen_all_s
229 {
230     u8 type;
231     u8 val8;
232     u16 val16;
233     u32 val32;  // align 64
234 
235     async_wait_s *aw;
236 };
237 
238 struct logger_message_channel_sink_all_s
239 {
240     u8 type;
241     u8 val8;
242     u16 val16;
243     u32 val32;  // align 64
244 
245     async_wait_s *aw;
246 };
247 
248 struct logger_message_channel_get_usage_count_s
249 {
250     u8 type;
251     u8 val8;
252     u16 val16;
253     u32 val32;  // align 64
254 
255     async_wait_s *aw;
256     const char* channel_name;
257     s32 *countp;
258 };
259 
260 struct logger_message_channel_register_s
261 {
262     u8 type;
263     u8 val8;
264     u16 val16;
265     u32 val32;  // align 64
266 
267     async_wait_s *aw;
268     const char* channel_name;
269     struct logger_channel *channel;
270 };
271 
272 struct logger_message_channel_unregister_s
273 {
274     u8 type;
275     u8 val8;
276     u16 val16;
277     u32 val32;  // align 64
278 
279     async_wait_s *aw;
280     const char* channel_name;
281 };
282 
283 /// @note no need for reopen
284 
285 struct logger_message_stop_s
286 {
287     u8 type;
288     u8 val8;
289     u16 val16;
290     u32 val32;  // align 64
291 
292     async_wait_s *aw;
293 };
294 
295 /// @note no need for ignore
296 
297 struct logger_message_handle_create_s
298 {
299     u8 type;
300     u8 val8;
301     u16 val16;
302     u32 val32;  // align 64
303 
304     async_wait_s *aw;
305     const char *logger_name;
306     logger_handle **handle_holder;
307 };
308 
309 struct logger_message_handle_close_s
310 {
311     u8 type;
312     u8 val8;
313     u16 val16;
314     u32 val32;  // align 64
315 
316     async_wait_s *aw;
317     const char *logger_name;
318 };
319 
320 struct logger_message_handle_add_channel_s
321 {
322     u8 type;
323     u8 val8;
324     u16 val16;
325     u32 val32;  // align 64
326 
327     async_wait_s *aw;
328     const char *logger_name;
329     const char *channel_name;
330     u16 level;
331 };
332 
333 struct logger_message_handle_remove_channel_s
334 {
335     u8 type;
336     u8 val8;
337     u16 val16;
338     u32 val32;  // align 64
339 
340     async_wait_s *aw;
341     const char *logger_name;
342     const char *channel_name;
343 };
344 
345 struct logger_message_handle_count_channels_s
346 {
347     u8 type;
348     u8 val8;
349     u16 val16;
350     u32 val32;  // align 64
351 
352     async_wait_s *aw;
353     const char *logger_name;
354     s32 *countp;
355 };
356 
357 #if DNSCORE_HAS_LOG_THREAD_TAG
358 
359 struct logger_message_thread_set_tag_s
360 {
361     u8 type;
362     u8 val8;
363     u16 val16;
364     u32 val32;  // align 64
365     async_wait_s *aw;
366     char tag[THREAD_TAG_SIZE];
367     thread_t tid;
368 };
369 
370 struct logger_message_thread_clear_tag_s
371 {
372     u8 type;
373     u8 val8;
374     u16 val16;
375     u32 val32;  // align 64
376     async_wait_s *aw;
377     thread_t tid;
378 };
379 
380 #endif
381 
382 struct logger_message
383 {
384 #if HAS_SHARED_QUEUE_SUPPORT
385     u8 reserved_for_the_queue;
386     u8 align0;
387     u16 align1;
388     pid_t pid;                      //   4 4
389 #endif
390     union
391     {
392         u8 type;
393         struct logger_message_text_s text;
394         struct logger_message_stop_s stop;
395         // no specific data for ignore
396         struct logger_message_channel_flush_all_s channel_flush_all;
397         struct logger_message_channel_reopen_all_s channel_reopen_all;
398         struct logger_message_channel_sink_all_s channel_sink_all;
399         struct logger_message_channel_get_usage_count_s get_usage_count;
400         struct logger_message_channel_register_s channel_register;
401         struct logger_message_channel_unregister_s channel_unregister;
402         struct logger_message_handle_create_s handle_create;
403         struct logger_message_handle_close_s handle_close;
404         struct logger_message_handle_add_channel_s handle_add_channel;
405         struct logger_message_handle_remove_channel_s handle_remove_channel;
406         struct logger_message_handle_count_channels_s handle_count_channels;
407 #if DNSCORE_HAS_LOG_THREAD_TAG
408         struct logger_message_thread_set_tag_s thread_set_tag;
409         struct logger_message_thread_clear_tag_s thread_clear_tag;
410 #endif
411     };
412 };
413 
414 typedef struct logger_message logger_message;
415 
416 /// tree set initialised empty with a comparator for ASCIIZ char* keys
417 static ptr_set logger_channels = PTR_SET_ASCIIZ_EMPTY;
418 static ptr_vector logger_handles = PTR_VECTOR_EMPTY;
419 static mutex_t logger_mutex = MUTEX_INITIALIZER;
420 
421 #if HAS_SHARED_QUEUE_SUPPORT
422 struct shared_circular_buffer* logger_shared_queue = NULL;
423 #else
424 static threaded_queue logger_commit_queue = THREADED_QUEUE_EMPTY;
425 #endif
426 
427 struct logger_shared_space_s
428 {
429     logger_message *_logger_sink_request_message;
430     logger_message *_logger_reopen_request_message;
431 };
432 
433 typedef struct logger_shared_space_s logger_shared_space_t;
434 
435 static logger_shared_space_t logger_shared_space_null = {NULL, NULL};
436 
437 static logger_shared_space_t *logger_shared_space = &logger_shared_space_null;
438 
439 static thread_t logger_thread_id = 0;
440 static pid_t logger_thread_pid = -1;
441 static u32 exit_level = MSG_CRIT;
442 static const char acewnid[16 + 1] = "!ACEWNID1234567";
443 
444 static volatile pid_t logger_handle_owner_pid = 0;
445 static volatile bool _logger_started = FALSE;
446 static volatile bool _logger_initialised = FALSE;
447 #if !HAS_SHARED_QUEUE_SUPPORT
448 static volatile bool logger_is_client = FALSE;
449 #endif
450 static volatile bool logger_queue_initialised = FALSE;
451 static volatile bool logger_handle_init_done = FALSE;
452 static volatile u8 logger_level = MSG_ALL;
453 static u8 logger_shared_heap_id = 0;
454 
logger_initialised()455 static bool logger_initialised()
456 {
457     mutex_lock(&logger_mutex);
458     bool ret = _logger_initialised;
459     mutex_unlock(&logger_mutex);
460     return ret;
461 }
462 
logger_started()463 static bool logger_started()
464 {
465     mutex_lock(&logger_mutex);
466     bool ret = _logger_started;
467     mutex_unlock(&logger_mutex);
468     return ret;
469 }
470 
logger_initialised_and_started()471 static bool logger_initialised_and_started()
472 {
473     mutex_lock(&logger_mutex);
474     bool ret = _logger_started && _logger_initialised;
475     mutex_unlock(&logger_mutex);
476     return ret;
477 }
478 
479 #if DEBUG_LOG_MESSAGES
480 static smp_int allocated_messages_count = SMP_INT_INITIALIZER;
481 static time_t allocated_messages_count_stats_time = 0;
482 #endif
483 
logger_handle_trigger_emergency_shutdown()484 static void logger_handle_trigger_emergency_shutdown()
485 {
486     flusherr();
487     logger_flush();
488     abort();
489 }
490 
491 /*******************************************************************************
492  *
493  * Logger message functions
494  *
495  *******************************************************************************/
496 
497 static inline logger_message*
logger_message_alloc()498 logger_message_alloc()
499 {
500 #ifdef NDEBUG
501     size_t sizeof_logger_message = sizeof(logger_message);
502     assert(sizeof_logger_message <= 64);
503     (void)sizeof_logger_message;
504 #endif
505     logger_message* message;
506 #if HAS_SHARED_QUEUE_SUPPORT
507     message = (logger_message*)shared_circular_buffer_prepare_enqueue(logger_shared_queue);
508 #if DEBUG
509     memset(((u8*)message) + 1, 'Q', sizeof(logger_message) - 1);
510 #endif
511 #else
512     ZALLOC_OBJECT_OR_DIE( message, logger_message, LOGRMSG_TAG);
513 #if DEBUG
514     memset(message, 'Q', sizeof(logger_message));
515 #endif
516 #endif
517 
518 #if DEBUG_LOG_MESSAGES
519     smp_int_inc(&allocated_messages_count);
520 #endif
521 
522     return message;
523 }
524 
525 #if HAS_SHARED_QUEUE_SUPPORT
526 static inline logger_message*
logger_message_try_alloc()527 logger_message_try_alloc()
528 {
529     logger_message* message;
530     message = (logger_message*)shared_circular_buffer_try_prepare_enqueue(logger_shared_queue);
531 #if DEBUG
532     if(message != NULL)
533     {
534         memset(&((u8*)message)[1], 'q', sizeof(logger_message) - 1);
535     }
536 #endif
537     return message;
538 }
539 #endif
540 
541 #if !HAS_SHARED_QUEUE_SUPPORT
542 static inline void
logger_message_free(logger_message * message)543 logger_message_free(logger_message *message)
544 {
545     ZFREE_OBJECT(message);
546 
547 #if DEBUG_LOG_MESSAGES
548     smp_int_dec(&allocated_messages_count);
549 #endif
550 }
551 #endif
552 
553 static inline void
logger_message_post(void * message)554 logger_message_post(void* message)
555 {
556 #if HAS_SHARED_QUEUE_SUPPORT
557     shared_circular_buffer_commit_enqueue(logger_shared_queue, message);
558 #else
559     threaded_queue_enqueue(&logger_commit_queue, message);
560 #endif
561 }
562 
563 /*******************************************************************************
564  *
565  * Logger handle functions
566  *
567  *******************************************************************************/
568 
569 static ya_result logger_service_handle_remove_channel(logger_handle *handle, const char *channel_name);
570 static void logger_service_handle_remove_all_channel(logger_handle *handle);
571 
572 /**
573  * Returns true iff the current thread is the logger.
574  *
575  * @return true iff the current thread is the logger.
576  */
577 
578 bool
logger_is_self()579 logger_is_self()
580 {
581     return logger_thread_id == thread_self();
582 }
583 
584 #if 0
585 static int
586 logger_handle_compare(const void* a, const void* b)
587 {
588     logger_handle* ha = (logger_handle*)a;
589     logger_handle* hb = (logger_handle*)b;
590 
591     if(ha == hb)
592     {
593         return 0;
594     }
595 
596     return strcmp(ha->name, hb->name);
597 }
598 #endif
599 
600 static int
logger_handle_compare_match(const void * key,const void * value)601 logger_handle_compare_match(const void* key, const void* value)
602 {
603     const char* hkey = (const char*)key;
604     const logger_handle* hvalue = (const logger_handle*)value;
605 
606     return strcmp(hkey, hvalue->name);
607 }
608 
609 static void
logger_handle_free(void * ptr)610 logger_handle_free(void* ptr)
611 {
612     logger_handle* handle = (logger_handle*)ptr;
613 
614 #if DEBUG_LOG_HANDLER
615     debug_osformatln(termout, "logger_handle_free(%s@%p)", handle->name, ptr);
616     flushout();
617 #endif
618 
619     logger_service_handle_remove_all_channel(handle);
620 
621     for(u8 lvl = 0; lvl < MSG_LEVEL_COUNT; lvl++)
622     {
623         ptr_vector_destroy(&handle->channels[lvl]);
624     }
625 
626     if(handle->global_reference == NULL)
627     {
628         debug_osformatln(termerr, "bug: logger handle '%s' must be initialised to LOGGER_HANDLE_SINK but is set to NULL", handle->name);
629         flusherr();
630         abort();
631         return;
632     }
633 
634     if(*handle->global_reference != LOGGER_HANDLE_SINK)
635     {
636         *handle->global_reference = LOGGER_HANDLE_SINK;
637     }
638 
639 #if DEBUG
640     memset((char*)handle->formatted_name, 0xfe, strlen(handle->formatted_name));
641 #endif
642 #if !HAS_SHARED_QUEUE_SUPPORT
643     free((char*)handle->formatted_name);
644 #endif
645 #if DEBUG
646     memset((char*)handle->name, 0xfe, strlen(handle->name));
647 #endif
648 #if !HAS_SHARED_QUEUE_SUPPORT
649     free((char*)handle->name);
650 #endif
651 #if DEBUG
652     memset(handle, 0xfe, sizeof(logger_handle));
653 #endif
654 #if HAS_SHARED_QUEUE_SUPPORT
655     //shared_heap_free(handle);
656 #else
657     free(handle);
658 #endif
659 }
660 
661 /*******************************************************************************
662  *
663  * Logger channel functions
664  *
665  *******************************************************************************/
666 
667 #define LOGGER_CHANNEL_COUNT_MAX 128
668 
669 static logger_channel* logger_channel_shared_memory = NULL;
670 static size_t logger_channel_shared_memory_avail = 0;
671 static u8 logger_channel_allocated[LOGGER_CHANNEL_COUNT_MAX/8];
672 
logger_channel_shared_memory_size()673 static inline size_t logger_channel_shared_memory_size()
674 {
675     return (LOGGER_CHANNEL_COUNT_MAX * sizeof(logger_channel) + 0xfff) & ~0xfff;
676 }
677 
678 logger_channel*
logger_channel_alloc()679 logger_channel_alloc()
680 {
681     if(logger_handle_owner_pid == 0) // don't know our pid yet
682     {
683         logger_handle_owner_pid = getpid_ex(); // update it, set us as the logger process
684     }
685     else if(logger_handle_owner_pid != getpid_ex()) // if we are not the logger process, this is very wrong
686     {
687         // no can do
688         debug_osformatln(termerr, "logger_channel_alloc() cannot be called from this process");
689         return NULL;
690     }
691 
692     if(logger_channel_shared_memory == NULL)
693     {
694         void *ptr = mmap(NULL, logger_channel_shared_memory_size(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
695 
696         if(ptr == MAP_FAILED)
697         {
698             int err = ERRNO_ERROR;
699             debug_osformatln(termerr, "logger_channel_alloc() shared memory allocation failed: %r", err);
700             return NULL;
701         }
702 
703         yassert(ptr != NULL);
704 
705         logger_channel_shared_memory = (logger_channel*)ptr;
706 
707         memset(logger_channel_shared_memory, 0U,  logger_channel_shared_memory_size());
708         logger_channel_shared_memory_avail = logger_channel_shared_memory_size() / sizeof(logger_channel);
709 
710         memset(logger_channel_allocated, 0U,  sizeof(logger_channel_allocated));
711     }
712 
713     logger_channel* chan;
714 
715 #if DEBUG_LOG_HANDLER
716     debug_osformatln(termout, "logger_channel_alloc()");
717     flushout();
718 #endif
719 
720     if(logger_channel_shared_memory_avail == 0)
721     {
722         return NULL;
723     }
724 
725     chan = NULL;
726 
727     for(int i = 0; i < LOGGER_CHANNEL_COUNT_MAX/8; ++i)
728     {
729         if(logger_channel_allocated[i] != MAX_U8)
730         {
731             for(int j = 0; j < 8; ++j)
732             {
733                 if((logger_channel_allocated[i] & (1 << j)) == 0)
734                 {
735                     logger_channel_allocated[i] |= 1 << j;
736                     chan = &logger_channel_shared_memory[(i << 3) + j];
737 
738                     chan->data = NULL;
739                     chan->vtbl = NULL;
740 
741 #if !HAS_SHARED_QUEUE_SUPPORT
742                     /* dummy to avoid a NULL test */
743                     logger_message* last_message = logger_message_alloc();
744                     last_message->pid = getpid_ex();
745                     last_message->type = LOGGER_MESSAGE_TYPE_TEXT;
746                     ZALLOC_ARRAY_OR_DIE(u8*, last_message->text.text, 1, LOGRTEXT_TAG);
747                     *last_message->text.text = '\0';
748                     last_message->text.text_length = 1;
749                     last_message->text.text_buffer_length = 1;
750                     last_message->text.flags = 0;
751                     last_message->text.rc = 1;
752                     last_message->text.thread_id = thread_self();
753 
754                     chan->last_message = last_message;
755                     chan->last_message_count = 0;
756 #endif
757                     chan->linked_handles = 0;
758                     return chan;
759                 }
760             }
761         }
762     }
763 
764     return NULL;
765 }
766 
767 static void
logger_channel_free(logger_channel * channel)768 logger_channel_free(logger_channel *channel)
769 {
770     if((channel == NULL) || (channel < logger_channel_shared_memory))
771     {
772         return;
773     }
774 
775 #if DEBUG_LOG_HANDLER
776     debug_osformatln(termout, "logger_channel_free(%p), linked to %d", channel, channel->linked_handles);
777     flushout();
778 #endif
779 
780     size_t slot = (channel - logger_channel_shared_memory);
781     if(slot > (sizeof(logger_channel_allocated) * 8))
782     {
783         return;
784     }
785 
786     if((logger_channel_allocated[slot >> 3] & (1 << (slot & 7))) == 0)
787     {
788         return;
789     }
790 
791     assert(channel->linked_handles == 0); // don't yassert
792     assert(logger_handle_owner_pid == getpid_ex());
793 
794 #if !HAS_SHARED_QUEUE_SUPPORT
795     logger_message* last_message = channel->last_message;
796 
797     if(--last_message->text.rc == 0)
798     {
799         ZFREE_ARRAY(last_message->text.text, last_message->text.text_buffer_length);
800         logger_message_free(last_message);
801     }
802 #endif
803     if(channel->vtbl != NULL)
804     {
805         logger_channel_close(channel);
806         channel->vtbl = NULL;
807     }
808 
809     logger_channel_allocated[slot >> 3] &= ~(1 << (slot & 7));
810     ++logger_channel_shared_memory_avail;
811 }
812 
813 static logger_channel*
logger_service_channel_get(const char * channel_name)814 logger_service_channel_get(const char *channel_name)
815 {
816     logger_channel *channel = NULL;
817 
818     ptr_node *node = ptr_set_find(&logger_channels, channel_name);
819     if(node != NULL)
820     {
821         channel = (logger_channel*)node->value;
822     }
823 
824 #if DEBUG_LOG_HANDLER
825     debug_osformatln(termout, "logger_service_channel_get(%s) = %p", channel_name, channel);
826     flushout();
827 #endif
828 
829     return channel;
830 }
831 
832 static ya_result
logger_service_channel_register(const char * channel_name,logger_channel * channel)833 logger_service_channel_register(const char *channel_name, logger_channel *channel)
834 {
835 #if DEBUG_LOG_HANDLER
836     debug_osformatln(termout, "logger_service_channel_register(%s,%p)", channel_name, channel);
837     flushout();
838 #endif
839 
840     if(channel->linked_handles != 0)
841     {
842 #if DEBUG_LOG_HANDLER
843         debug_osformatln(termout, "logger_service_channel_register(%s,%p) ALREADY LINKED", channel_name, channel);
844         flushout();
845 #endif
846         return LOGGER_CHANNEL_HAS_LINKS;
847     }
848 
849     if(logger_service_channel_get(channel_name) != NULL)
850     {
851 #if DEBUG_LOG_HANDLER
852         debug_osformatln(termout, "logger_service_channel_register(%s,%p) NAME ALREADY USED", channel_name, channel);
853         flushout();
854 #endif
855         logger_channel_free(channel);
856         return LOGGER_CHANNEL_ALREADY_REGISTERED;
857     }
858 
859     ptr_node *node = ptr_set_insert(&logger_channels, strdup(channel_name));
860     node->value = channel;
861 
862     return SUCCESS;
863 }
864 
865 static ya_result
logger_service_channel_unregister(const char * channel_name)866 logger_service_channel_unregister(const char *channel_name)
867 {
868 #if DEBUG_LOG_HANDLER
869     debug_osformatln(termout, "logger_service_channel_unregister(%s)", channel_name);
870     flushout();
871 #endif
872 
873     logger_channel *channel;
874 
875     ptr_node *node = ptr_set_find(&logger_channels, channel_name);
876 
877     if(node == NULL)
878     {
879 #if DEBUG_LOG_HANDLER
880         debug_osformatln(termout, "logger_service_channel_unregister(%s) NAME NOT USED", channel_name);
881         flushout();
882 #endif
883         return LOGGER_CHANNEL_NOT_REGISTERED;
884     }
885 
886     channel = (logger_channel*)node->value;
887 
888     if(channel->linked_handles != 0)
889     {
890 #if DEBUG_LOG_HANDLER
891         debug_osformatln(termout, "logger_service_channel_unregister(%s) STILL LINKED", channel_name);
892         flushout();
893 #endif
894         return LOGGER_CHANNEL_HAS_LINKS;
895     }
896 
897     char *key = (char*)node->key;
898     ptr_set_delete(&logger_channels, channel_name);
899     free(key);
900 
901     // remove the channel from all the handles
902 
903     for(s32 i = 0; i < ptr_vector_size(&logger_handles); i++)
904     {
905         logger_handle *handle = (logger_handle*)ptr_vector_get(&logger_handles, i);
906         logger_service_handle_remove_channel(handle, channel_name);
907     }
908 
909     logger_channel_free(channel);
910 
911     return SUCCESS;
912 }
913 
914 static void
logger_service_channel_unregister_all()915 logger_service_channel_unregister_all()
916 {
917 #if DEBUG_LOG_HANDLER
918     debug_osformatln(termout, "logger_service_channel_unregister_all()");
919     flushout();
920 #endif
921 
922     // for all channels
923 
924     ptr_vector logger_channel_list = PTR_VECTOR_EMPTY;
925     ptr_vector logger_name_list = PTR_VECTOR_EMPTY;
926 
927     ptr_set_iterator iter;
928     ptr_set_iterator_init(&logger_channels, &iter);
929     while(ptr_set_iterator_hasnext(&iter))
930     {
931         ptr_node *node = ptr_set_iterator_next_node(&iter);
932 
933         logger_channel *channel = (logger_channel*)node->value;
934         char *channel_name = (char*)node->key;
935 
936         ptr_vector_append(&logger_name_list, channel_name);
937         ptr_vector_append(&logger_channel_list, channel);
938     }
939 
940     for(int i = 0; i <= ptr_vector_last_index(&logger_name_list); ++i)
941     {
942         char *channel_name = (char*)ptr_vector_get(&logger_name_list, i);
943 
944 #if DEBUG_LOG_HANDLER
945         logger_channel *channel = (logger_channel*)ptr_vector_get(&logger_channel_list, i);
946         debug_osformatln(termout, "logger_service_channel_unregister_all() : channel %s@%p", channel_name, channel);
947         flushout();
948 #endif
949 
950         // for all handles
951 
952         for(s32 i = 0; i <= ptr_vector_last_index(&logger_handles); i++)
953         {
954             logger_handle *handle = (logger_handle*)ptr_vector_get(&logger_handles, i);
955 
956 #if DEBUG_LOG_HANDLER
957             debug_osformatln(termout, "logger_service_channel_unregister_all() : channel %s@%p : handle %s@%p", channel_name, channel, handle->name, handle);
958             flushout();
959 #endif
960 
961             // remove channel from handle
962 
963             logger_service_handle_remove_channel(handle, channel_name);
964         }
965 
966 #if DEBUG_LOG_HANDLER
967             assert(channel->linked_handles == 0);
968 #endif
969     }
970 
971     for(int i = 0; i <= ptr_vector_last_index(&logger_name_list); ++i)
972     {
973         char *channel_name = (char*)ptr_vector_get(&logger_name_list, i);
974         logger_channel *channel = (logger_channel*)ptr_vector_get(&logger_channel_list, i);
975 
976         logger_channel_free(channel);
977         free(channel_name);
978     }
979 
980     ptr_set_destroy(&logger_channels);
981 
982     ptr_vector_destroy(&logger_channel_list);
983     ptr_vector_destroy(&logger_name_list);
984 }
985 
986 /**
987  * Used to find a channel in the channel array in a handle
988  */
989 
990 static int
logger_handle_channel_compare_match(const void * a,const void * b)991 logger_handle_channel_compare_match(const void *a, const void *b)
992 {
993     const logger_channel* channel_a = (const logger_channel*)a;
994     const logger_channel* channel_b = (const logger_channel*)b;
995 
996     if(channel_a == channel_b)
997     {
998         return 0;
999     }
1000 
1001     return 1;
1002 }
1003 
1004 /**
1005  * INTERNAL: used by the service
1006  */
1007 
1008 static logger_handle*
logger_service_handle_create(const char * name)1009 logger_service_handle_create(const char *name)
1010 {
1011 #if DEBUG_LOG_HANDLER
1012     debug_osformatln(termout, "[%i] logger_service_handle_create(%s)", getpid(), name);
1013     flushout();
1014 #endif
1015 
1016     size_t name_len = strlen(name);
1017 
1018     if(name_len > LOGGER_HANDLE_NAME_SIZE_MAX)
1019     {
1020 #if DEBUG_LOG_HANDLER
1021         debug_osformatln(termout, "[%i] logger_service_handle_create(%s) : name is too big", getpid(), name);
1022         flushout();
1023 #endif
1024         return NULL;
1025     }
1026 
1027     logger_handle* handle = (logger_handle*)ptr_vector_linear_search(&logger_handles, name, logger_handle_compare_match);
1028 
1029     if(handle == NULL)
1030     {
1031         s32 handle_index = ptr_vector_size(&logger_handles);
1032 
1033         assert(handle_index < LOGGER_HANDLE_COUNT_MAX);
1034 
1035         handle = &g_logger_handle_shared_table[handle_index];
1036 
1037         memcpy(handle->name, name, name_len + 1);
1038         memset(handle->formatted_name, ' ', LOGGER_HANDLE_FORMATTED_NAME_SIZE_MAX);
1039         memcpy(handle->formatted_name, name, MIN(name_len, LOGGER_HANDLE_FORMATTED_NAME_SIZE_MAX));
1040         handle->formatted_name[LOGGER_HANDLE_FORMATTED_NAME_SIZE_MAX] = '\0';
1041 
1042         handle->enabled = TRUE;
1043 
1044 #if DEBUG
1045         handle->magic_check = LOGGER_HANDLE_MAGIC_CHECK;
1046 #endif
1047         int i;
1048 
1049         for(i = 0; i < MSG_LEVEL_COUNT; i++)
1050         {
1051             handle->active[i] = 0;
1052             ptr_vector_init(&handle->channels[i]);
1053         }
1054 
1055         ptr_vector_append(&logger_handles, handle); // this is a collection to keep track of the handles, not their storage
1056     }
1057     else
1058     {
1059         if(handle->enabled)
1060         {
1061 #if DEBUG_LOG_HANDLER
1062             debug_osformatln(termerr, "[%i] logger_service_handle_create(%s) : handle already created at %p", getpid(), name, handle);
1063             flusherr();
1064 #endif
1065         }
1066         else
1067         {
1068             handle->enabled = TRUE;
1069         }
1070     }
1071 
1072 #if DEBUG_LOG_HANDLER
1073     debug_osformatln(termout, "[%i] logger_service_handle_create(%s) = %p", getpid(), name, handle);
1074     flushout();
1075 #endif
1076 
1077     return handle;
1078 }
1079 
1080 static void
logger_service_handle_close(const char * name)1081 logger_service_handle_close(const char *name)
1082 {
1083 #if DEBUG_LOG_HANDLER
1084     debug_osformatln(termout, "logger_service_handle_close(%s)", name);
1085     flushout();
1086 #endif
1087 
1088     //logger_handle* handle = (logger_handle*)ptr_vector_search(&logger_handles, name, logger_handle_compare_match);
1089     logger_handle* handle = (logger_handle*)ptr_vector_linear_search(&logger_handles, name, logger_handle_compare_match);
1090 
1091     if(handle != NULL)
1092     {
1093         if(!handle->enabled)
1094         {
1095             return;
1096         }
1097 
1098         if(*handle->global_reference != LOGGER_HANDLE_SINK)
1099         {
1100             *handle->global_reference = LOGGER_HANDLE_SINK; // but the handle will still exist, only disabled
1101         }
1102 
1103         // decrement references for all channels used
1104 
1105         memset(handle->active, 0, sizeof(handle->active));
1106 
1107         for(int lvl = 0; lvl < MSG_LEVEL_COUNT; lvl++)
1108         {
1109             for(s32 idx = 0; idx < ptr_vector_size(&handle->channels[lvl]); idx++)
1110             {
1111                 logger_channel *channel = (logger_channel*)ptr_vector_get(&handle->channels[lvl], idx);
1112                 ptr_vector_end_swap(&handle->channels[lvl], idx);
1113                 ptr_vector_pop(&handle->channels[lvl]);
1114                 channel->linked_handles--;
1115             }
1116 
1117             ptr_vector_destroy(&handle->channels[lvl]);
1118         }
1119 
1120         handle->enabled = FALSE;
1121     }
1122     // else the handle never existed
1123 }
1124 
1125 #if 0
1126 static void
1127 logger_service_handle_close_all()
1128 {
1129 }
1130 #endif
1131 
1132 static inline logger_handle*
logger_service_handle_get(const char * name)1133 logger_service_handle_get(const char *name)
1134 {
1135     logger_handle* handle = (logger_handle*)ptr_vector_linear_search(&logger_handles, name, logger_handle_compare_match);
1136 
1137     if((handle != NULL) && (!handle->enabled))
1138     {
1139         handle = NULL;
1140     }
1141 
1142     return handle;
1143 }
1144 
1145 /**
1146  * INTERNAL: used by the service
1147  */
1148 
1149 static ya_result
logger_service_handle_add_channel(logger_handle * handle,int level,const char * channel_name)1150 logger_service_handle_add_channel(logger_handle *handle, int level, const char *channel_name)
1151 {
1152 #if DEBUG_LOG_HANDLER
1153     debug_osformatln(termout, "logger_service_handle_add_channel(%s@%p, %x, %s)", handle->name, handle, level, channel_name);
1154     flushout();
1155 #endif
1156 
1157     assert(level >= 0 && level <= MSG_ALL_MASK);
1158 
1159     int lvl;
1160     int level_mask;
1161 
1162     logger_channel *channel = logger_service_channel_get(channel_name);
1163 
1164     if(channel == NULL)
1165     {
1166 #if DEBUG_LOG_HANDLER
1167         debug_osformatln(termout, "logger_service_handle_add_channel(%s@%p, %x, %s) UNKNOWN CHANNEL", handle->name, handle, level, channel_name);
1168         flushout();
1169 #endif
1170 
1171         return LOGGER_CHANNEL_NOT_REGISTERED;
1172     }
1173 
1174     // add the channel in every level required by the level mask
1175 
1176     for(lvl = 0U,  level_mask = 1; level_mask <= MSG_ALL_MASK; lvl++, level_mask <<= 1)
1177     {
1178         if((level & level_mask) != 0)
1179         {
1180             if(ptr_vector_linear_search(&handle->channels[lvl], channel, logger_handle_channel_compare_match) == NULL)
1181             {
1182                 ptr_vector_append(&handle->channels[lvl], channel);
1183                 channel->linked_handles++;
1184                 handle->active[lvl] = 1;
1185             }
1186         }
1187     }
1188 
1189     return SUCCESS;
1190 }
1191 
1192 static ya_result
logger_service_handle_remove_channel(logger_handle * handle,const char * channel_name)1193 logger_service_handle_remove_channel(logger_handle *handle, const char *channel_name)
1194 {
1195 #if DEBUG_LOG_HANDLER
1196     debug_osformatln(termout, "logger_service_handle_remove_channel(%s@%p, %s)", handle->name, handle, channel_name);
1197     flushout();
1198 #endif
1199 
1200     logger_channel *channel = logger_service_channel_get(channel_name);
1201     if(channel == NULL)
1202     {
1203 #if DEBUG_LOG_HANDLER
1204         debug_osformatln(termout, "logger_service_handle_remove_channel(%s@%p, %s) UNKNOWN CHANNEL", handle->name, handle, channel_name);
1205         flushout();
1206 #endif
1207 
1208         return LOGGER_CHANNEL_NOT_REGISTERED;
1209     }
1210 
1211     for(u8 lvl = 0; lvl <= MSG_ALL; lvl++)
1212     {
1213         s32 idx = ptr_vector_index_of(&handle->channels[lvl], channel, logger_handle_channel_compare_match);
1214 
1215         if(idx >= 0)
1216         {
1217             ptr_vector_end_swap(&handle->channels[lvl], idx);
1218             ptr_vector_pop(&handle->channels[lvl]);
1219             channel->linked_handles--;
1220 
1221             if(ptr_vector_isempty(&handle->channels[lvl]))
1222             {
1223                 handle->active[lvl] = 0;
1224             }
1225         }
1226     }
1227 
1228     return SUCCESS;
1229 }
1230 
1231 static void
logger_service_handle_remove_all_channel(logger_handle * handle)1232 logger_service_handle_remove_all_channel(logger_handle *handle)
1233 {
1234 #if DEBUG_LOG_HANDLER
1235     debug_osformatln(termout, "logger_service_handle_remove_all_channel(%s@%p)", handle->name, handle);
1236     flushout();
1237 #endif
1238     memset(handle->active, 0, sizeof(handle->active));
1239 
1240     for(u8 lvl = 0; lvl < MSG_LEVEL_COUNT; lvl++)
1241     {
1242         for(s32 idx = 0; idx < ptr_vector_size(&handle->channels[lvl]); idx++)
1243         {
1244             logger_channel *channel = (logger_channel*)ptr_vector_get(&handle->channels[lvl], idx);
1245             channel->linked_handles--;
1246         }
1247         ptr_vector_clear(&handle->channels[lvl]);
1248     }
1249 }
1250 
1251 static ya_result
logger_service_handle_count_channels(logger_handle * handle)1252 logger_service_handle_count_channels(logger_handle *handle)
1253 {
1254 #if DEBUG_LOG_HANDLER
1255     debug_osformatln(termout, "logger_service_handle_count_channels(%s@%p)", handle->name, handle);
1256     flushout();
1257 #endif
1258 
1259     s32 sum = 0;
1260 
1261     for(u8 lvl = 0; lvl <= MSG_ALL; lvl++)
1262     {
1263         sum += ptr_vector_size(&handle->channels[lvl]);
1264     }
1265 
1266     return sum;
1267 }
1268 
1269 /**
1270  * INTERNAL: used inside the service (2)
1271  */
1272 
1273 static void
logger_service_flush_all_channels()1274 logger_service_flush_all_channels()
1275 {
1276 #if DEBUG_LOG_HANDLER > 1
1277     debug_osformatln(termout, "logger_service_flush_all_channels()");
1278     flushout();
1279 #endif
1280 
1281     ptr_set_iterator iter;
1282     ptr_set_iterator_init(&logger_channels, &iter);
1283     while(ptr_set_iterator_hasnext(&iter))
1284     {
1285         ptr_node *node = ptr_set_iterator_next_node(&iter);
1286         logger_channel *channel = (logger_channel*)node->value;
1287         logger_channel_flush(channel);
1288     }
1289 }
1290 
1291 /**
1292  * INTERNAL: used inside the service (1)
1293  */
1294 
1295 static void
logger_service_reopen_all_channels()1296 logger_service_reopen_all_channels()
1297 {
1298 #if DEBUG_LOG_HANDLER
1299     debug_osformatln(termout, "logger_service_reopen_all_channels()");
1300     flushout();
1301 #endif
1302     ptr_set_iterator iter;
1303     ptr_set_iterator_init(&logger_channels, &iter);
1304     while(ptr_set_iterator_hasnext(&iter))
1305     {
1306         ptr_node *node = ptr_set_iterator_next_node(&iter);
1307         logger_channel *channel = (logger_channel*)node->value;
1308         ya_result return_code = logger_channel_reopen(channel);
1309 
1310         if(FAIL(return_code))
1311         {
1312             log_try_err("could not reopen logger channel '%s': %r", STRNULL((char*)node->key), return_code);
1313         }
1314     }
1315 }
1316 
1317 /**
1318  * INTERNAL: used inside the service (1)
1319  */
1320 
1321 static void
logger_service_sink_all_channels()1322 logger_service_sink_all_channels()
1323 {
1324 #if DEBUG_LOG_HANDLER
1325     debug_osformatln(termout, "logger_service_sink_all_channels()");
1326     flushout();
1327 #endif
1328     ptr_set_iterator iter;
1329     ptr_set_iterator_init(&logger_channels, &iter);
1330     while(ptr_set_iterator_hasnext(&iter))
1331     {
1332         ptr_node *node = ptr_set_iterator_next_node(&iter);
1333         logger_channel *channel = (logger_channel*)node->value;
1334         logger_channel_sink(channel);
1335     }
1336 }
1337 
1338 /**
1339  *
1340  * Create the handle tables
1341  *
1342  * INTERNAL: used at initialisation the service
1343  */
1344 
1345 void
logger_handle_exit_level(u32 level)1346 logger_handle_exit_level(u32 level)
1347 {
1348     if(level <= MSG_CRIT)
1349     {
1350         debug_osformatln(termerr, "message level too low: %u < %u", level, MSG_CRIT);
1351         flusherr();
1352         return;
1353     }
1354 
1355     exit_level = level;
1356 }
1357 
1358 #if !HAS_SHARED_QUEUE_SUPPORT
1359 static void*
logger_client_dispatcher_thread(void * context)1360 logger_client_dispatcher_thread(void* context)
1361 {
1362 #if DNSCORE_HAS_LOG_THREAD_TAG
1363     static char loggercl_thread_tag[9] = "loggercl";
1364     logger_handle_set_thread_tag(loggercl_thread_tag);
1365 #endif
1366 
1367     int sockfd;
1368 
1369     for(;;)
1370     {
1371         if((sockfd = ipc_client_connect("logger")) >= 0)
1372         {
1373             break;
1374         }
1375     }
1376 
1377     output_stream los;
1378     input_stream lis;
1379 
1380     fd_output_stream_attach_noclose(&los, sockfd);
1381     //buffer_output_stream_init(&los, &los, 4096);
1382     fd_input_stream_attach_noclose(&lis, sockfd);
1383 
1384     bool must_run = TRUE;
1385 
1386     while(must_run)
1387     {
1388         logger_message* message = (logger_message*)threaded_queue_try_dequeue(&logger_commit_queue);
1389 
1390         if(message == NULL)
1391         {
1392             output_stream_flush(&los);
1393             sleep(1);
1394             continue;
1395         }
1396 
1397         switch(message->type)
1398         {
1399             case LOGGER_MESSAGE_TYPE_TEXT:
1400             {
1401                 struct logger_message_text_s *logger_message_text = (struct logger_message_text_s*)message;
1402                 output_stream_write(&los, logger_message_text, offsetof(struct logger_message_text_s, text));
1403                 output_stream_write(&los, &logger_message_text->tv, sizeof(struct logger_message_text_s) - offsetof(struct logger_message_text_s, tv));
1404                 int len = strlen((const char*)logger_message_text->text);
1405                 output_stream_write_u16(&los, len);
1406                 output_stream_write(&los, logger_message_text->text, len);
1407                 ZFREE_ARRAY(message->text.text, message->text.text_buffer_length);
1408                 logger_message_free(message);
1409                 break;
1410             }
1411 
1412             case LOGGER_MESSAGE_TYPE_STOP:
1413             {
1414                 must_run = threaded_queue_size(&logger_commit_queue) > 0;
1415                 if(must_run)
1416                 {
1417                     // repost
1418                     logger_message_post(message);
1419                     break;
1420                 }
1421 
1422                 u8 tmp;
1423                 output_stream_write_u8(&los, message->type);
1424                 input_stream_read_u8(&lis, &tmp);
1425                 // process the sync (flush + process)
1426                 async_wait_s *awp = message->stop.aw;
1427                 logger_message_free(message);
1428                 async_wait_progress(awp, 1);
1429 
1430                 break;
1431             }
1432 
1433             case LOGGER_MESSAGE_TYPE_CHANNEL_FLUSH_ALL:
1434             case LOGGER_MESSAGE_TYPE_CHANNEL_REOPEN_ALL:
1435             case LOGGER_MESSAGE_TYPE_CHANNEL_CLOSE_ALL:
1436             case LOGGER_MESSAGE_TYPE_CHANNEL_SINK_ALL:
1437             {
1438                 u8 tmp;
1439                 output_stream_write_u8(&los, message->type);
1440                 input_stream_read_u8(&lis, &tmp);
1441                 // process the sync (flush + process)
1442                 async_wait_s *awp = message->channel_flush_all.aw;
1443                 logger_message_free(message);
1444                 async_wait_progress(awp, 1);
1445 
1446                 break;
1447             }
1448 
1449             case LOGGER_MESSAGE_TYPE_IGNORE:
1450             {
1451                 logger_message_free(message);
1452                 break;
1453             }
1454 
1455             default:
1456             {
1457                 abort();
1458                 break;
1459             }
1460         }
1461     }
1462 
1463     output_stream_close(&los);
1464     input_stream_close(&lis);
1465 
1466     ipc_client_close(sockfd);
1467     logger_started = FALSE;
1468 
1469     return NULL;
1470 }
1471 
1472 static void*
logger_server_dispatcher_client_thread(void * context)1473 logger_server_dispatcher_client_thread(void* context)
1474 {
1475     output_stream los;
1476     input_stream lis;
1477     int *sockfdp = (int*)context;
1478     int sockfd = *sockfdp;
1479     ZFREE_OBJECT(sockfdp);
1480 
1481     fd_input_stream_attach_noclose(&lis, sockfd);
1482     //buffer_input_stream_init(&lis, &lis, 4096);
1483     fd_output_stream_attach_noclose(&los, sockfd);
1484 
1485     bool must_run = TRUE;
1486 
1487     logger_message* message = logger_message_alloc();
1488 
1489     while(must_run)
1490     {
1491         if(input_stream_read_u8(&lis, &message->type) == 0)
1492         {
1493             continue;
1494         }
1495 
1496         switch(message->type)
1497         {
1498             case LOGGER_MESSAGE_TYPE_TEXT:
1499             {
1500                 struct logger_message_text_s *logger_message_text = (struct logger_message_text_s*)message;
1501                 input_stream_read(&lis, &logger_message_text->level, offsetof(struct logger_message_text_s, text) - 1);
1502                 input_stream_read(&lis, &logger_message_text->tv, sizeof(struct logger_message_text_s) - offsetof(struct logger_message_text_s, tv));
1503                 u16 text_size = 0;
1504                 input_stream_read_u16(&lis, &text_size);
1505                 ZALLOC_ARRAY_OR_DIE(u8*, logger_message_text->text, logger_message_text->text_buffer_length, BYTE_ARRAY_OUTPUT_STREAM_BUFF_TAG);
1506                 input_stream_read(&lis, logger_message_text->text, text_size);
1507                 logger_message_post(message);
1508                 message = logger_message_alloc();
1509                 break;
1510             }
1511 
1512             case LOGGER_MESSAGE_TYPE_STOP:
1513             {
1514                 must_run = FALSE;
1515                 /*
1516                 must_run = threaded_queue_size(&logger_commit_queue) > 0;
1517                 if(must_run)
1518                 {
1519                     // repost
1520                     logger_message_post(message);
1521                     message = logger_message_alloc();
1522                 }
1523 
1524                 async_wait_progress(message->handle_close.aw, 1);
1525                 */
1526 
1527                 break;
1528             }
1529             case LOGGER_MESSAGE_TYPE_CHANNEL_FLUSH_ALL:
1530             case LOGGER_MESSAGE_TYPE_CHANNEL_REOPEN_ALL:
1531             case LOGGER_MESSAGE_TYPE_CHANNEL_CLOSE_ALL:
1532             case LOGGER_MESSAGE_TYPE_CHANNEL_SINK_ALL:
1533             {
1534 #if HAS_SHARED_QUEUE_SUPPORT
1535                 async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
1536                 message->channel_flush_all.aw = aw;
1537 #else
1538                 async_wait_s aw;
1539                 async_wait_init(&aw, 1);
1540                 message->channel_flush_all.aw = &aw;
1541 #endif
1542                 logger_message_post(message);
1543 
1544                 while(logger_initialised_and_started())
1545                 {
1546 #if HAS_SHARED_QUEUE_SUPPORT
1547                     if(async_wait_timeout(aw, ONE_SECOND_US))
1548                     {
1549                         async_wait_destroy_shared(aw);
1550                         break;
1551                     }
1552 #else
1553                     if(async_wait_timeout(&aw, ONE_SECOND_US))
1554                     {
1555                         async_wait_finalize(&aw);
1556                         break;
1557                     }
1558 #endif
1559                 }
1560 
1561                 message = logger_message_alloc();
1562 
1563                 output_stream_write_u8(&los, 1);
1564 
1565                 break;
1566             }
1567             default:
1568             {
1569                 abort();
1570             }
1571         }
1572     }
1573 
1574     logger_message_free(message);
1575     ipc_client_close(sockfd);
1576 
1577     return NULL;
1578 }
1579 
1580 static void*
logger_server_dispatcher_thread(void * context)1581 logger_server_dispatcher_thread(void* context)
1582 {
1583 #if DNSCORE_HAS_LOG_THREAD_TAG
1584     static char loggersr_thread_tag[9] = "loggersr";
1585     logger_handle_set_thread_tag(loggersr_thread_tag);
1586 #endif
1587     int sockfd = ipc_server_listen("logger");
1588     int ret;
1589 
1590     for(;;)
1591     {
1592         int clientfd = ipc_server_accept(sockfd);
1593         if(clientfd >= 0)
1594         {
1595             int *clientfdp;
1596             ZALLOC_OBJECT_OR_DIE(clientfdp, int, GENERIC);
1597             *clientfdp = clientfd;
1598             if((ret = thread_create(&logger_thread_id, logger_server_dispatcher_client_thread, clientfdp)) != 0)
1599             {
1600             }
1601         }
1602     }
1603     ipc_server_close(sockfd);
1604 
1605     return NULL;
1606 }
1607 #endif
1608 
1609 static void*
logger_dispatcher_thread(void * context)1610 logger_dispatcher_thread(void* context)
1611 {
1612     (void)context;
1613 
1614 #if DEBUG_LOG_HANDLER
1615     debug_osformatln(termout, "logger: dispatcher starting");
1616     flushout();
1617 #endif
1618 
1619     if(!smp_int_setifequal(&logger_thread_state, LOGGER_DISPATCHED_THREAD_STOPPED, LOGGER_DISPATCHED_THREAD_STARTED))
1620     {
1621         debug_osformatln(termout, "logger_dispatcher_thread(%p) state expected to be LOGGER_DISPATCHED_THREAD_STOPPED", context);
1622         return NULL;
1623     }
1624 
1625 #if DEBUG_LOG_HANDLER
1626     debug_osformatln(termout, "logger_dispatcher_thread(%p) started", context);
1627     flushout();
1628 #endif
1629 
1630     thread_set_name("logger", 0U,  0);
1631 
1632 #if DNSCORE_HAS_LOG_THREAD_TAG
1633     thread_set_tag_with_pid_and_tid(getpid_ex(), thread_self(), "logger");
1634 #endif
1635 
1636     output_stream baos;
1637     bytearray_output_stream_context baos_context;
1638     bytearray_output_stream_init_ex_static(&baos, NULL, 1024, BYTEARRAY_DYNAMIC, &baos_context);
1639 
1640     /*
1641      * Since I'll use this virtual call a lot, it's best to cache it.
1642      * (Actually it would be even better to use the static method)
1643      */
1644     output_stream_write_method *baos_write = baos.vtbl->write;
1645 
1646 #if !HAS_SHARED_QUEUE_SUPPORT
1647     char repeat_text[128];
1648 
1649 #if DNSCORE_HAS_LOG_THREAD_TAG
1650     char thread_tag_buffer[12];
1651 #endif
1652 #endif
1653 
1654     if(!smp_int_setifequal(&logger_thread_state, LOGGER_DISPATCHED_THREAD_STARTED, LOGGER_DISPATCHED_THREAD_READY))
1655     {
1656         debug_osformatln(termout, "logger_dispatcher_thread(%p) state expected to be LOGGER_DISPATCHED_THREAD_STARTED", context);
1657         return NULL;
1658     }
1659 
1660     bool must_run = TRUE;
1661 
1662     while(must_run)
1663     {
1664 #if DEBUG_LOG_HANDLER > 1
1665         debug_osformatln(termout, "logger: waiting for message");
1666         flushout();
1667 #endif
1668 
1669 #if HAS_SHARED_QUEUE_SUPPORT
1670         struct shared_circular_buffer_slot* slot = shared_circular_buffer_prepare_dequeue(logger_shared_queue);
1671         logger_message* message = (logger_message*)slot;
1672 
1673 #else
1674         logger_message* message = (logger_message*)threaded_queue_dequeue(&logger_commit_queue);
1675 #endif
1676 
1677         assert(message != NULL);
1678 
1679 #if DEBUG_LOG_HANDLER
1680 #if DEBUG_LOG_HANDLER > 1
1681         debug_osformatln(termout, "logger: got message %p (%i) from %i:%p",
1682                         message,
1683                         message->type,
1684                         message->pid,
1685                         message->text.thread_id);
1686         flushout();
1687 #else
1688         if(logger_thread_pid != getpid_ex())
1689         {
1690             debug_osformatln(termout, "logger: got message %p (%i) from %i:%p",
1691                             message,
1692                             message->type,
1693                             message->pid,
1694                             message->text.thread_id);
1695             flushout();
1696         }
1697 #endif
1698         if(kill(message->pid, 0) < 0)
1699         {
1700             debug_osformatln(termerr, "logger: got message %p (%i) from %i:%p : PID doesn't exist",
1701                              message,
1702                              message->type,
1703                              message->pid,
1704                              message->text.thread_id);
1705             flusherr();
1706         }
1707 #endif
1708         /*
1709          * Reopen is not a message per se.
1710          * It has to be done "now" (ie: the disk is full, files have to be moved)
1711          * But if it was handled as a message, it would need to clear the queue before having an effect.
1712          * So instead a flag is used0
1713          */
1714 
1715         {
1716             mutex_lock(&logger_mutex);
1717             logger_message *logger_sink_request_message = logger_shared_space->_logger_sink_request_message;
1718             if(logger_sink_request_message != NULL)
1719             {
1720                 logger_shared_space->_logger_sink_request_message = NULL;
1721             }
1722             logger_message *logger_reopen_request_message = logger_shared_space->_logger_reopen_request_message;
1723             if(logger_reopen_request_message != NULL)
1724             {
1725                 logger_shared_space->_logger_reopen_request_message = NULL;
1726             }
1727             mutex_unlock(&logger_mutex);
1728 
1729             if(((intptr)logger_sink_request_message | (intptr)logger_reopen_request_message) != 0)
1730             {
1731                 if(logger_sink_request_message != NULL)
1732                 {
1733                     logger_service_sink_all_channels();
1734 
1735                     if(logger_sink_request_message != LOGGER_MESSAGE_SINK_FAKE)
1736                     {
1737                         if(logger_sink_request_message->channel_sink_all.aw != NULL)
1738                         {
1739 
1740                             async_wait_progress(logger_sink_request_message->channel_sink_all.aw, 1);
1741                         }
1742                         logger_sink_request_message->channel_sink_all.aw = NULL;
1743                     }
1744                 }
1745 
1746                 if(logger_reopen_request_message != NULL)
1747                 {
1748                     logger_service_reopen_all_channels();
1749                     if(logger_reopen_request_message->channel_sink_all.aw != NULL)
1750                     {
1751                         async_wait_progress(logger_reopen_request_message->channel_reopen_all.aw, 1);
1752                         logger_reopen_request_message->channel_reopen_all.aw = NULL;
1753                     }
1754                 }
1755             }
1756         }
1757 
1758         switch(message->type)
1759         {
1760             case LOGGER_MESSAGE_TYPE_TEXT:
1761             {
1762 #if DEBUG_LOG_MESSAGES
1763                 {
1764                     time_t now = time(NULL);
1765                     if(now - allocated_messages_count_stats_time > 10)
1766                     {
1767                         allocated_messages_count_stats_time = now;
1768                         int val = smp_int_get(&allocated_messages_count);
1769 
1770                         //debug_osformatln(termerr, "messages allocated count = %d", val);
1771                         //flusherr();
1772                         osformat(&baos, "[LOGGER: %i messages allocated]\n", val);
1773                     }
1774                 }
1775 #endif
1776 
1777                 logger_handle *handle = message->text.handle;
1778                 u32 level = message->text.level;
1779 
1780                 s32 channel_count = handle->channels[level].offset;
1781 
1782                 if(channel_count < 0)
1783                 {
1784 #if HAS_SHARED_QUEUE_SUPPORT
1785                     shared_heap_free(message->text.text);
1786                     shared_circular_buffer_commit_dequeue(logger_shared_queue);
1787 #else
1788                     ZFREE_ARRAY(message->text.text, message->text.text_buffer_length);
1789                     logger_message_free(message);
1790 #endif
1791                     continue;
1792                 }
1793 
1794                 u32 date_header_len;
1795 
1796                 if(message->text.flags == 0)
1797                 {
1798                     struct tm t;
1799 #if SIZEOF_TIMEVAL <= 8
1800                     localtime_r(&message->text.tv.tv_sec, &t);
1801                     osformat(&baos, "%04d-%02d-%02d %02d:%02d:%02d.%06d",
1802                             t.tm_year + 1900U,  t.tm_mon + 1, t.tm_mday,
1803                             t.tm_hour, t.tm_min, t.tm_sec, message->text.tv.tv_usec);
1804 #else
1805                     time_t tv_sec = message->text.timestamp / ONE_SECOND_US;
1806                     localtime_r(&tv_sec, &t);
1807                     osformat(&baos, "%04d-%02d-%02d %02d:%02d:%02d.%06d",
1808                             t.tm_year + 1900U,  t.tm_mon + 1, t.tm_mday,
1809                             t.tm_hour, t.tm_min, t.tm_sec, message->text.timestamp % ONE_SECOND_US);
1810 #endif
1811 
1812 
1813 
1814                     baos_write(&baos, (const u8*)COLUMN_SEPARATOR, COLUMN_SEPARATOR_SIZE);
1815 
1816 #if HAS_SHARED_QUEUE_SUPPORT
1817                     format_dec_u64(message->pid, &baos, 6, ' ', FALSE);
1818                     baos_write(&baos, (const u8*)COLUMN_SEPARATOR, COLUMN_SEPARATOR_SIZE);
1819 #else
1820 #if DEBUG || HAS_LOG_PID
1821                     format_dec_u64(message->text.pid, &baos, 6, ' ', FALSE);
1822                     baos_write(&baos, (const u8*)COLUMN_SEPARATOR, COLUMN_SEPARATOR_SIZE);
1823 #endif
1824 #endif
1825 #if DEBUG || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
1826 #if DNSCORE_HAS_LOG_THREAD_TAG
1827                     baos_write(&baos, (const u8*)thread_get_tag_with_pid_and_tid(message->pid, message->text.thread_id), 8);
1828 #else
1829                     osprint_u32_hex(&baos, (u32)message->text.thread_id);
1830 #endif
1831                     baos_write(&baos, (const u8*)COLUMN_SEPARATOR, COLUMN_SEPARATOR_SIZE);
1832 #endif
1833 
1834                     baos_write(&baos, (u8*)handle->formatted_name, LOGGER_HANDLE_FORMATTED_NAME_SIZE_MAX);
1835                     baos_write(&baos, (const u8*)COLUMN_SEPARATOR, COLUMN_SEPARATOR_SIZE);
1836 
1837                     osprint_char(&baos, acewnid[message->text.level & 15]);
1838                     baos_write(&baos, (const u8*)COLUMN_SEPARATOR, COLUMN_SEPARATOR_SIZE);
1839 
1840                     date_header_len = 29;
1841                 }
1842                 else
1843                 {
1844                     /* shortcut : assume both ones on since that's the only used case */
1845 
1846                     assert( (message->text.flags & (LOGGER_MESSAGE_TIMEMS | LOGGER_MESSAGE_PREFIX)) == (LOGGER_MESSAGE_TIMEMS | LOGGER_MESSAGE_PREFIX));
1847 
1848                     struct tm t;
1849 #if SIZEOF_TIMEVAL <= 8
1850                     localtime_r(&message->text.tv.tv_sec, &t);
1851                     osformat(&baos, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
1852                             t.tm_year + 1900U,  t.tm_mon + 1, t.tm_mday,
1853                             t.tm_hour, t.tm_min, t.tm_sec, message->text.tv.tv_usec / 1000);
1854                     baos_write(&baos, message->text.prefix, message->text.prefix_length);
1855 #else
1856                     time_t tv_sec = message->text.timestamp / ONE_SECOND_US;
1857                     localtime_r(&tv_sec, &t);
1858                     osformat(&baos, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
1859                             t.tm_year + 1900U,  t.tm_mon + 1, t.tm_mday,
1860                             t.tm_hour, t.tm_min, t.tm_sec, (message->text.timestamp % ONE_SECOND_US) / 1000ULL);
1861                     baos_write(&baos, message->text.prefix, message->text.prefix_length);
1862 #endif
1863 
1864 
1865                     date_header_len = 24;
1866                 }
1867 
1868                 baos_write(&baos, message->text.text, message->text.text_length);
1869 
1870 #if HAS_SHARED_QUEUE_SUPPORT
1871                 shared_heap_free(message->text.text);
1872                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
1873 #endif
1874 
1875                 output_stream_write_u8(&baos, 0);
1876 
1877                 size_t size = bytearray_output_stream_size(&baos) - 1;
1878                 char* buffer = (char*)bytearray_output_stream_buffer(&baos);
1879 
1880                 logger_channel** channelp = (logger_channel**)handle->channels[level].data;
1881 
1882                 do
1883                 {
1884                     logger_channel* channel = *channelp;
1885 
1886                     ya_result return_code;
1887 
1888 #if !HAS_SHARED_QUEUE_SUPPORT
1889                     if((channel->last_message->text.text_length == message->text.text_length) && (memcmp(channel->last_message->text.text, message->text.text, message->text.text_length) == 0))
1890                     {
1891                         /* match, it's a repeat */
1892                         channel->last_message_count++;
1893                     }
1894                     else
1895                     {
1896                         /* no match */
1897 
1898                         if(channel->last_message_count > 0)
1899                         {
1900                             /* log the repeat count */
1901 
1902                             /* If the same line is outputted twice : filter it to say 'repeated' instead of sending everything */
1903 
1904                             struct tm t;
1905 #if SIZE_TIMEVAL <= 8
1906                             localtime_r(&message->text.tv.tv_sec, &t);
1907 #else
1908                             localtime_r(&message->text.timestamp / 1000000ULL, &t);
1909 #endif
1910 
1911 #if 1
1912 #if DNSCORE_HAS_LOG_THREAD_TAG
1913                             thread_copy_tag(channel->last_message->text.thread_id, thread_tag_buffer);
1914 #endif
1915 
1916                             return_code = snformat(repeat_text, sizeof(repeat_text),
1917 
1918 #if (DEBUG || HAS_LOG_PID) && DNSCORE_HAS_LOG_THREAD_TAG
1919                             "%04d-%02d-%02d %02d:%02d:%02d.%06d | %-5i | %s | -------- | N | last message repeated %d times",
1920 #elif DEBUG || (HAS_LOG_PID && HAS_LOG_THREAD_ID)
1921                             "%04d-%02d-%02d %02d:%02d:%02d.%06d | %-5i | %08x | -------- | N | last message repeated %d times",
1922 #elif DNSCORE_HAS_LOG_THREAD_TAG
1923                             "%04d-%02d-%02d %02d:%02d:%02d.%06d | %s | -------- | N | last message repeated %d times",
1924 #elif HAS_LOG_THREAD_ID
1925                             "%04d-%02d-%02d %02d:%02d:%02d.%06d | %08x | -------- | N | last message repeated %d times",
1926 #elif HAS_LOG_PID
1927                             "%04d-%02d-%02d %02d:%02d:%02d.%06d | %-5i | -------- | N | last message repeated %d times",
1928 #else
1929                             "%04d-%02d-%02d %02d:%02d:%02d.%06d | -------- | N | last message repeated %d times",
1930 #endif
1931                             t.tm_year + 1900U,  t.tm_mon + 1, t.tm_mday,
1932                                     t.tm_hour, t.tm_min, t.tm_sec,
1933 #if SIZE_TIMEVAL <= 8
1934                                     message->text.tv.tv_usec
1935 #else
1936                                     message->text.timestamp % ONE_SECOND_US
1937 #endif
1938                                     ,
1939 #if DEBUG || HAS_LOG_PID
1940                             getpid_ex(),
1941 #endif
1942 #if DNSCORE_HAS_LOG_THREAD_TAG
1943                             thread_tag_buffer,
1944 #else
1945     #if DEBUG || HAS_LOG_THREAD_ID
1946                             channel->last_message->text.thread_id,
1947     #endif
1948 #endif
1949                             channel->last_message_count);
1950 #else
1951 
1952                             return_code = snformat(repeat_text, sizeof(repeat_text), "%04d-%02d-%02d %02d:%02d:%02d.%06d" COLUMN_SEPARATOR
1953 #if DEBUG
1954                                     "%-5d" COLUMN_SEPARATOR
1955                                     "%08x" COLUMN_SEPARATOR
1956 #endif
1957                                     "--------" COLUMN_SEPARATOR
1958                                     "N" COLUMN_SEPARATOR
1959                                     "last message repeated %d times",
1960                                     t.tm_year + 1900U,  t.tm_mon + 1, t.tm_mday,
1961                                     t.tm_hour, t.tm_min, t.tm_sec,
1962 #if SIZE_TIMEVAL <= 8
1963                                     message->text.tv.tv_usec
1964 #else
1965                                     message->text.timestamp % ONE_SECOND_US
1966 #endif
1967                                     ,
1968 #if DEBUG || HAS_LOG_PID
1969                                     channel->last_message->text.pid,
1970 #endif
1971 #if DEBUG || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
1972                                     channel->last_message->text.thread_id,
1973 #endif
1974                                     channel->last_message_count);
1975 #endif
1976 
1977 
1978                             if(ISOK(return_code))
1979                             {
1980                                 while(FAIL(return_code = logger_channel_msg(channel, level, repeat_text, return_code, 29)))
1981                                 {
1982                                     if(stdstream_is_tty(termerr))
1983                                     {
1984                                         debug_osformatln(termerr, "message write failed on channel: %r", return_code);
1985                                         flusherr();
1986                                     }
1987 
1988                                     if(return_code == MAKE_ERRNO_ERROR(EBADF) || return_code == MAKE_ERRNO_ERROR(ENOSPC))
1989                                     {
1990                                         logger_sink_requested = TRUE;
1991                                     }
1992 
1993                                     if(logger_sink_requested || logger_reopen_requested)
1994                                     {
1995                                         if(logger_sink_requested)
1996                                         {
1997                                             logger_service_sink_all_channels();
1998                                             logger_sink_requested = FALSE;
1999                                         }
2000                                         if(logger_reopen_requested)
2001                                         {
2002                                             logger_service_reopen_all_channels();
2003                                             logger_reopen_requested = FALSE;
2004                                         }
2005                                     }
2006 
2007                                     if(dnscore_shuttingdown())
2008                                     {
2009                                         // message will be lost
2010                                         break;
2011                                     }
2012 
2013                                     sleep(1);
2014                                 }
2015                             }
2016                             else
2017                             {
2018                                 if(stdstream_is_tty(termerr))
2019                                 {
2020                                     debug_osformatln(termerr, "message formatting failed on channel: %r", return_code);
2021                                     flusherr();
2022                                 }
2023                             }
2024                         }
2025 
2026                         /* cleanup */
2027                         if(--channel->last_message->text.rc == 0)
2028                         {
2029                             /* free the message */
2030 
2031 #if DEBUG_LOG_MESSAGES
2032                             debug_osformatln(termout, "message rc is 0 (%s)", channel->last_message->text.text);
2033                             flushout();
2034 #endif
2035                             ZFREE_ARRAY(channel->last_message->text.text, channel->last_message->text.text_buffer_length);
2036                             logger_message_free(channel->last_message);
2037                         }
2038 #if DEBUG_LOG_MESSAGES
2039                         else
2040                         {
2041                             debug_osformatln(termout, "message rc decreased to %d (%s)", channel->last_message->text.rc, channel->last_message->text.text);
2042                             flushout();
2043                         }
2044 
2045                         channel->last_message = message;
2046                         channel->last_message_count = 0;
2047                         message->text.rc++;
2048 #endif
2049 
2050 
2051 #if DEBUG_LOG_MESSAGES
2052                         debug_osformatln(termout, "message rc is %d (%s)", channel->last_message->text.rc, channel->last_message->text.text);
2053                         flushout();
2054 #endif
2055 
2056 #endif // !HAS_SHARED_QUEUE_SUPPORT (no repeat compression)
2057 
2058                         while(FAIL(return_code = logger_channel_msg(channel, level, buffer, size, date_header_len)))
2059                         {
2060                             if(stdstream_is_tty(termerr))
2061                             {
2062                                 debug_osformatln(termerr, "message write failed on channel: %r", return_code);
2063                                 flusherr();
2064                             }
2065 
2066                             bool logger_sink_requested = FALSE;
2067 
2068                             if((return_code == MAKE_ERRNO_ERROR(EBADF)) || (return_code == MAKE_ERRNO_ERROR(ENOSPC)))
2069                             {
2070                                 logger_sink_requested = TRUE;
2071                             }
2072 
2073                             mutex_lock(&logger_mutex);
2074                             logger_message *logger_sink_request_message = logger_shared_space->_logger_sink_request_message;
2075                             if(logger_sink_request_message != NULL)
2076                             {
2077                                 logger_shared_space->_logger_sink_request_message = NULL;
2078                             }
2079                             logger_message *logger_reopen_request_message = logger_shared_space->_logger_reopen_request_message;
2080                             if(logger_reopen_request_message != NULL)
2081                             {
2082                                 logger_shared_space->_logger_reopen_request_message = NULL;
2083                             }
2084                             mutex_unlock(&logger_mutex);
2085 
2086                             if(logger_sink_request_message != NULL)
2087                             {
2088                                 logger_service_sink_all_channels();
2089                                 //logger_sink_requested = FALSE;
2090                                 if(logger_sink_request_message != LOGGER_MESSAGE_SINK_FAKE)
2091                                 {
2092                                     if(logger_sink_request_message->channel_sink_all.aw != NULL)
2093                                     {
2094 
2095                                         async_wait_progress(logger_sink_request_message->channel_sink_all.aw, 1);
2096                                     }
2097                                     logger_sink_request_message->channel_sink_all.aw = NULL;
2098                                 }
2099                             }
2100                             else if(logger_sink_requested)
2101                             {
2102                                 logger_service_sink_all_channels();
2103                                 //logger_sink_requested = FALSE;
2104                             }
2105 
2106                             if(logger_reopen_request_message != NULL)
2107                             {
2108                                 logger_service_reopen_all_channels();
2109                                 if(logger_reopen_request_message->channel_sink_all.aw != NULL)
2110                                 {
2111                                     async_wait_progress(logger_reopen_request_message->channel_reopen_all.aw, 1);
2112                                     logger_reopen_request_message->channel_reopen_all.aw = NULL;
2113                                 }
2114                             }
2115 
2116                             if(dnscore_shuttingdown())
2117                             {
2118                                 // message will be lost
2119                                 break;
2120                             }
2121 
2122                             sleep(1);
2123                         }
2124 #if !HAS_SHARED_QUEUE_SUPPORT
2125                     }
2126 #endif
2127 
2128                     channelp++;
2129                 }
2130                 while(--channel_count >= 0);
2131 
2132 #if !HAS_SHARED_QUEUE_SUPPORT
2133                 if(message->text.rc == 0)
2134                 {
2135 #if DEBUG_LOG_HANDLER
2136                     debug_osformatln(termout, "message has not been used (full dup): '%s'", message->text.text);
2137                     flushout();
2138 #endif
2139                     ZFREE_ARRAY(message->text.text, message->text.text_buffer_length);
2140                     logger_message_free(message);
2141                 }
2142 #endif
2143                 bytearray_output_stream_reset(&baos);
2144 
2145                 break;
2146             }
2147 
2148             case LOGGER_MESSAGE_TYPE_CHANNEL_CLOSE_ALL:
2149             {
2150                 async_wait_s *awp = message->channel_flush_all.aw;
2151 
2152 #if HAS_SHARED_QUEUE_SUPPORT
2153                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2154 #else
2155                 logger_message_free(message);
2156 #endif
2157 
2158                 logger_service_flush_all_channels();
2159                 //logger_service_close_all_channels();
2160                 logger_service_channel_unregister_all();
2161 
2162                 async_wait_progress(awp, 1);
2163 
2164                 break;
2165             }
2166 
2167             case LOGGER_MESSAGE_TYPE_STOP:
2168             {
2169 #if HAS_SHARED_QUEUE_SUPPORT
2170                 must_run = shared_circular_buffer_size(logger_shared_queue) > 1;
2171                 if(must_run)
2172                 {
2173                     // repost
2174                     logger_message* new_message = (logger_message*)shared_circular_buffer_prepare_enqueue(logger_shared_queue);
2175 #if HAS_SHARED_QUEUE_SUPPORT
2176                     new_message->pid = getpid_ex();
2177 #endif
2178                     new_message->type = LOGGER_MESSAGE_TYPE_STOP;
2179                     new_message->stop.aw = message->stop.aw;
2180                     shared_circular_buffer_commit_dequeue(logger_shared_queue);
2181                     shared_circular_buffer_commit_enqueue(logger_shared_queue, (struct shared_circular_buffer_slot*)new_message);
2182                 }
2183                 else
2184                 {
2185                     async_wait_s *awp = message->handle_close.aw;
2186                     shared_circular_buffer_commit_dequeue(logger_shared_queue); // destroys the message but not the synchronisation structure.
2187                     async_wait_progress(awp, 1);
2188                 }
2189 #else
2190                 must_run = threaded_queue_size(&logger_commit_queue) > 0;
2191                 if(must_run)
2192                 {
2193                     // repost
2194                     logger_message_post(message);
2195                 }
2196                 else
2197                 {
2198                     async_wait_s *awp = message->handle_close.aw;
2199                     async_wait_progress(awp, 1);
2200                 }
2201 #endif
2202                 break;
2203             }
2204 
2205                 /// @note fall through by design
2206 
2207             case LOGGER_MESSAGE_TYPE_CHANNEL_FLUSH_ALL:
2208             {
2209                 async_wait_s *awp = message->channel_flush_all.aw;
2210 
2211 #if HAS_SHARED_QUEUE_SUPPORT
2212                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2213 #else
2214                 logger_message_free(message);
2215 #endif
2216 
2217                 logger_service_flush_all_channels();
2218 
2219                 async_wait_progress(awp, 1);
2220 
2221                 break;
2222             }
2223 
2224             case LOGGER_MESSAGE_TYPE_CHANNEL_REOPEN_ALL:
2225             {
2226                 // reopen is activated by a flag
2227                 // this structure is just a way to fire the event
2228 
2229                 async_wait_s *awp = message->channel_reopen_all.aw;
2230                 if(awp != NULL)
2231                 {
2232                     if(stdstream_is_tty(termerr))
2233                     {
2234                         debug_osformatln(termerr, "logger: unexpected synchronization point in reopen");
2235                         flusherr();
2236                     }
2237 
2238                     async_wait_progress(awp, 1);
2239                 }
2240 #if HAS_SHARED_QUEUE_SUPPORT
2241                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2242 #else
2243                 logger_message_free(message);
2244 #endif
2245                 break;
2246             }
2247 
2248             case LOGGER_MESSAGE_TYPE_CHANNEL_SINK_ALL:
2249             {
2250                 // sink is activated by a flag
2251                 // this structure is just a way to fire the event
2252 
2253                 async_wait_s *awp = message->channel_sink_all.aw;
2254                 if(awp != NULL)
2255                 {
2256                     if(stdstream_is_tty(termerr))
2257                     {
2258                         debug_osformatln(termerr, "logger: unexpected synchronization point in sink");
2259                         flusherr();
2260                     }
2261 
2262                     async_wait_progress(awp, 1);
2263                 }
2264 
2265 #if HAS_SHARED_QUEUE_SUPPORT
2266                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2267 #else
2268                 logger_message_free(message);
2269 #endif
2270                 break;
2271             }
2272 
2273             case LOGGER_MESSAGE_TYPE_IGNORE:
2274             {
2275 #if HAS_SHARED_QUEUE_SUPPORT
2276                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2277 #else
2278                 logger_message_free(message);
2279 #endif
2280                 break;
2281             }
2282 
2283             case LOGGER_MESSAGE_TYPE_CHANNEL_GET_USAGE_COUNT:
2284             {
2285                 async_wait_s *awp = message->get_usage_count.aw;
2286                 const char *channel_name = message->get_usage_count.channel_name;
2287 
2288                 s32 *countp = message->get_usage_count.countp;
2289 
2290                 assert(countp != NULL);
2291 
2292 #if HAS_SHARED_QUEUE_SUPPORT
2293                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2294 #else
2295                 logger_message_free(message);
2296 #endif
2297 
2298                 logger_channel *channel = logger_service_channel_get(channel_name);
2299 
2300                 if(channel != NULL)
2301                 {
2302                     *countp = channel->linked_handles;
2303                 }
2304                 else
2305                 {
2306                     *countp = -1;
2307                 }
2308 
2309                 async_wait_progress(awp, 1);
2310                 break;
2311             }
2312 
2313             case LOGGER_MESSAGE_TYPE_CHANNEL_REGISTER:
2314             {
2315                 async_wait_s *awp = message->channel_register.aw;
2316                 const char *channel_name = message->channel_register.channel_name;
2317                 logger_channel *channel = message->channel_register.channel;
2318 
2319 #if HAS_SHARED_QUEUE_SUPPORT
2320                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2321 #else
2322                 logger_message_free(message);
2323 #endif
2324 
2325                 logger_service_channel_register(channel_name, channel);
2326 
2327                 async_wait_progress(awp, 1);
2328                 break;
2329             }
2330 
2331             case LOGGER_MESSAGE_TYPE_CHANNEL_UNREGISTER:
2332             {
2333                 async_wait_s *awp = message->channel_unregister.aw;
2334                 const char *channel_name = message->channel_unregister.channel_name;
2335 
2336 #if HAS_SHARED_QUEUE_SUPPORT
2337                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2338 #else
2339                 logger_message_free(message);
2340 #endif
2341 
2342                 logger_service_channel_unregister(channel_name);
2343 
2344                 async_wait_progress(awp, 1);
2345                 break;
2346             }
2347 
2348             case LOGGER_MESSAGE_TYPE_HANDLE_CREATE:
2349             {
2350                 async_wait_s *awp = message->handle_create.aw;
2351                 const char *name = message->handle_create.logger_name;
2352                 logger_handle **handlep = message->handle_create.handle_holder;
2353                 logger_handle* handle = logger_service_handle_create(name);
2354                 handle->global_reference = handlep;
2355                 *handlep = handle;
2356 
2357 #if HAS_SHARED_QUEUE_SUPPORT
2358                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2359 #else
2360                 logger_message_free(message);
2361 #endif
2362                 async_wait_progress(awp, 1);
2363                 break;
2364             }
2365 
2366             case LOGGER_MESSAGE_TYPE_HANDLE_CLOSE:
2367             {
2368                 async_wait_s *awp = message->handle_close.aw;
2369                 const char *name = message->handle_close.logger_name;
2370                 //u32 name_len = message->text_length;
2371                 logger_service_handle_close(name);
2372 
2373 #if HAS_SHARED_QUEUE_SUPPORT
2374                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2375 #else
2376                 logger_message_free(message);
2377 #endif
2378 
2379                 async_wait_progress(awp, 1);
2380                 break;
2381             }
2382 
2383             case LOGGER_MESSAGE_TYPE_HANDLE_NAME_ADD_CHANNEL:
2384             {
2385                 logger_handle *handle;
2386                 async_wait_s *awp = message->handle_add_channel.aw;
2387                 const char *name = message->handle_add_channel.logger_name;
2388                 int level = message->handle_add_channel.level;
2389                 const char *channel_name = message->handle_add_channel.channel_name;
2390 
2391                 handle = logger_service_handle_get(name);
2392                 if(handle != NULL)
2393                 {
2394                     logger_service_handle_add_channel(handle, level, channel_name);
2395                 }
2396 
2397 #if HAS_SHARED_QUEUE_SUPPORT
2398                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2399 #else
2400                 logger_message_free(message);
2401 #endif
2402 
2403                 async_wait_progress(awp, 1);
2404                 break;
2405             }
2406 
2407             case LOGGER_MESSAGE_TYPE_HANDLE_NAME_REMOVE_CHANNEL:
2408             {
2409                 logger_handle *handle;
2410                 async_wait_s *awp = message->handle_remove_channel.aw;
2411                 const char *name = message->handle_remove_channel.logger_name;
2412                 const char *channel_name = message->handle_remove_channel.channel_name;
2413 
2414                 handle = logger_service_handle_get(name);
2415                 if(handle != NULL)
2416                 {
2417                     logger_service_handle_remove_channel(handle, channel_name);
2418                 }
2419 
2420 #if HAS_SHARED_QUEUE_SUPPORT
2421                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2422 #else
2423                 logger_message_free(message);
2424 #endif
2425 
2426                 async_wait_progress(awp, 1);
2427                 break;
2428             }
2429 
2430             case LOGGER_MESSAGE_TYPE_HANDLE_NAME_COUNT_CHANNELS:
2431             {
2432                 logger_handle *handle;
2433                 async_wait_s *awp = message->handle_count_channels.aw;
2434                 const char *name = message->handle_count_channels.logger_name;
2435 
2436                 handle = logger_service_handle_get(name);
2437 
2438                 *message->handle_count_channels.countp = 0;
2439 
2440                 if(handle != NULL)
2441                 {
2442                     *message->handle_count_channels.countp = logger_service_handle_count_channels(handle);
2443                 }
2444 
2445 #if HAS_SHARED_QUEUE_SUPPORT
2446                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2447 #else
2448                 logger_message_free(message);
2449 #endif
2450 
2451                 async_wait_progress(awp, 1);
2452                 break;
2453             }
2454 #if DNSCORE_HAS_LOG_THREAD_TAG
2455             case LOGGER_MESSAGE_TYPE_THREAD_SET_TAG:
2456             {
2457                 async_wait_s *awp = message->thread_set_tag.aw;
2458 #if DEBUG
2459 #if DEBUG_LOG_REGISTRATIONS
2460                 printf("logger: registering: pid=%i thread=%p tag=%c%c%c%c%c%c%c%c (printf)\n",
2461                               message->pid, (void*)(intptr_t)message->thread_set_tag.tid,
2462                               message->thread_set_tag.tag[0],message->thread_set_tag.tag[1],message->thread_set_tag.tag[2],message->thread_set_tag.tag[3],
2463                               message->thread_set_tag.tag[4],message->thread_set_tag.tag[5],message->thread_set_tag.tag[6],message->thread_set_tag.tag[7]);
2464                 debug_osformatln(termout, "logger: registering: pid=%i thread=%p tag=%c%c%c%c%c%c%c%c (printf)",
2465                        message->pid, (void*)(intptr_t)message->thread_set_tag.tid,
2466                        message->thread_set_tag.tag[0],message->thread_set_tag.tag[1],message->thread_set_tag.tag[2],message->thread_set_tag.tag[3],
2467                        message->thread_set_tag.tag[4],message->thread_set_tag.tag[5],message->thread_set_tag.tag[6],message->thread_set_tag.tag[7]);
2468 #endif
2469 #endif
2470 #if DEBUG
2471 #if DEBUG_LOG_REGISTRATIONS
2472                 log_try_debug("logger: registering: pid=%i thread=%p tag=%c%c%c%c%c%c%c%c (log_try_debug)",
2473                               message->pid, message->thread_set_tag.tid,
2474                               message->thread_set_tag.tag[0],message->thread_set_tag.tag[1],message->thread_set_tag.tag[2],message->thread_set_tag.tag[3],
2475                               message->thread_set_tag.tag[4],message->thread_set_tag.tag[5],message->thread_set_tag.tag[6],message->thread_set_tag.tag[7]);
2476 #endif
2477 #endif
2478                 thread_set_tag_with_pid_and_tid(message->pid, message->thread_set_tag.tid, message->thread_set_tag.tag);
2479 
2480 #if HAS_SHARED_QUEUE_SUPPORT
2481                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2482 #else
2483                 logger_message_free(message);
2484 #endif
2485                 async_wait_progress(awp, 1);
2486                 break;
2487             }
2488 
2489             case LOGGER_MESSAGE_TYPE_THREAD_CLEAR_TAG:
2490             {
2491                 async_wait_s *awp = message->thread_clear_tag.aw;
2492 
2493                 thread_clear_tag_with_pid_and_tid(message->pid, message->thread_clear_tag.tid);
2494 
2495 #if HAS_SHARED_QUEUE_SUPPORT
2496                 shared_circular_buffer_commit_dequeue(logger_shared_queue);
2497 #else
2498                 logger_message_free(message);
2499 #endif
2500                 async_wait_progress(awp, 1);
2501                 break;
2502             }
2503 #endif
2504             default:
2505             {
2506                 if(stdstream_is_tty(termerr))
2507                 {
2508                     debug_osformatln(termerr, "unexpected message type %u in log queue", message->type);
2509                     flusherr();
2510                 }
2511 
2512                 break;
2513             }
2514         }
2515     } // while must run
2516 
2517     if(!smp_int_setifequal(&logger_thread_state, LOGGER_DISPATCHED_THREAD_READY, LOGGER_DISPATCHED_THREAD_STOPPING))
2518     {
2519         debug_osformatln(termout, "logger_dispatcher_thread(%p) state expected to be LOGGER_DISPATCHED_THREAD_READY", context);
2520         return NULL;
2521     }
2522 
2523     // flush everything
2524 
2525     logger_service_flush_all_channels();
2526 
2527     // close everything
2528 
2529     output_stream_close(&baos);
2530 
2531 #if DEBUG_LOG_HANDLER
2532     debug_osformatln(termout, "logger_dispatcher_thread(%p) END", context);
2533     flushout();
2534 #endif
2535 
2536 #if DNSCORE_HAS_LOG_THREAD_TAG
2537     thread_clear_tag_with_pid_and_tid(getpid_ex(), thread_self());
2538 #endif
2539 
2540     if(!smp_int_setifequal(&logger_thread_state, LOGGER_DISPATCHED_THREAD_STOPPING, LOGGER_DISPATCHED_THREAD_STOPPED))
2541     {
2542         debug_osformatln(termout, "logger_dispatcher_thread(%p) state expected to be LOGGER_DISPATCHED_THREAD_STOPPING", context);
2543         //return NULL;
2544     }
2545 
2546     return NULL;
2547 }
2548 
2549 s32
logger_channel_get_usage_count(const char * channel_name)2550 logger_channel_get_usage_count(const char* channel_name)
2551 {
2552 #if DEBUG_LOG_HANDLER
2553     debug_osformatln(termout, "logger_channel_get_usage_count(%s) ", channel_name);
2554     flushout();
2555 #endif
2556 
2557     s32 count = -2;
2558 
2559     if(logger_is_running())
2560     {
2561         logger_message *message = logger_message_alloc();
2562 
2563         // ZEROMEMORY(message, sizeof(logger_message));
2564 
2565 #if HAS_SHARED_QUEUE_SUPPORT
2566         async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2567 #else
2568         async_wait_s aw;
2569         async_wait_init(&aw, 1);
2570 #endif
2571 #if HAS_SHARED_QUEUE_SUPPORT
2572         message->pid = getpid_ex();
2573 #endif
2574         message->type = LOGGER_MESSAGE_TYPE_CHANNEL_GET_USAGE_COUNT;
2575 #if HAS_SHARED_QUEUE_SUPPORT
2576         message->get_usage_count.aw = aw;
2577 #else
2578         message->get_usage_count.aw = &aw;
2579 #endif
2580         message->get_usage_count.channel_name = channel_name;
2581         message->get_usage_count.countp = &count;
2582 
2583         logger_message_post(message);
2584 
2585 #if HAS_SHARED_QUEUE_SUPPORT
2586         async_wait(aw);
2587         async_wait_destroy_shared(aw);
2588 #else
2589         async_wait(&aw);
2590         async_wait_finalize(&aw);
2591 #endif
2592     }
2593     else
2594     {
2595 #if HAS_SHARED_QUEUE_SUPPORT
2596         shared_circular_buffer_lock(logger_shared_queue);
2597 #else
2598         mutex_lock(&logger_commit_queue.mutex);
2599 #endif
2600 
2601         logger_channel *channel = logger_service_channel_get(channel_name);
2602 
2603         if(channel != NULL)
2604         {
2605             count = channel->linked_handles;
2606         }
2607         else
2608         {
2609             count = -1;
2610         }
2611 
2612 #if HAS_SHARED_QUEUE_SUPPORT
2613         shared_circular_buffer_unlock(logger_shared_queue);
2614 #else
2615         mutex_unlock(&logger_commit_queue.mutex);
2616 #endif
2617     }
2618 
2619     return count;
2620 }
2621 
2622 void
logger_channel_register(const char * channel_name,struct logger_channel * channel)2623 logger_channel_register(const char* channel_name, struct logger_channel *channel)
2624 {
2625     if((channel == NULL) || (channel->vtbl == NULL))
2626     {
2627         debug_osformatln(termerr, "tried to register channel on uninitialised channel");
2628         return;
2629     }
2630 
2631 #if DEBUG_LOG_HANDLER
2632     debug_osformatln(termout, "logger_channel_register(%s,%p) ", channel_name, channel);
2633     flushout();
2634 #endif
2635     if(logger_is_running())
2636     {
2637         logger_message *message = logger_message_alloc();
2638 
2639 #if HAS_SHARED_QUEUE_SUPPORT
2640         async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2641 #else
2642         async_wait_s aw;
2643         async_wait_init(&aw, 1);
2644 #endif
2645 #if HAS_SHARED_QUEUE_SUPPORT
2646         message->pid = getpid_ex();
2647 #endif
2648         message->type = LOGGER_MESSAGE_TYPE_CHANNEL_REGISTER;
2649 #if HAS_SHARED_QUEUE_SUPPORT
2650         message->channel_register.aw = aw;
2651 #else
2652         message->channel_register.aw = &aw;
2653 #endif
2654         message->channel_register.channel_name = channel_name;
2655         message->channel_register.channel = channel;
2656 
2657         logger_message_post(message);
2658 
2659 #if HAS_SHARED_QUEUE_SUPPORT
2660         async_wait(aw);
2661         async_wait_destroy_shared(aw);
2662 #else
2663         async_wait(&aw);
2664         async_wait_finalize(&aw);
2665 #endif
2666     }
2667     else
2668     {
2669 #if HAS_SHARED_QUEUE_SUPPORT
2670         shared_circular_buffer_lock(logger_shared_queue);
2671 #else
2672         mutex_lock(&logger_commit_queue.mutex);
2673 #endif
2674         logger_service_channel_register(channel_name, channel);
2675 
2676 #if HAS_SHARED_QUEUE_SUPPORT
2677         shared_circular_buffer_unlock(logger_shared_queue);
2678 #else
2679         mutex_unlock(&logger_commit_queue.mutex);
2680 #endif
2681     }
2682 }
2683 
2684 void
logger_channel_unregister(const char * channel_name)2685 logger_channel_unregister(const char* channel_name)
2686 {
2687 #if DEBUG_LOG_HANDLER
2688     debug_osformatln(termout, "logger_channel_unregister(%s) ", channel_name);
2689     flushout();
2690 #endif
2691 
2692     logger_message *message = logger_message_alloc();
2693 
2694 #if HAS_SHARED_QUEUE_SUPPORT
2695     async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2696 #else
2697     async_wait_s aw;
2698     async_wait_init(&aw, 1);
2699 #endif
2700 #if HAS_SHARED_QUEUE_SUPPORT
2701     message->pid = getpid_ex();
2702 #endif
2703     message->type = LOGGER_MESSAGE_TYPE_CHANNEL_UNREGISTER;
2704 
2705 #if HAS_SHARED_QUEUE_SUPPORT
2706     message->channel_unregister.aw = aw;
2707 #else
2708     message->channel_unregister.aw = &aw;
2709 #endif
2710     message->channel_unregister.channel_name = channel_name;
2711 
2712     logger_message_post(message);
2713 
2714 #if HAS_SHARED_QUEUE_SUPPORT
2715     async_wait(aw);
2716     async_wait_destroy_shared(aw);
2717 #else
2718     async_wait(&aw);
2719     async_wait_finalize(&aw);
2720 #endif
2721 }
2722 
2723 void
logger_handle_create(const char * logger_name,logger_handle ** handle_holder)2724 logger_handle_create(const char *logger_name, logger_handle **handle_holder)
2725 {
2726 #if DEBUG_LOG_HANDLER
2727     debug_osformatln(termout, "logger_handle_create(%s,%p) ", logger_name, handle_holder);
2728     flushout();
2729 #endif
2730 
2731     if(logger_is_running())
2732     {
2733         logger_message *message = logger_message_alloc();
2734 
2735 #if HAS_SHARED_QUEUE_SUPPORT
2736         async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2737 #else
2738         async_wait_s aw;
2739         async_wait_init(&aw, 1);
2740 #endif
2741 #if HAS_SHARED_QUEUE_SUPPORT
2742         message->pid = getpid_ex();
2743 #endif
2744         message->type = LOGGER_MESSAGE_TYPE_HANDLE_CREATE;
2745 #if HAS_SHARED_QUEUE_SUPPORT
2746         message->handle_create.aw = aw;
2747 #else
2748         message->handle_create.aw = &aw;
2749 #endif
2750         message->handle_create.logger_name = logger_name;
2751         message->handle_create.handle_holder = handle_holder;
2752 
2753         logger_message_post(message);
2754 
2755 #if HAS_SHARED_QUEUE_SUPPORT
2756         async_wait(aw);
2757         async_wait_destroy_shared(aw);
2758 #else
2759         async_wait(&aw);
2760         async_wait_finalize(&aw);
2761 #endif
2762     }
2763     else
2764     {
2765 #if HAS_SHARED_QUEUE_SUPPORT
2766         shared_circular_buffer_lock(logger_shared_queue);
2767 #else
2768         mutex_lock(&logger_commit_queue.mutex);
2769 #endif
2770         logger_handle* handle = logger_service_handle_create(logger_name);
2771         handle->global_reference = handle_holder;
2772         *handle_holder = handle;
2773 
2774 #if HAS_SHARED_QUEUE_SUPPORT
2775         shared_circular_buffer_unlock(logger_shared_queue);
2776 #else
2777         mutex_unlock(&logger_commit_queue.mutex);
2778 #endif
2779     }
2780 }
2781 
2782 void
logger_handle_close(const char * logger_name)2783 logger_handle_close(const char *logger_name)
2784 {
2785 #if DEBUG_LOG_HANDLER
2786     debug_osformatln(termout, "logger_handle_close(%s) ", logger_name);
2787     flushout();
2788 #endif
2789 
2790     logger_message *message = logger_message_alloc();
2791 
2792 #if HAS_SHARED_QUEUE_SUPPORT
2793     async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2794 #else
2795     async_wait_s aw;
2796     async_wait_init(&aw, 1);
2797 #endif
2798 #if HAS_SHARED_QUEUE_SUPPORT
2799     message->pid = getpid_ex();
2800 #endif
2801     message->type = LOGGER_MESSAGE_TYPE_HANDLE_CLOSE;
2802 #if HAS_SHARED_QUEUE_SUPPORT
2803     message->handle_close.aw = aw;
2804 #else
2805     message->handle_close.aw = &aw;
2806 #endif
2807     message->handle_close.logger_name = logger_name;
2808 
2809     logger_message_post(message);
2810 
2811 #if HAS_SHARED_QUEUE_SUPPORT
2812     async_wait(aw);
2813     async_wait_destroy_shared(aw);
2814 #else
2815     async_wait(&aw);
2816     async_wait_finalize(&aw);
2817 #endif
2818 }
2819 
2820 void
logger_handle_add_channel(const char * logger_name,int level,const char * channel_name)2821 logger_handle_add_channel(const char *logger_name, int level, const char *channel_name)
2822 {
2823 #if DEBUG_LOG_HANDLER
2824     debug_osformatln(termout, "logger_handle_add_channel(%s,%x,%s) ", logger_name, level, channel_name);
2825     flushout();
2826 #endif
2827 
2828     if(logger_is_running())
2829     {
2830         logger_message *message = logger_message_alloc();
2831         ZEROMEMORY(message, sizeof(logger_message));
2832 #if HAS_SHARED_QUEUE_SUPPORT
2833         async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2834 #else
2835         async_wait_s aw;
2836         async_wait_init(&aw, 1);
2837 #endif
2838 #if HAS_SHARED_QUEUE_SUPPORT
2839         message->pid = getpid_ex();
2840 #endif
2841         message->type = LOGGER_MESSAGE_TYPE_HANDLE_NAME_ADD_CHANNEL;
2842 #if HAS_SHARED_QUEUE_SUPPORT
2843         message->handle_add_channel.aw = aw;
2844 #else
2845         message->handle_add_channel.aw = &aw;
2846 #endif
2847         message->handle_add_channel.logger_name = logger_name;
2848         message->handle_add_channel.level = level;
2849         message->handle_add_channel.channel_name = channel_name;
2850 
2851         logger_message_post(message);
2852 
2853 #if HAS_SHARED_QUEUE_SUPPORT
2854         async_wait(aw);
2855         async_wait_destroy_shared(aw);
2856 #else
2857         async_wait(&aw);
2858         async_wait_finalize(&aw);
2859 #endif
2860     }
2861     else
2862     {
2863 #if HAS_SHARED_QUEUE_SUPPORT
2864         shared_circular_buffer_lock(logger_shared_queue);
2865 #else
2866         mutex_lock(&logger_commit_queue.mutex);
2867 #endif
2868         logger_handle *handle = logger_service_handle_get(logger_name);
2869         if(handle != NULL)
2870         {
2871             logger_service_handle_add_channel(handle, level, channel_name);
2872         }
2873 
2874 #if HAS_SHARED_QUEUE_SUPPORT
2875         shared_circular_buffer_unlock(logger_shared_queue);
2876 #else
2877         mutex_unlock(&logger_commit_queue.mutex);
2878 #endif
2879     }
2880 }
2881 
2882 void
logger_handle_remove_channel(const char * logger_name,const char * channel_name)2883 logger_handle_remove_channel(const char *logger_name, const char *channel_name)
2884 {
2885 #if DEBUG_LOG_HANDLER
2886     debug_osformatln(termout, "logger_handle_remove_channel(%s,%s) ", logger_name, channel_name);
2887     flushout();
2888 #endif
2889 
2890     logger_message *message = logger_message_alloc();
2891 
2892 #if HAS_SHARED_QUEUE_SUPPORT
2893     async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2894 #else
2895     async_wait_s aw;
2896     async_wait_init(&aw, 1);
2897 #endif
2898 #if HAS_SHARED_QUEUE_SUPPORT
2899     message->pid = getpid_ex();
2900 #endif
2901     message->type = LOGGER_MESSAGE_TYPE_HANDLE_NAME_REMOVE_CHANNEL;
2902 
2903 #if HAS_SHARED_QUEUE_SUPPORT
2904     message->handle_remove_channel.aw = aw;
2905 #else
2906     message->handle_remove_channel.aw = &aw;
2907 #endif
2908 
2909     message->handle_remove_channel.logger_name = logger_name;
2910     message->handle_remove_channel.channel_name = channel_name;
2911 
2912     logger_message_post(message);
2913 
2914 #if HAS_SHARED_QUEUE_SUPPORT
2915     async_wait(aw);
2916     async_wait_destroy_shared(aw);
2917 #else
2918     async_wait(&aw);
2919     async_wait_finalize(&aw);
2920 #endif
2921 }
2922 
2923 /**
2924  *
2925  * Helper function.
2926  * Creates a logger for the given file descriptor (typically 1/stdout or 2/stderr)
2927  *
2928  * @param logger_name name of the logger
2929  * @param mask the mask to use (ie: MSG_ALL_MASK)
2930  * @param fd the file descriptor
2931  */
2932 
2933 void
logger_handle_create_to_fd(const char * logger_name,int mask,int fd)2934 logger_handle_create_to_fd(const char *logger_name, int mask, int fd)
2935 {
2936     logger_channel* channel = logger_channel_alloc();
2937     output_stream stdout_os;
2938     fd_output_stream_attach(&stdout_os, dup(fd));
2939     logger_channel_stream_open(&stdout_os, FALSE, channel);
2940     logger_channel_register("stdout", channel);
2941     logger_handle_create(logger_name, &g_system_logger);
2942     logger_handle_add_channel(logger_name, mask, "stdout");
2943 }
2944 
2945 s32
logger_handle_count_channels(const char * logger_name)2946 logger_handle_count_channels(const char *logger_name)
2947 {
2948 #if DEBUG_LOG_HANDLER
2949     debug_osformatln(termout, "logger_handle_count_channels(%s)", logger_name);
2950     flushout();
2951 #endif
2952 
2953     logger_message *message = logger_message_alloc();
2954     s32 ret = -2;
2955 
2956 #if HAS_SHARED_QUEUE_SUPPORT
2957     async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
2958 #else
2959     async_wait_s aw;
2960     async_wait_init(&aw, 1);
2961 #endif
2962 #if HAS_SHARED_QUEUE_SUPPORT
2963     message->pid = getpid_ex();
2964 #endif
2965     message->type = LOGGER_MESSAGE_TYPE_HANDLE_NAME_COUNT_CHANNELS;
2966 #if HAS_SHARED_QUEUE_SUPPORT
2967     message->handle_count_channels.aw = aw;
2968 #else
2969     message->handle_count_channels.aw = &aw;
2970 #endif
2971     message->handle_count_channels.logger_name = logger_name;
2972     message->handle_count_channels.countp = &ret;
2973 
2974     logger_message_post(message);
2975 
2976 #if HAS_SHARED_QUEUE_SUPPORT
2977     async_wait(aw);
2978     async_wait_destroy_shared(aw);
2979 #else
2980     async_wait(&aw);
2981     async_wait_finalize(&aw);
2982 #endif
2983 
2984     return ret;
2985 }
2986 
2987 #if DNSCORE_HAS_LOG_THREAD_TAG
2988 
2989 void
logger_handle_set_thread_tag_with_pid_and_tid(pid_t pid,thread_t tid,const char tag[THREAD_TAG_SIZE])2990 logger_handle_set_thread_tag_with_pid_and_tid(pid_t pid, thread_t tid, const char tag[THREAD_TAG_SIZE])
2991 {
2992     (void)pid;
2993 #if DEBUG_LOG_HANDLER
2994     debug_osformatln(termout, "logger_handle_set_thread_tag_with_pid_and_tid(%i,%p) ", pid, tid,
2995             tag[0],tag[1],tag[2],tag[3],
2996             tag[4],tag[5],tag[6],tag[7]);
2997     flushout();
2998 #endif
2999 
3000     logger_message *message = logger_message_alloc();
3001 #if HAS_SHARED_QUEUE_SUPPORT
3002     async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
3003 #else
3004     async_wait_s aw;
3005     async_wait_init(&aw, 1);
3006 #endif
3007 #if HAS_SHARED_QUEUE_SUPPORT
3008     message->pid = getpid_ex();
3009 #endif
3010     message->type = LOGGER_MESSAGE_TYPE_THREAD_SET_TAG;
3011 #if HAS_SHARED_QUEUE_SUPPORT
3012     message->thread_set_tag.aw = aw;
3013 #else
3014     message->thread_set_tag.aw = &aw;
3015 #endif
3016     memcpy(message->thread_set_tag.tag, tag, THREAD_TAG_SIZE);
3017     message->thread_set_tag.tid = tid;
3018 
3019     logger_message_post(message);
3020 
3021 #if DEBUG_LOG_HANDLER
3022     debug_osformatln(termout, "logger_handle_set_thread_tag_with_pid_and_tid(%i,%p) (posted)", pid, tid,
3023             tag[0],tag[1],tag[2],tag[3],
3024             tag[4],tag[5],tag[6],tag[7]);
3025     flushout();
3026 #endif
3027 
3028 #if HAS_SHARED_QUEUE_SUPPORT
3029     async_wait(aw);
3030     async_wait_destroy_shared(aw); // does the finalize call
3031 #else
3032     async_wait(&aw);
3033     async_wait_finalize(&aw);
3034 #endif
3035 #if DEBUG_LOG_HANDLER
3036     debug_osformatln(termout, "logger_handle_set_thread_tag_with_pid_and_tid(%i,%p) (synced, done)", pid, tid,
3037             tag[0],tag[1],tag[2],tag[3],
3038             tag[4],tag[5],tag[6],tag[7]);
3039     flushout();
3040 #endif
3041 }
3042 
3043 void
logger_handle_clear_thread_tag_with_pid_and_tid(pid_t pid,thread_t tid)3044 logger_handle_clear_thread_tag_with_pid_and_tid(pid_t pid, thread_t tid)
3045 {
3046     (void)pid;
3047 #if DEBUG_LOG_HANDLER
3048     debug_osformatln(termout, "logger_handle_clear_thread_tag_with_pid_and_tid(%i,%p) ", pid, tid);
3049     flushout();
3050 #endif
3051 
3052     logger_message *message = logger_message_alloc();
3053 
3054 #if HAS_SHARED_QUEUE_SUPPORT
3055     async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
3056 #else
3057     async_wait_s aw;
3058     async_wait_init(&aw, 1);
3059 #endif
3060 #if HAS_SHARED_QUEUE_SUPPORT
3061     message->pid = getpid_ex();
3062 #endif
3063     message->type = LOGGER_MESSAGE_TYPE_THREAD_CLEAR_TAG;
3064 #if HAS_SHARED_QUEUE_SUPPORT
3065     message->thread_clear_tag.aw = aw;
3066 #else
3067     message->thread_clear_tag.aw = &aw;
3068 #endif
3069     message->thread_clear_tag.tid = tid;
3070 
3071     logger_message_post(message);
3072 
3073 #if HAS_SHARED_QUEUE_SUPPORT
3074     async_wait(aw);
3075     async_wait_destroy_shared(aw);
3076 #else
3077     async_wait(&aw);
3078     async_wait_finalize(&aw);
3079 #endif
3080 }
3081 
3082 void
logger_handle_set_thread_tag(const char tag[THREAD_TAG_SIZE])3083 logger_handle_set_thread_tag(const char tag[THREAD_TAG_SIZE])
3084 {
3085     char clean_tag[THREAD_TAG_SIZE + 1];
3086     memset(clean_tag, 0U,  sizeof(clean_tag));
3087     strcpy_ex(clean_tag, tag, sizeof(clean_tag));
3088 
3089     if(logger_is_running())
3090     {
3091         logger_handle_set_thread_tag_with_pid_and_tid(getpid_ex(), thread_self(), clean_tag);
3092     }
3093     else
3094     {
3095         thread_set_tag_with_pid_and_tid(getpid_ex(), thread_self(), clean_tag);
3096     }
3097 }
3098 
3099 void
logger_handle_clear_thread_tag()3100 logger_handle_clear_thread_tag()
3101 {
3102     if(logger_is_running())
3103     {
3104         logger_handle_clear_thread_tag_with_pid_and_tid(getpid_ex(), thread_self());
3105     }
3106     else
3107     {
3108         thread_clear_tag_with_pid_and_tid(getpid_ex(), thread_self());
3109     }
3110 }
3111 
3112 #endif
3113 
3114 static u32 logger_queue_size = LOG_QUEUE_DEFAULT_SIZE;
3115 
3116 #if !HAS_SHARED_QUEUE_SUPPORT
3117 u32
logger_set_queue_size(u32 n)3118 logger_set_queue_size(u32 n)
3119 {
3120     if(n < LOG_QUEUE_MIN_SIZE)
3121     {
3122         n = LOG_QUEUE_MIN_SIZE;
3123     }
3124     else if(n > LOG_QUEUE_MAX_SIZE)
3125     {
3126         n = LOG_QUEUE_MAX_SIZE;
3127     }
3128 
3129     if(logger_queue_initialised && (logger_queue_size != n))
3130     {
3131         logger_queue_size = n;
3132         logger_queue_size = threaded_queue_set_maxsize(&logger_commit_queue, logger_queue_size);
3133     }
3134 
3135     return logger_queue_size;
3136 }
3137 #endif
3138 
3139 void
logger_init_ex(u32 queue_size,size_t shared_heap_size)3140 logger_init_ex(u32 queue_size, size_t shared_heap_size)
3141 {
3142 #if DEBUG_LOG_HANDLER
3143     debug_osformatln(termout, "logger_init_ex(%u)", queue_size);
3144     flushout();
3145 #endif
3146 
3147     if(!logger_initialised())
3148     {
3149         logger_thread_pid = getpid_ex();
3150 
3151 #if HAS_SHARED_QUEUE_SUPPORT
3152         shared_heap_init();
3153 
3154         if(shared_heap_size == 0)
3155         {
3156             shared_heap_size = 0x4000000 + LOGGER_HANDLE_SHARED_TABLE_SIZE; // 64MB
3157         }
3158 
3159         for(;;)
3160         {
3161             ya_result ret;
3162             if(ISOK(ret = shared_heap_create(shared_heap_size)))
3163             {
3164                 logger_shared_heap_id = (u8)ret;
3165                 break;
3166             }
3167 
3168             if(shared_heap_size < 0x10000)
3169             {
3170                 debug_osformatln(termerr, "logger: unable to allocate enough shared memory: %r", ret);
3171                 flusherr();
3172                 exit(1);
3173             }
3174 
3175             shared_heap_size <<= 1;
3176         }
3177 
3178         g_logger_handle_shared_table = shared_heap_alloc(logger_shared_heap_id, LOGGER_HANDLE_SHARED_TABLE_SIZE);
3179         if(g_logger_handle_shared_table == NULL)
3180         {
3181             debug_osformatln(termerr, "logger: unable to allocate handle table");
3182             flusherr();
3183             exit(1);
3184         }
3185 
3186         memset(g_logger_handle_shared_table, 0U,  LOGGER_HANDLE_SHARED_TABLE_SIZE);
3187 
3188         for(int i = 0; i < LOGGER_HANDLE_COUNT_MAX; ++i)
3189         {
3190             for(int j = 0; j < MSG_LEVEL_COUNT; ++j)
3191             {
3192                 ptr_vector_init(&g_logger_handle_shared_table[i].channels[j]);
3193             }
3194         }
3195 #endif
3196 
3197         if(!logger_queue_initialised)
3198         {
3199 #if HAS_SHARED_QUEUE_SUPPORT
3200             if(queue_size == 0)
3201             {
3202                 logger_queue_size = 1024 * 1024;
3203             }
3204 
3205             logger_shared_queue = shared_circular_buffer_create_ex(20U,  sizeof(logger_shared_space_t));
3206 
3207             if(logger_shared_queue == NULL)
3208             {
3209                 debug_osformatln(termerr, "logger: unable to allocate shared buffer: %r", ERRNO_ERROR);
3210                 flusherr();
3211                 exit(1);
3212             }
3213 
3214             logger_shared_space = (logger_shared_space_t*)shared_circular_buffer_additional_space_ptr(logger_shared_queue);
3215 #else
3216             if(queue_size != 0)
3217             {
3218                 logger_queue_size = queue_size;
3219             }
3220             threaded_queue_init(&logger_commit_queue, logger_queue_size); // not used anymore (replaced by a shared queue)
3221 #endif
3222             logger_queue_initialised = TRUE;
3223         }
3224 
3225         if(!logger_handle_init_done)
3226         {
3227             logger_handle_init_done = TRUE;
3228 
3229             ptr_vector_init(&logger_handles);
3230 
3231             format_class_init();
3232         }
3233 
3234 #ifndef WIN32
3235         logger_set_uid(getuid());
3236         logger_set_gid(getgid());
3237 #endif
3238 
3239         logger_handle_create("system", &g_system_logger);
3240 
3241         mutex_lock(&logger_mutex);
3242         _logger_initialised = TRUE;
3243         mutex_unlock(&logger_mutex);
3244     }
3245     else
3246     {
3247 #if DEBUG_LOG_HANDLER
3248         debug_osformatln(termout, "logger_init_ex(%u) : already initialised", logger_queue_size);
3249         flushout();
3250 #endif
3251     }
3252 }
3253 
3254 void
logger_init()3255 logger_init()
3256 {
3257     logger_init_ex(logger_queue_size, 0 );
3258 }
3259 
3260 void
logger_start()3261 logger_start()
3262 {
3263 #if DEBUG_LOG_HANDLER
3264     debug_osformatln(termout, "logger_start() ");
3265     flushout();
3266 #endif
3267 
3268     ya_result return_code;
3269 
3270     if(!logger_initialised())
3271     {
3272 #if DEBUG_LOG_HANDLER
3273         debug_osformatln(termout, "logger_start() : not initialised yet : calling");
3274         flushout();
3275 #endif
3276 
3277         logger_init();
3278     }
3279 
3280     if(logger_thread_pid != getpid_ex())
3281     {
3282 #if DEBUG_LOG_HANDLER
3283         debug_osformatln(termout, "logger_start() : not initialised by the same process");
3284         flushout();
3285 #endif
3286 
3287 #if DNSCORE_HAS_LOG_THREAD_TAG
3288         // push all tags to the logger process
3289 
3290         thread_tag_push_tags();
3291 #endif
3292         return;
3293     }
3294 
3295     mutex_lock(&logger_mutex);
3296     if(!_logger_started)
3297     {
3298 #if DEBUG_LOG_HANDLER
3299         debug_osformatln(termout, "logger_start() : starting");
3300         flushout();
3301 #endif
3302         if((return_code = thread_create(&logger_thread_id, logger_dispatcher_thread, NULL)) != 0)
3303         {
3304             mutex_unlock(&logger_mutex);
3305             debug_osformatln(termerr, "logger_start: pthread_create: %r", return_code);
3306             DIE(LOGGER_INITIALISATION_ERROR);
3307         }
3308 
3309         _logger_started = TRUE;
3310 
3311         mutex_unlock(&logger_mutex);
3312     }
3313     else
3314     {
3315         mutex_unlock(&logger_mutex);
3316 #if DEBUG_LOG_HANDLER
3317         debug_osformatln(termout, "logger_start() : already started");
3318         flushout();
3319 #endif
3320     }
3321 
3322 #if DEBUG_LOG_HANDLER
3323     debug_osformatln(termout, "logger_start() : started");
3324     flushout();
3325 #endif
3326 }
3327 
3328 #if !HAS_SHARED_QUEUE_SUPPORT
3329 static thread_t logger_server_id = 0;
3330 
3331 void
logger_start_server()3332 logger_start_server()
3333 {
3334     if(logger_initialised_and_started())
3335     {
3336         int ret;
3337         if((ret = thread_create(&logger_server_id, logger_server_dispatcher_thread, NULL)) != 0)
3338         {
3339             debug_osformatln(termerr, "logger_start_server: pthread_create: %r", ret);
3340             DIE(LOGGER_INITIALISATION_ERROR);
3341         }
3342     }
3343 }
3344 
3345 void
logger_stop_server()3346 logger_stop_server()
3347 {
3348     pthread_cancel(logger_server_id);
3349 }
3350 
3351 void
logger_start_client()3352 logger_start_client()
3353 {
3354 #if DEBUG_LOG_HANDLER
3355     debug_osformatln(termout, "logger_start_client() ");
3356     flushout();
3357 #endif
3358 
3359     ya_result ret;
3360 
3361     if(!logger_initialised())
3362     {
3363 #if DEBUG_LOG_HANDLER
3364         debug_osformatln(termout, "logger_start_client() : not initialised yet : calling");
3365         flushout();
3366 #endif
3367 
3368         logger_init();
3369     }
3370 
3371     if(!logger_started())
3372     {
3373 #if DEBUG_LOG_HANDLER
3374         debug_osformatln(termout, "logger_start_client() : starting");
3375         flushout();
3376 #endif
3377 
3378         if((ret = thread_create(&logger_thread_id, logger_client_dispatcher_thread, NULL)) != 0)
3379         {
3380             debug_osformatln(termerr, "logger_start: pthread_create: %r", ret);
3381             DIE(LOGGER_INITIALISATION_ERROR);
3382         }
3383 
3384         logger_is_client = TRUE;
3385         logger_started = TRUE;
3386     }
3387     else
3388     {
3389 #if DEBUG_LOG_HANDLER
3390         debug_osformatln(termout, "logger_start_client() : already started");
3391         flushout();
3392 #endif
3393     }
3394 
3395 #if DEBUG_LOG_HANDLER
3396     debug_osformatln(termout, "logger_start_client() : started");
3397     flushout();
3398 #endif
3399 }
3400 
3401 void
logger_stop_client()3402 logger_stop_client()
3403 {
3404     logger_stop();
3405     //pthread_cancel(logger_thread_id);
3406 }
3407 
3408 #endif
3409 
3410 static void
logger_send_message_stop_wait()3411 logger_send_message_stop_wait()
3412 {
3413 #if DEBUG_LOG_HANDLER
3414     debug_osformatln(termout, "logger_send_message_stop_wait()");
3415     flushout();
3416 #endif
3417 
3418 #if HAS_SHARED_QUEUE_SUPPORT
3419     async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
3420 #else
3421     async_wait_s aw;
3422     async_wait_init(&aw, 1);
3423 #endif
3424 
3425     logger_message* message = logger_message_alloc();
3426 #if HAS_SHARED_QUEUE_SUPPORT
3427     message->pid = getpid_ex();
3428 #endif
3429     message->type = LOGGER_MESSAGE_TYPE_STOP;
3430 #if HAS_SHARED_QUEUE_SUPPORT
3431     message->stop.aw = aw;
3432 #else
3433     message->stop.aw = &aw;
3434 #endif
3435 
3436     logger_message_post(message);
3437 
3438 #if DEBUG_LOG_HANDLER
3439     debug_osformatln(termout, "logger_send_message_stop_wait() : waiting");
3440     flushout();
3441 #endif
3442 
3443 #if HAS_SHARED_QUEUE_SUPPORT
3444     async_wait(aw);
3445     async_wait_destroy_shared(aw);
3446 #else
3447     async_wait(&aw);
3448     async_wait_finalize(&aw);
3449 #endif
3450 
3451 #if DEBUG_LOG_HANDLER
3452     debug_osformatln(termout, "logger_send_message_stop_wait() : should be stopped");
3453     flushout();
3454 #endif
3455 }
3456 
3457 u8
logger_set_shared_heap(u8 id)3458 logger_set_shared_heap(u8 id)
3459 {
3460     u8 ret = logger_shared_heap_id;
3461     logger_shared_heap_id = id;
3462     return ret;
3463 }
3464 
3465 void
logger_stop()3466 logger_stop()
3467 {
3468 #if DEBUG_LOG_HANDLER
3469     debug_osformatln(termout, "logger_stop()");
3470     flushout();
3471 #endif
3472 
3473     if(logger_initialised_and_started())
3474     {
3475         // send the stop order
3476 
3477         if(logger_thread_pid == getpid_ex())
3478         {
3479             logger_send_message_stop_wait();
3480 
3481 #if DEBUG_LOG_HANDLER
3482             debug_osformatln(termout, "logger_stop() : joining");
3483             flushout();
3484 #endif
3485 
3486             // wait for the end
3487 
3488             ya_result return_code;
3489 
3490             if((return_code = thread_join(logger_thread_id, NULL)) != 0)
3491             {
3492                 flushout();
3493                 flusherr();
3494                 debug_osformatln(termerr, "logger_stop: thread_join: %r", return_code);
3495                 flusherr();
3496             }
3497 
3498             logger_thread_id = 0;
3499             mutex_lock(&logger_mutex);
3500             _logger_started = FALSE;
3501             mutex_unlock(&logger_mutex);
3502         }
3503         else
3504         {
3505             // not the owner
3506         }
3507     }
3508 
3509 #if DEBUG_LOG_HANDLER
3510     debug_osformatln(termout, "logger_stop() : stopped");
3511     flushout();
3512 #endif
3513 }
3514 
3515 void
logger_finalize()3516 logger_finalize()
3517 {
3518 #if DEBUG_LOG_HANDLER
3519     debug_osformatln(termout, "logger_finalize()");
3520     flushout();
3521 #endif
3522 
3523     if(logger_thread_pid != getpid_ex())
3524     {
3525 #if DEBUG_LOG_HANDLER
3526         debug_osformatln(termout, "logger_finalize() : not owner");
3527         flushout();
3528 #endif
3529         return;
3530     }
3531 
3532     if(!logger_initialised())
3533     {
3534 #if DEBUG_LOG_HANDLER
3535         debug_osformatln(termout, "logger_finalize() : not initialised");
3536         flushout();
3537 #endif
3538         return;
3539     }
3540 
3541 #if HAS_SHARED_QUEUE_SUPPORT
3542     if(!shared_circular_buffer_empty(logger_shared_queue))
3543     {
3544 #if DEBUG_LOG_HANDLER
3545         debug_osformatln(termout, "logger_finalize() : queue is not empty : starting & flushing");
3546         flushout();
3547 #endif
3548         if(!logger_started())
3549         {
3550             logger_start();
3551             if(logger_wait_started())
3552             {
3553                 logger_flush();
3554             }
3555         }
3556         else
3557         {
3558             logger_flush();
3559         }
3560     }
3561 #else
3562     if(threaded_queue_size(&logger_commit_queue) > 0)
3563     {
3564 #if DEBUG_LOG_HANDLER
3565         debug_osformatln(termout, "logger_finalize() : queue is not empty : starting & flushing");
3566         flushout();
3567 #endif
3568         logger_start();
3569         logger_flush();
3570     }
3571 #endif
3572 
3573     if(logger_started())
3574     {
3575 #if DEBUG_LOG_HANDLER
3576         debug_osformatln(termout, "logger_finalize() : still running : stopping");
3577         flushout();
3578 #endif
3579         logger_stop();
3580     }
3581 
3582     /*
3583      * Ensure there is nothing left at all in the queue
3584      */
3585 
3586 #if HAS_SHARED_QUEUE_SUPPORT
3587     while(!shared_circular_buffer_empty(logger_shared_queue))
3588     {
3589         logger_message* message = (logger_message*)shared_circular_buffer_prepare_dequeue(logger_shared_queue);
3590         if(message->type == LOGGER_MESSAGE_TYPE_TEXT)
3591         {
3592             shared_heap_free(message->text.text);
3593         }
3594         shared_circular_buffer_commit_dequeue(logger_shared_queue);
3595     }
3596 #else
3597     while(threaded_queue_size(&logger_commit_queue) > 0)
3598     {
3599         logger_message* message = threaded_queue_dequeue(&logger_commit_queue);
3600 
3601 #if DEBUG_LOG_HANDLER
3602         debug_osformatln(termout, "logger_finalize() : freeing message of type %u", message->type);
3603         flushout();
3604 #endif
3605 
3606         if(message->type == LOGGER_MESSAGE_TYPE_TEXT)
3607         {
3608             ZFREE_ARRAY(message->text.text, message->text.text_buffer_length);
3609         }
3610         logger_message_free(message);
3611     }
3612 #endif
3613 
3614     if(logger_handle_init_done)
3615     {
3616 #if DEBUG_LOG_HANDLER
3617         debug_osformatln(termout, "logger_finalize() : flushing all channels");
3618         flushout();
3619 #endif
3620         logger_service_flush_all_channels();
3621 
3622         // closes all handles
3623 
3624         if(logger_thread_pid == getpid_ex()) // logger_handle_owner_pid
3625         {
3626 #if DEBUG_LOG_HANDLER
3627             debug_osformatln(termout, "logger_finalize() : closing all handles");
3628             flushout();
3629 #endif
3630             ptr_vector_callback_and_clear(&logger_handles, logger_handle_free);
3631             ptr_vector_destroy(&logger_handles);
3632 
3633             // closes all channels
3634 
3635 #if DEBUG_LOG_HANDLER
3636             debug_osformatln(termout, "logger_finalize() : closing all channels");
3637             flushout();
3638 #endif
3639 
3640             logger_service_channel_unregister_all();
3641         }
3642 
3643         logger_handle_init_done = FALSE;
3644     }
3645 
3646     if(logger_queue_initialised)
3647     {
3648 #if HAS_SHARED_QUEUE_SUPPORT
3649         shared_circular_buffer_destroy(logger_shared_queue);
3650 #else
3651         threaded_queue_finalize(&logger_commit_queue);
3652 #endif
3653         logger_queue_initialised = FALSE;
3654     }
3655 
3656     logger_set_path(NULL);
3657 
3658     mutex_lock(&logger_mutex);
3659     _logger_initialised = FALSE;
3660     mutex_unlock(&logger_mutex);
3661 
3662 #if DEBUG_LOG_HANDLER
3663     debug_osformatln(termout, "logger_finalize() : finalised");
3664     flushout();
3665 #endif
3666 }
3667 
3668 void
logger_flush()3669 logger_flush()
3670 {
3671 #if DEBUG_LOG_HANDLER > 1
3672     debug_osformatln(termout, "logger_flush()");
3673     flushout();
3674 #endif
3675 
3676     if(logger_initialised_and_started())
3677     {
3678         if(logger_thread_id != thread_self())
3679         {
3680 #if HAS_SHARED_QUEUE_SUPPORT
3681             async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
3682 #else
3683             async_wait_s aw;
3684             async_wait_init(&aw, 1);
3685 #endif
3686             logger_message* message = logger_message_alloc();
3687 #if DEBUG
3688             message->align0 = 0xde;
3689             message->align1 = 0xf00d;
3690 #endif
3691 #if HAS_SHARED_QUEUE_SUPPORT
3692             message->pid = getpid_ex();
3693 #endif
3694             message->channel_flush_all.tid = thread_self();
3695             message->type = LOGGER_MESSAGE_TYPE_CHANNEL_FLUSH_ALL;
3696 
3697 #if HAS_SHARED_QUEUE_SUPPORT
3698             message->channel_flush_all.aw = aw;
3699 #else
3700             message->channel_flush_all.aw = &aw;
3701 #endif
3702             logger_message_post(message);
3703 
3704             // avoid being stuck forever if the service is down
3705 
3706             while(logger_initialised_and_started())
3707             {
3708 #if HAS_SHARED_QUEUE_SUPPORT
3709                 if(async_wait_timeout(aw, ONE_SECOND_US))
3710                 {
3711                     //async_wait_destroy_shared(aw);
3712                     break;
3713                 }
3714 #else
3715                 if(async_wait_timeout(&aw, ONE_SECOND_US))
3716                 {
3717                     async_wait_finalize(&aw);
3718                     break;
3719                 }
3720 #endif
3721             }
3722 
3723             async_wait_destroy_shared(aw);
3724         }
3725         else
3726         {
3727             logger_service_flush_all_channels();
3728         }
3729     }
3730 #if DEBUG_LOG_HANDLER
3731     else
3732     {
3733         debug_osformatln(termout, "logger_flush() : i=%i s=%i", logger_initialised, logger_started());
3734         flushout();
3735     }
3736 #endif
3737 }
3738 
3739 void
logger_channel_close_all()3740 logger_channel_close_all()
3741 {
3742 #if DEBUG_LOG_HANDLER
3743     debug_osformatln(termout, "logger_close_all_channels()");
3744     flushout();
3745 #endif
3746 
3747     if(logger_initialised_and_started())
3748     {
3749 #if HAS_SHARED_QUEUE_SUPPORT
3750         async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
3751 #else
3752         async_wait_s aw;
3753         async_wait_init(&aw, 1);
3754 #endif
3755 
3756         logger_message* message = logger_message_alloc();
3757 
3758 #if DEBUG
3759         ZEROMEMORY(message, sizeof(logger_message));
3760 #endif
3761 #if HAS_SHARED_QUEUE_SUPPORT
3762         message->pid = getpid_ex();
3763 #endif
3764         message->type = LOGGER_MESSAGE_TYPE_CHANNEL_CLOSE_ALL;
3765 #if HAS_SHARED_QUEUE_SUPPORT
3766         message->channel_flush_all.aw = aw;
3767 #else
3768         message->channel_flush_all.aw = &aw;
3769 #endif
3770 
3771         logger_message_post(message);
3772 
3773         // avoid being stuck forever if the service is down
3774 
3775         while(logger_initialised_and_started())
3776         {
3777 #if HAS_SHARED_QUEUE_SUPPORT
3778             formatln("logger_channel_close_all");
3779             if(async_wait_timeout(aw, ONE_SECOND_US))
3780             {
3781                 //async_wait_destroy_shared(aw);
3782                 break;
3783             }
3784 #else
3785             if(async_wait_timeout(&aw, ONE_SECOND_US))
3786             {
3787                 async_wait_finalize(&aw);
3788                 break;
3789             }
3790 #endif
3791         }
3792 
3793         async_wait_destroy_shared(aw);
3794     }
3795 #if DEBUG_LOG_HANDLER
3796     else
3797     {
3798         debug_osformatln(termout, "logger_close_all_channels() : i=%i s=%i", logger_initialised, logger_started());
3799         flushout();
3800     }
3801 #endif
3802 }
3803 
3804 void
logger_reopen()3805 logger_reopen()
3806 {
3807 #if DEBUG_LOG_HANDLER
3808     debug_osformatln(termout, "logger_reopen()");
3809     flushout();
3810 #endif
3811 
3812     if(logger_initialised_and_started())
3813     {
3814         // even for a lflag, the message NEEDS to be enqueued because
3815         // 1) it activates the service
3816         // 2) synchronises the memory between the threads (memory wall)
3817 
3818 #if HAS_SHARED_QUEUE_SUPPORT
3819         async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
3820 #else
3821         async_wait_s aw;
3822         async_wait_init(&aw, 1);
3823 #endif
3824 
3825         logger_message* message = logger_message_alloc();
3826 
3827 #if DEBUG
3828         ZEROMEMORY(message, sizeof(logger_message));
3829 #endif
3830 #if HAS_SHARED_QUEUE_SUPPORT
3831         message->pid = getpid_ex();
3832 #endif
3833         message->type = LOGGER_MESSAGE_TYPE_CHANNEL_REOPEN_ALL;
3834 #if HAS_SHARED_QUEUE_SUPPORT
3835         message->channel_reopen_all.aw = aw;
3836 #else
3837         message->channel_reopen_all.aw = &aw;
3838 #endif
3839         mutex_lock(&logger_mutex);
3840         logger_shared_space->_logger_reopen_request_message = message;
3841         mutex_unlock(&logger_mutex);
3842 
3843         logger_message_post(message);
3844 
3845         while(logger_initialised_and_started())
3846         {
3847 #if HAS_SHARED_QUEUE_SUPPORT
3848 #if DEBUG_LOG_HANDLER
3849             formatln("logger_reopen");
3850 #endif
3851             if(async_wait_timeout(aw, ONE_SECOND_US))
3852             {
3853                 //async_wait_destroy_shared(aw);
3854                 break;
3855             }
3856 #else
3857             if(async_wait_timeout(&aw, ONE_SECOND_US))
3858             {
3859                 async_wait_finalize(&aw);
3860                 break;
3861             }
3862 #endif
3863         }
3864 
3865         async_wait_destroy_shared(aw);
3866     }
3867 #if DEBUG_LOG_HANDLER
3868     else
3869     {
3870         debug_osformatln(termout, "logger_reopen() : i=%i s=%i", logger_initialised, logger_started());
3871         flushout();
3872     }
3873 #endif
3874 }
3875 
3876 void
logger_sink_noblock()3877 logger_sink_noblock()
3878 {
3879     mutex_lock(&logger_mutex);
3880     logger_shared_space->_logger_sink_request_message = LOGGER_MESSAGE_SINK_FAKE;
3881     mutex_unlock(&logger_mutex);
3882 }
3883 
3884 void
logger_sink()3885 logger_sink()
3886 {
3887 #if DEBUG_LOG_HANDLER
3888     debug_osformatln(termout, "logger_reopen()");
3889     flushout();
3890 #endif
3891 
3892     if(logger_initialised_and_started())
3893     {
3894         // even for a lflag, the message NEEDS to be enqueued because
3895         // 1) it activates the service
3896         // 2) synchronises the memory between the threads (memory wall)
3897 
3898 #if HAS_SHARED_QUEUE_SUPPORT
3899         async_wait_s *aw = async_wait_create_shared(logger_shared_heap_id, 1);
3900 #else
3901         async_wait_s aw;
3902         async_wait_init(&aw, 1);
3903 #endif
3904         logger_message* message = logger_message_alloc();
3905 #if DEBUG
3906         ZEROMEMORY(message, sizeof(logger_message));
3907 #endif
3908 #if HAS_SHARED_QUEUE_SUPPORT
3909         message->pid = getpid_ex();
3910 #endif
3911         message->type = LOGGER_MESSAGE_TYPE_CHANNEL_SINK_ALL;
3912 #if HAS_SHARED_QUEUE_SUPPORT
3913         message->channel_sink_all.aw = aw;
3914 #else
3915         message->channel_sink_all.aw = &aw;
3916 #endif
3917         mutex_lock(&logger_mutex);
3918         logger_shared_space->_logger_sink_request_message = message;
3919         mutex_unlock(&logger_mutex);
3920 
3921         logger_message_post(message);
3922 
3923         while(logger_initialised_and_started())
3924         {
3925 #if HAS_SHARED_QUEUE_SUPPORT
3926 #if DEBUG
3927             formatln("logger_sink");
3928 #endif
3929             if(async_wait_timeout(aw, ONE_SECOND_US))
3930             {
3931                 //async_wait_destroy_shared(aw);
3932                 break;
3933             }
3934 #else
3935             if(async_wait_timeout(&aw, ONE_SECOND_US))
3936             {
3937                 async_wait_finalize(&aw);
3938                 break;
3939             }
3940 #endif
3941 #if DEBUG
3942             mutex_lock(&logger_mutex);
3943             bool stop_looping = logger_shared_space->_logger_sink_request_message != NULL;
3944             mutex_unlock(&logger_mutex);
3945             if(stop_looping)
3946             {
3947                 formatln("_logger_sink_requested is FALSE but the synchronization hasn't been released yet");
3948             }
3949 #endif
3950         }
3951 
3952         async_wait_destroy_shared(aw);
3953     }
3954 #if DEBUG_LOG_HANDLER
3955     else
3956     {
3957         debug_osformatln(termout, "logger_reopen() : i=%i s=%i", logger_initialised, logger_started());
3958         flushout();
3959     }
3960 #endif
3961 }
3962 
3963 bool
logger_is_running()3964 logger_is_running()
3965 {
3966     return logger_started();
3967 }
3968 
3969 void
logger_handle_vmsg(logger_handle * handle,u32 level,const char * fmt,va_list args)3970 logger_handle_vmsg(logger_handle* handle, u32 level, const char* fmt, va_list args)
3971 {
3972     /*
3973      * check that the handle has got a channel for the level
3974      */
3975 
3976 #if DEBUG
3977     if((handle == NULL) || (handle->magic_check != LOGGER_HANDLE_MAGIC_CHECK))
3978     {
3979 #if DEBUG_LOG_HANDLER
3980         debug_stacktrace_print(termout, debug_stacktrace_get());
3981         debug_stacktrace_print(termerr, debug_stacktrace_get());
3982         flushout();
3983         flusherr();
3984 #endif
3985         abort();
3986     }
3987 
3988     if(level >= MSG_LEVEL_COUNT)
3989     {
3990         debug_osformatln(termerr, "bad message level %u", level);
3991         logger_handle_trigger_emergency_shutdown();
3992         return;
3993     }
3994 
3995     if(level <= MSG_ERR)
3996     {
3997         sleep(0);
3998     }
3999 
4000 #endif
4001 
4002     if(handle == NULL)
4003     {
4004         if(level <= exit_level)
4005         {
4006             logger_handle_trigger_emergency_shutdown();
4007         }
4008         return;
4009     }
4010 
4011     if(level > logger_level)
4012     {
4013         return;
4014     }
4015 
4016     s32 channel_count = handle->channels[level].offset;
4017 
4018     if(channel_count < 0) /* it's count-1 actually */
4019     {
4020         return;
4021     }
4022 
4023     /**
4024      * @note At this point we KNOW we have to print something.
4025      */
4026 
4027     output_stream baos;
4028 #if HAS_SHARED_QUEUE_SUPPORT
4029     shared_heap_output_stream_context shos_context;
4030 #else
4031     bytezarray_output_stream_context baos_context;
4032 #endif
4033 
4034     /*
4035      * DEFAULT_MAX_LINE_SIZE is the base size.
4036      *
4037      * The output stream has the BYTEARRAY_DYNAMIC flag set in order to allow
4038      * bigger sentences.
4039      *
4040      */
4041 
4042     /* Will use the tmp buffer, but alloc a bigger one if required. */
4043 #if HAS_SHARED_QUEUE_SUPPORT
4044     shared_heap_output_stream_init_ex_static(&baos, logger_shared_heap_id, NULL, 48, SHARED_HEAP_DYNAMIC, &shos_context);
4045 #else
4046     bytezarray_output_stream_init_ex_static(&baos, NULL, DEFAULT_MAX_LINE_SIZE, BYTEARRAY_DYNAMIC, &baos_context);
4047 #endif
4048 
4049     if(FAIL(vosformat(&baos, fmt, args)))
4050     {
4051 #if HAS_SHARED_QUEUE_SUPPORT
4052         shared_heap_output_stream_reset(&baos);
4053 #else
4054         bytezarray_output_stream_reset(&baos);
4055 #endif
4056         osprint(&baos, "*** ERROR : MESSAGE FORMATTING FAILED ***");
4057     }
4058 
4059     output_stream_write_u8(&baos, 0);
4060 
4061     logger_message* message = logger_message_alloc();
4062 
4063 #if HAS_SHARED_QUEUE_SUPPORT
4064     message->pid = getpid_ex();
4065 #endif
4066     message->type = LOGGER_MESSAGE_TYPE_TEXT;
4067     message->text.level = level;
4068     message->text.flags = 0;
4069 
4070 #if HAS_SHARED_QUEUE_SUPPORT
4071     message->text.text_length = shared_heap_output_stream_size(&baos) - 1;
4072     message->text.text_buffer_length = shared_heap_output_stream_buffer_size(&baos);
4073 #else
4074     message->text.text_length = bytezarray_output_stream_size(&baos) - 1;
4075     message->text.text_buffer_length = bytezarray_output_stream_buffer_size(&baos);
4076 #endif
4077 
4078     message->text.handle = handle;
4079 
4080 #if HAS_SHARED_QUEUE_SUPPORT
4081     message->text.text = shared_heap_output_stream_detach(&baos);
4082 #else
4083     message->text.text = bytezarray_output_stream_detach(&baos);
4084 #endif
4085 
4086 #if SIZEOF_TIMEVAL <= 8
4087     gettimeofday(&message->text.tv, NULL);
4088 #else
4089     message->text.timestamp = timeus();
4090 #endif
4091 
4092 #if !HAS_SHARED_QUEUE_SUPPORT
4093     // prefix
4094     // prefix_len
4095 
4096     message->text.rc = 0;
4097 
4098 #if DEBUG || HAS_LOG_PID
4099     message->text.pid = getpid_ex();
4100 #endif
4101 #endif
4102 
4103 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
4104     message->text.thread_id = thread_self();
4105 #endif
4106 
4107     logger_message_post(message);
4108 
4109     output_stream_close(&baos); /* Frees the memory */
4110 
4111     if(level <= exit_level)
4112     {
4113         logger_handle_trigger_emergency_shutdown();
4114     }
4115 }
4116 
4117 void
logger_handle_msg_nocull(logger_handle * handle,u32 level,const char * fmt,...)4118 logger_handle_msg_nocull(logger_handle* handle, u32 level, const char* fmt, ...)
4119 {
4120     /**
4121      * @note At this point we KNOW we have to print something.
4122      */
4123 
4124 #if DEBUG
4125 
4126     if((handle == NULL) || (handle->magic_check != LOGGER_HANDLE_MAGIC_CHECK))
4127     {
4128 #if DEBUG_LOG_HANDLER
4129         debug_stacktrace_print(termout, debug_stacktrace_get());
4130         debug_stacktrace_print(termerr, debug_stacktrace_get());
4131         flushout();
4132         flusherr();
4133 #endif
4134         abort();
4135     }
4136 
4137 #ifdef NDEBUG
4138     size_t sizeof_logger_message = sizeof(logger_message);
4139     size_t sizeof_logger_message_text_s = sizeof(struct logger_message_text_s);
4140     assert(sizeof_logger_message_text_s <= 64);
4141     assert(sizeof_logger_message <= 64);
4142     (void)sizeof_logger_message;
4143     (void)sizeof_logger_message_text_s;
4144 #endif
4145 
4146 #endif
4147 
4148     output_stream baos;
4149 #if HAS_SHARED_QUEUE_SUPPORT
4150     shared_heap_output_stream_context shos_context;
4151 #else
4152     bytezarray_output_stream_context baos_context;
4153 #endif
4154     /*
4155      * DEFAULT_MAX_LINE_SIZE is the base size.
4156      *
4157      * The output stream has the BYTEARRAY_DYNAMIC flag set in order to allow
4158      * bigger sentences.
4159      *
4160      */
4161 
4162     va_list args;
4163     va_start(args, fmt);
4164 
4165     /* Will use the tmp buffer, but alloc a bigger one if required. */
4166 #if HAS_SHARED_QUEUE_SUPPORT
4167     shared_heap_output_stream_init_ex_static(&baos, logger_shared_heap_id, NULL, 48, SHARED_HEAP_DYNAMIC, &shos_context);
4168 #else
4169     bytezarray_output_stream_init_ex_static(&baos, NULL, DEFAULT_MAX_LINE_SIZE, BYTEARRAY_DYNAMIC, &baos_context);
4170 #endif
4171 
4172     if(FAIL(vosformat(&baos, fmt, args)))
4173     {
4174 #if HAS_SHARED_QUEUE_SUPPORT
4175         shared_heap_output_stream_reset(&baos);
4176 #else
4177         bytezarray_output_stream_reset(&baos);
4178 #endif
4179         osprint(&baos, "*** ERROR : MESSAGE FORMATTING FAILED ***");
4180     }
4181 
4182     output_stream_write_u8(&baos, 0);
4183 
4184     logger_message* message = logger_message_alloc();
4185 
4186 #if HAS_SHARED_QUEUE_SUPPORT
4187     message->pid = getpid_ex();
4188 #endif
4189     message->type = LOGGER_MESSAGE_TYPE_TEXT;
4190     message->text.level = level;
4191     message->text.flags = 0;
4192 
4193 #if HAS_SHARED_QUEUE_SUPPORT
4194     message->text.text_length = shared_heap_output_stream_size(&baos) - 1;
4195     message->text.text_buffer_length = shared_heap_output_stream_buffer_size(&baos);
4196 #else
4197     message->text.text_length = bytezarray_output_stream_size(&baos) - 1;
4198     message->text.text_buffer_length = bytezarray_output_stream_buffer_size(&baos);
4199 #endif
4200 
4201     message->text.handle = handle;
4202 
4203 #if HAS_SHARED_QUEUE_SUPPORT
4204     message->text.text = shared_heap_output_stream_detach(&baos);
4205 #else
4206     message->text.text = bytezarray_output_stream_detach(&baos);
4207 #endif
4208 
4209     assert(message->text.text != NULL);
4210 
4211 #if SIZEOF_TIMEVAL <= 8
4212     gettimeofday(&message->text.tv, NULL);
4213 #else
4214     message->text.timestamp = timeus();
4215 #endif
4216 
4217     // prefix
4218     // prefix_len
4219 
4220 #if !HAS_SHARED_QUEUE_SUPPORT
4221     message->text.rc = 0;
4222 
4223 #if DEBUG || HAS_LOG_PID
4224     message->text.pid = getpid_ex();
4225 #endif
4226 #endif
4227 
4228 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
4229     message->text.thread_id = thread_self();
4230 #endif
4231 
4232     logger_message_post(message);
4233 
4234     va_end(args);
4235 
4236     output_stream_close(&baos); /* Frees the memory */
4237 }
4238 
4239 
4240 void
logger_handle_msg(logger_handle * handle,u32 level,const char * fmt,...)4241 logger_handle_msg(logger_handle* handle, u32 level, const char* fmt, ...)
4242 {
4243     /*
4244      * check that the handle has got a channel for the level
4245      */
4246 
4247 #if DEBUG
4248     if((handle == NULL) || (handle->magic_check != LOGGER_HANDLE_MAGIC_CHECK))
4249     {
4250 #if DEBUG_LOG_HANDLER
4251         debug_stacktrace_print(termout, debug_stacktrace_get());
4252         debug_stacktrace_print(termerr, debug_stacktrace_get());
4253         flushout();
4254         flusherr();
4255 #endif
4256         abort();
4257     }
4258 
4259     if(level >= MSG_LEVEL_COUNT)
4260     {
4261         debug_osformatln(termerr, "bad message level %u", level);
4262         logger_handle_trigger_emergency_shutdown();
4263         return;
4264     }
4265 
4266     if(level <= MSG_ERR)
4267     {
4268         sleep(0);
4269     }
4270 
4271 #endif
4272 
4273     if(handle == NULL)
4274     {
4275         if(level <= exit_level)
4276         {
4277             logger_handle_trigger_emergency_shutdown();
4278         }
4279         return;
4280     }
4281 
4282     if(level > logger_level)
4283     {
4284         return;
4285     }
4286 
4287     s32 channel_count = handle->channels[level].offset;
4288 
4289     if(channel_count < 0) /* it's count-1 actually */
4290     {
4291         return;
4292     }
4293 
4294     /**
4295      * @note At this point we KNOW we have to print something.
4296      */
4297 
4298     output_stream baos;
4299 #if HAS_SHARED_QUEUE_SUPPORT
4300     shared_heap_output_stream_context baos_context;
4301 #else
4302     bytezarray_output_stream_context baos_context;
4303 #endif
4304 
4305     /*
4306      * DEFAULT_MAX_LINE_SIZE is the base size.
4307      *
4308      * The output stream has the BYTEARRAY_DYNAMIC flag set in order to allow
4309      * bigger sentences.
4310      *
4311      */
4312 
4313     va_list args;
4314     va_start(args, fmt);
4315 
4316     /* Will use the tmp buffer, but alloc a bigger one if required. */
4317 #if HAS_SHARED_QUEUE_SUPPORT
4318     shared_heap_output_stream_init_ex_static(&baos, logger_shared_heap_id, NULL, DEFAULT_MAX_LINE_SIZE, SHARED_HEAP_DYNAMIC, &baos_context);
4319 #else
4320     bytezarray_output_stream_init_ex_static(&baos, NULL, DEFAULT_MAX_LINE_SIZE, BYTEARRAY_DYNAMIC, &baos_context);
4321 #endif
4322 
4323     if(FAIL(vosformat(&baos, fmt, args)))
4324     {
4325 #if HAS_SHARED_QUEUE_SUPPORT
4326         shared_heap_output_stream_reset(&baos);
4327 #else
4328         bytezarray_output_stream_reset(&baos);
4329 #endif
4330         osprint(&baos, "*** ERROR : MESSAGE FORMATTING FAILED ***");
4331     }
4332 
4333     output_stream_write_u8(&baos, 0);
4334 
4335     logger_message* message = logger_message_alloc();
4336 
4337 #if HAS_SHARED_QUEUE_SUPPORT
4338     message->pid = getpid_ex();
4339 #endif
4340     message->type = LOGGER_MESSAGE_TYPE_TEXT;
4341     message->text.level = level;
4342     message->text.flags = 0;
4343 
4344 #if HAS_SHARED_QUEUE_SUPPORT
4345     message->text.text_length = shared_heap_output_stream_size(&baos) - 1;
4346     message->text.text_buffer_length = shared_heap_output_stream_buffer_size(&baos);
4347 #else
4348     message->text.text_length = bytezarray_output_stream_size(&baos) - 1;
4349     message->text.text_buffer_length = bytezarray_output_stream_buffer_size(&baos);
4350 #endif
4351 
4352     message->text.handle = handle;
4353 
4354 #if HAS_SHARED_QUEUE_SUPPORT
4355     message->text.text = shared_heap_output_stream_detach(&baos);
4356 #else
4357     message->text.text = bytezarray_output_stream_detach(&baos);
4358 #endif
4359 
4360     assert(message->text.text != NULL);
4361 
4362 #if SIZEOF_TIMEVAL <= 8
4363     gettimeofday(&message->text.tv, NULL);
4364 #else
4365     message->text.timestamp = timeus();
4366 #endif
4367 
4368     // prefix
4369     // prefix_len
4370 
4371 #if !HAS_SHARED_QUEUE_SUPPORT
4372     message->text.rc = 0;
4373 
4374 #if DEBUG || HAS_LOG_PID
4375     message->text.pid = getpid_ex();
4376 #endif
4377 #endif
4378 
4379 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
4380     message->text.thread_id = thread_self();
4381 #endif
4382 
4383     logger_message_post(message);
4384 
4385     va_end(args);
4386 
4387     output_stream_close(&baos); /* Frees the memory */
4388 
4389     if(level <= exit_level)
4390     {
4391         exit_level = 0;
4392         if(!dnscore_shuttingdown())
4393         {
4394             logger_handle_trigger_emergency_shutdown();
4395         }
4396     }
4397 }
4398 
4399 void
logger_handle_msg_text(logger_handle * handle,u32 level,const char * text,u32 text_len)4400 logger_handle_msg_text(logger_handle* handle, u32 level, const char* text, u32 text_len)
4401 {
4402     /*
4403      * check that the handle has got a channel for the level
4404      */
4405 
4406 #if DEBUG
4407     if((handle == NULL) || (handle->magic_check != LOGGER_HANDLE_MAGIC_CHECK))
4408     {
4409 #if DEBUG_LOG_HANDLER
4410         debug_stacktrace_print(termout, debug_stacktrace_get());
4411         debug_stacktrace_print(termerr, debug_stacktrace_get());
4412         flushout();
4413         flusherr();
4414 #endif
4415         abort();
4416     }
4417 
4418     if(level >= MSG_LEVEL_COUNT)
4419     {
4420         debug_osformatln(termerr, "bad message level %u", level);
4421         logger_handle_trigger_emergency_shutdown();
4422         return;
4423     }
4424 
4425     if(level <= MSG_ERR)
4426     {
4427         sleep(0);
4428     }
4429 
4430 #endif
4431 
4432     if(handle == NULL)
4433     {
4434         if(level <= exit_level)
4435         {
4436             logger_handle_trigger_emergency_shutdown();
4437         }
4438         return;
4439     }
4440 
4441     if(level > logger_level)
4442     {
4443         return;
4444     }
4445 
4446     s32 channel_count = handle->channels[level].offset;
4447 
4448     if(channel_count < 0) /* it's count-1 actually */
4449     {
4450         return;
4451     }
4452 
4453     logger_message* message = logger_message_alloc();
4454 
4455 #if HAS_SHARED_QUEUE_SUPPORT
4456     message->pid = getpid_ex();
4457 #endif
4458     message->type = LOGGER_MESSAGE_TYPE_TEXT;
4459     message->text.level = level;
4460     message->text.flags = 0;
4461 
4462     message->text.text_length = text_len;
4463     message->text.text_buffer_length = text_len;
4464     message->text.handle = handle;
4465 
4466 #if HAS_SHARED_QUEUE_SUPPORT
4467     message->text.text = (u8*)shared_heap_wait_alloc(logger_shared_heap_id, text_len);
4468 #else
4469     ZALLOC_ARRAY_OR_DIE(u8*, message->text. text, text_len, LOGRTEXT_TAG);
4470 #endif
4471     assert(message->text.text != NULL);
4472 
4473     memcpy(message->text.text, text, text_len);
4474 
4475 #if SIZEOF_TIMEVAL <= 8
4476     gettimeofday(&message->text.tv, NULL);
4477 #else
4478     message->text.timestamp = timeus();
4479 #endif
4480 
4481     // prefix
4482     // prefix_len
4483 
4484 #if !HAS_SHARED_QUEUE_SUPPORT
4485     message->text.rc = 0;
4486 
4487 #if DEBUG || HAS_LOG_PID
4488     message->text.pid = getpid_ex();
4489 #endif
4490 #endif
4491 
4492 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
4493     message->text.thread_id = thread_self();
4494 #endif
4495 
4496     logger_message_post(message);
4497 
4498     if(level <= exit_level)
4499     {
4500         logger_handle_trigger_emergency_shutdown();
4501     }
4502 }
4503 
4504 void
logger_handle_msg_text_ext(logger_handle * handle,u32 level,const char * text,u32 text_len,const char * prefix,u32 prefix_len,u16 flags)4505 logger_handle_msg_text_ext(logger_handle* handle, u32 level, const char* text, u32 text_len, const char* prefix, u32 prefix_len, u16 flags)
4506 {
4507         /*
4508      * check that the handle has got a channel for the level
4509      */
4510 
4511 #if DEBUG
4512     if((handle == NULL) || (handle->magic_check != LOGGER_HANDLE_MAGIC_CHECK))
4513     {
4514 #if DEBUG_LOG_HANDLER
4515         debug_stacktrace_print(termout, debug_stacktrace_get());
4516         debug_stacktrace_print(termerr, debug_stacktrace_get());
4517         flushout();
4518         flusherr();
4519 #endif
4520         abort();
4521     }
4522 
4523     if(level >= MSG_LEVEL_COUNT)
4524     {
4525         debug_osformatln(termerr, "bad message level %u", level);
4526         logger_handle_trigger_emergency_shutdown();
4527         return;
4528     }
4529 
4530     if(level <= MSG_ERR)
4531     {
4532         sleep(0);
4533     }
4534 
4535 #endif
4536 
4537     if(handle == NULL)
4538     {
4539         if(level <= exit_level)
4540         {
4541             logger_handle_trigger_emergency_shutdown();
4542         }
4543         return;
4544     }
4545 
4546     if(level > logger_level)
4547     {
4548         return;
4549     }
4550 
4551     s32 channel_count = handle->channels[level].offset;
4552 
4553     if(channel_count < 0) /* it's count-1 actually */
4554     {
4555         return;
4556     }
4557 
4558     logger_message* message = logger_message_alloc();
4559 
4560 #if HAS_SHARED_QUEUE_SUPPORT
4561     message->pid = getpid_ex();
4562 #endif
4563     message->type = LOGGER_MESSAGE_TYPE_TEXT;
4564     message->text.level = level;
4565     message->text.flags = flags;
4566 
4567     message->text.text_length = text_len;
4568     message->text.text_buffer_length = text_len;
4569 
4570     message->text.handle = handle;
4571 
4572     ZALLOC_ARRAY_OR_DIE(u8*, message->text.text, text_len, LOGRTEXT_TAG);
4573     memcpy(message->text.text, text, text_len);
4574 
4575 #if SIZEOF_TIMEVAL <= 8
4576     gettimeofday(&message->text.tv, NULL);
4577 #else
4578     message->text.timestamp = timeus();
4579 #endif
4580 
4581     message->text.prefix = (const u8*)prefix;
4582     message->text.prefix_length = prefix_len;
4583 
4584 #if !HAS_SHARED_QUEUE_SUPPORT
4585     message->text.rc = 0;
4586 
4587 #if DEBUG || HAS_LOG_PID
4588     message->text.pid = getpid_ex();
4589 #endif
4590 #endif
4591 
4592 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
4593     message->text.thread_id = thread_self();
4594 #endif
4595 
4596     logger_message_post(message);
4597 
4598     if(level <= exit_level)
4599     {
4600         logger_handle_trigger_emergency_shutdown();
4601     }
4602 }
4603 
4604 void
logger_handle_try_msg(logger_handle * handle,u32 level,const char * fmt,...)4605 logger_handle_try_msg(logger_handle* handle, u32 level, const char* fmt, ...)
4606 {
4607     /*
4608      * check that the handle has got a channel for the level
4609      */
4610 
4611 #if DEBUG
4612     if((handle == NULL) || (handle->magic_check != LOGGER_HANDLE_MAGIC_CHECK))
4613     {
4614 #if DEBUG_LOG_HANDLER
4615         debug_stacktrace_print(termout, debug_stacktrace_get());
4616         debug_stacktrace_print(termerr, debug_stacktrace_get());
4617         flushout();
4618         flusherr();
4619 #endif
4620         abort();
4621     }
4622 
4623     if(level >= MSG_LEVEL_COUNT)
4624     {
4625         debug_osformatln(termerr, "bad message level %u", level);
4626         logger_handle_trigger_emergency_shutdown();
4627         return;
4628     }
4629 
4630     if(level <= MSG_ERR)
4631     {
4632         sleep(0);
4633     }
4634 
4635 #endif
4636 
4637     if(handle == NULL)
4638     {
4639         if(level <= exit_level)
4640         {
4641             logger_handle_trigger_emergency_shutdown();
4642         }
4643         return;
4644     }
4645 
4646     if(level > logger_level)
4647     {
4648         return;
4649     }
4650 
4651     s32 channel_count = handle->channels[level].offset;
4652 
4653     if(channel_count < 0) /* it's count-1 actually */
4654     {
4655         return;
4656     }
4657 
4658     logger_message* message = logger_message_try_alloc();
4659 
4660     if(message == NULL)
4661     {
4662         return;
4663     }
4664 
4665     /**
4666      * @note At this point we KNOW we have to print something.
4667      */
4668 
4669     output_stream baos;
4670 #if HAS_SHARED_QUEUE_SUPPORT
4671     shared_heap_output_stream_context baos_context;
4672 #else
4673     bytezarray_output_stream_context baos_context;
4674 #endif
4675 
4676     /*
4677      * DEFAULT_MAX_LINE_SIZE is the base size.
4678      *
4679      * The output stream has the BYTEARRAY_DYNAMIC flag set in order to allow
4680      * bigger sentences.
4681      *
4682      */
4683 
4684     va_list args;
4685     va_start(args, fmt);
4686 
4687     /* Will use the tmp buffer, but alloc a bigger one if required. */
4688 #if HAS_SHARED_QUEUE_SUPPORT
4689     shared_heap_output_stream_init_ex_static(&baos, logger_shared_heap_id, NULL, DEFAULT_MAX_LINE_SIZE, SHARED_HEAP_DYNAMIC, &baos_context);
4690 #else
4691     bytezarray_output_stream_init_ex_static(&baos, NULL, DEFAULT_MAX_LINE_SIZE, BYTEARRAY_DYNAMIC, &baos_context);
4692 #endif
4693 
4694     if(FAIL(vosformat(&baos, fmt, args)))
4695     {
4696 #if HAS_SHARED_QUEUE_SUPPORT
4697         shared_heap_output_stream_reset(&baos);
4698 #else
4699         bytezarray_output_stream_reset(&baos);
4700 #endif
4701         osprint(&baos, "*** ERROR : MESSAGE FORMATTING FAILED ***");
4702     }
4703 
4704     output_stream_write_u8(&baos, 0);
4705 
4706 #if HAS_SHARED_QUEUE_SUPPORT
4707     message->pid = getpid_ex();
4708 #endif
4709     message->type = LOGGER_MESSAGE_TYPE_TEXT;
4710     message->text.level = level;
4711     message->text.flags = 0;
4712 
4713 #if HAS_SHARED_QUEUE_SUPPORT
4714     message->text.text_length = shared_heap_output_stream_size(&baos) - 1;
4715     message->text.text_buffer_length = shared_heap_output_stream_buffer_size(&baos);
4716 #else
4717     message->text.text_length = bytezarray_output_stream_size(&baos) - 1;
4718     message->text.text_buffer_length = bytezarray_output_stream_buffer_size(&baos);
4719 #endif
4720 
4721     message->text.handle = handle;
4722 
4723 #if HAS_SHARED_QUEUE_SUPPORT
4724     message->text.text = shared_heap_output_stream_detach(&baos);
4725 #else
4726     message->text.text = bytezarray_output_stream_detach(&baos);
4727 #endif
4728 
4729     assert(message->text.text != NULL);
4730 
4731 #if SIZEOF_TIMEVAL <= 8
4732     gettimeofday(&message->text.tv, NULL);
4733 #else
4734     message->text.timestamp = timeus();
4735 #endif
4736 
4737     // prefix
4738     // prefix_len
4739 
4740 #if !HAS_SHARED_QUEUE_SUPPORT
4741     message->text.rc = 0;
4742 
4743 #if DEBUG || HAS_LOG_PID
4744     message->text.pid = getpid_ex();
4745 #endif
4746 #endif
4747 
4748 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
4749     message->text.thread_id = thread_self();
4750 #endif
4751 
4752 #if HAS_SHARED_QUEUE_SUPPORT
4753     logger_message_post(message);
4754 #else
4755     if(!threaded_queue_try_enqueue(&logger_commit_queue, message))
4756     {
4757         // could not enqueue
4758         ZFREE_ARRAY(message->text.text, message->text.text_buffer_length);
4759         logger_message_free(message);
4760     }
4761 #endif
4762 
4763     va_end(args);
4764 
4765     output_stream_close(&baos); /* Frees the memory */
4766 
4767     if(level <= exit_level)
4768     {
4769         exit_level = 0;
4770         if(!dnscore_shuttingdown())
4771         {
4772             logger_handle_trigger_emergency_shutdown();
4773         }
4774     }
4775 }
4776 
4777 void
logger_handle_try_msg_text(logger_handle * handle,u32 level,const char * text,u32 text_len)4778 logger_handle_try_msg_text(logger_handle* handle, u32 level, const char* text, u32 text_len)
4779 {
4780     /*
4781      * check that the handle has got a channel for the level
4782      */
4783 
4784 #if DEBUG
4785     if((handle == NULL) || (handle->magic_check != LOGGER_HANDLE_MAGIC_CHECK))
4786     {
4787 #if DEBUG_LOG_HANDLER
4788         debug_stacktrace_print(termout, debug_stacktrace_get());
4789         debug_stacktrace_print(termerr, debug_stacktrace_get());
4790         flushout();
4791         flusherr();
4792 #endif
4793         abort();
4794     }
4795 
4796     if(level >= MSG_LEVEL_COUNT)
4797     {
4798         debug_osformatln(termerr, "bad message level %u", level);
4799         logger_handle_trigger_emergency_shutdown();
4800         return;
4801     }
4802 
4803     if(level <= MSG_ERR)
4804     {
4805         sleep(0);
4806     }
4807 
4808 #endif
4809 
4810     if(handle == NULL)
4811     {
4812         if(level <= exit_level)
4813         {
4814             logger_handle_trigger_emergency_shutdown();
4815         }
4816         return;
4817     }
4818 
4819     if(level > logger_level)
4820     {
4821         return;
4822     }
4823 
4824     s32 channel_count = handle->channels[level].offset;
4825 
4826     if(channel_count < 0) /* it's count-1 actually */
4827     {
4828         return;
4829     }
4830 
4831 #if HAS_SHARED_QUEUE_SUPPORT
4832     logger_message* message = logger_message_try_alloc();
4833 #else
4834     logger_message* message = logger_message_alloc();
4835 #endif
4836 
4837 #if HAS_SHARED_QUEUE_SUPPORT
4838     message->pid = getpid_ex();
4839 #endif
4840     message->type = LOGGER_MESSAGE_TYPE_TEXT;
4841     message->text.level = level;
4842     message->text.flags = 0;
4843 
4844     message->text.text_length = text_len;
4845     message->text.text_buffer_length = text_len;
4846     message->text.handle = handle;
4847 
4848 #if HAS_SHARED_QUEUE_SUPPORT
4849     message->text.text = (u8*)shared_heap_wait_alloc(logger_shared_heap_id, text_len);
4850 #else
4851     ZALLOC_ARRAY_OR_DIE(u8*, message->text.text, text_len, LOGRTEXT_TAG);
4852 #endif
4853 
4854     assert(message->text.text != NULL);
4855 
4856     memcpy(message->text.text, text, text_len);
4857 
4858 #if SIZEOF_TIMEVAL <= 8
4859     gettimeofday(&message->text.tv, NULL);
4860 #else
4861     message->text.timestamp = timeus();
4862 #endif
4863 
4864     // prefix
4865     // prefix_len
4866 
4867 #if !HAS_SHARED_QUEUE_SUPPORT
4868     message->text.rc = 0;
4869 
4870 #if DEBUG || HAS_LOG_PID
4871     message->text.pid = getpid_ex();
4872 #endif
4873 #endif
4874 
4875 #if DEBUG || HAS_SHARED_QUEUE_SUPPORT || HAS_LOG_THREAD_ID || DNSCORE_HAS_LOG_THREAD_TAG
4876     message->text.thread_id = thread_self();
4877 #endif
4878 
4879 #if HAS_SHARED_QUEUE_SUPPORT
4880     logger_message_post(message);
4881 #else
4882     if(!threaded_queue_try_enqueue(&logger_commit_queue, message))
4883     {
4884         // could not enqueue
4885         ZFREE_ARRAY(message->text.text, message->text.text_buffer_length);
4886         logger_message_free(message);
4887     }
4888 #endif
4889 
4890     if(level <= exit_level)
4891     {
4892         logger_handle_trigger_emergency_shutdown();
4893     }
4894 }
4895 
4896 bool
logger_queue_fill_critical()4897 logger_queue_fill_critical()
4898 {
4899 #if HAS_SHARED_QUEUE_SUPPORT
4900     int size = shared_circular_buffer_size(logger_shared_queue);
4901     int room = shared_circular_buffer_avail(logger_shared_queue);
4902 #else
4903     int size = threaded_ringbuffer_cw_size(&logger_commit_queue);
4904     int room = threaded_ringbuffer_cw_room(&logger_commit_queue);
4905 #endif
4906     int maxsize = size + room;
4907     if(maxsize > 0)
4908     {
4909         float ratio = ((float)size) / ((float)maxsize);
4910 
4911         return (ratio > 0.5f);
4912     }
4913     else
4914     {
4915         return TRUE;
4916     }
4917 }
4918 
4919 static const char LOGGER_PATH_DEFAULT[] = "";
4920 static const char *g_logger_path = LOGGER_PATH_DEFAULT;
4921 static uid_t g_logger_uid = 0;
4922 static gid_t g_logger_gid = 0;
4923 
4924 void
logger_set_path(const char * path)4925 logger_set_path(const char *path)
4926 {
4927     if(g_logger_path != LOGGER_PATH_DEFAULT)
4928     {
4929         free((char*)g_logger_path);
4930     }
4931     if(path != NULL)
4932     {
4933         g_logger_path = strdup(path);
4934     }
4935     else
4936     {
4937         g_logger_path = LOGGER_PATH_DEFAULT;
4938     }
4939 }
4940 
4941 void
logger_release_ownership()4942 logger_release_ownership()
4943 {
4944     if(logger_thread_pid != -1)
4945     {
4946         logger_thread_pid = -1;
4947     }
4948 
4949     if(logger_handle_owner_pid != -1)
4950     {
4951         logger_handle_owner_pid = -1;
4952     }
4953 }
4954 
4955 void
logger_take_ownership(pid_t new_owner)4956 logger_take_ownership(pid_t new_owner)
4957 {
4958     if(logger_thread_pid == -1)
4959     {
4960         logger_thread_pid = new_owner;
4961     }
4962 
4963     if(logger_handle_owner_pid == -1)
4964     {
4965         logger_handle_owner_pid = new_owner;
4966     }
4967 }
4968 
4969 const char*
logger_get_path()4970 logger_get_path()
4971 {
4972     return g_logger_path;
4973 }
4974 
4975 void
logger_set_uid(uid_t uid)4976 logger_set_uid(uid_t uid)
4977 {
4978     g_logger_uid = uid;
4979 }
4980 
4981 uid_t
logger_get_uid()4982 logger_get_uid()
4983 {
4984     return g_logger_uid;
4985 }
4986 
4987 void
logger_set_gid(uid_t gid)4988 logger_set_gid(uid_t gid)
4989 {
4990     g_logger_gid = gid;
4991 }
4992 
4993 gid_t
logger_get_gid()4994 logger_get_gid()
4995 {
4996     return g_logger_gid;
4997 }
4998 
4999 void
logger_set_level(u8 level)5000 logger_set_level(u8 level)
5001 {
5002     logger_level = MIN(level, MSG_ALL);
5003 }
5004 
5005 bool
logger_wait_started()5006 logger_wait_started()
5007 {
5008     for(int countdown = 50; countdown > 0; --countdown)
5009     {
5010         int value = smp_int_get(&logger_thread_state);
5011         if(value == LOGGER_DISPATCHED_THREAD_STARTED)
5012         {
5013             return TRUE;
5014         }
5015         usleep_ex(100000);
5016     }
5017 
5018     return FALSE;
5019 }
5020 
5021 /** @} */
5022