]> mj.ucw.cz Git - libucw.git/blobdiff - ucw/log-stream.c
Just fixed a comment in libimages.
[libucw.git] / ucw / log-stream.c
index 748164c86d804e7ed785a3cbc834d0e89cc30526..5af9f3e6581ad264797e64c566ba0573db40f5d8 100644 (file)
  */
 
 #include "ucw/lib.h"
-#include "ucw/clists.h"
-#include "ucw/simple-lists.h"
 #include "ucw/log.h"
+#include "ucw/log-internal.h"
+#include "ucw/simple-lists.h"
 
 #include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <time.h>
-#include <alloca.h>
-#include <fcntl.h>
+
+/* Initial number of streams to allocate (must be >=2) */
+#define LS_INIT_STREAMS 8
 
 /* Flag indicating initialization of the module */
-static int ls_initialized = 0;
+static int log_initialized = 0;
 
-/* The head of the list of freed log_streams indexes in ls_streams.ptr (-1 if none free).
- * Freed positions in ls_streams.ptr are connected into a linked list in the following way:
- * ls_streams.ptr[ls_streams_free].idata is the index of next freed position (or -1) */
-static int ls_streams_free = -1;
+/* The head of the list of freed log_streams indexes in log_streams.ptr (~0U if none free).
+ * Freed positions in log_streams.ptr are connected into a linked list in the following way:
+ * log_streams.ptr[log_streams_free].levels is the index of next freed position (or ~0U) */
+static uns log_streams_free = ~0U;
 
 /* Initialize the logstream module.
  * It is not neccessary to call this explicitely as it is called by
- * the first ls_new()  (for backward compatibility and ease of use). */
-static void ls_init_module(void)
+ * the first log_new_stream()  (for backward compatibility and ease of use). */
+static void
+log_init_module(void)
 {
-  if (ls_initialized) return;
+  if (log_initialized)
+    return;
 
-  /* create the grow array */
+  /* Create the growing array */
   lsbuf_init(&log_streams);
   lsbuf_set_size(&log_streams, LS_INIT_STREAMS);
 
   bzero(log_streams.ptr, sizeof(struct log_stream*) * (log_streams.len));
-  ls_streams_free = -1;
+  log_streams_free = ~0U;
 
-  ls_initialized = 1;
+  log_initialized = 1;
 
   /* init the default stream (0) as forwarder to fd2 */
-  struct log_stream *ls = ls_new();
+  struct log_stream *ls = log_new_stream(sizeof(*ls));
   ASSERT(ls == log_streams.ptr[0]);
   ASSERT(ls->regnum == 0);
   ls->name = "default";
-  ls_add_substream(ls, (struct log_stream *) &ls_default_log);
-
-  /* log this */
-  ls_msg(L_DEBUG, "logstream module initialized.");
+  log_add_substream(ls, &log_stream_default);
 }
 
-/* close all open streams, un-initialize the module, free all memory,
- * use only ls_default_log */
-void ls_close_all(void)
+void
+log_close_all(void)
 {
-  int i;
+  if (!log_initialized)
+    return;
 
-  if (!ls_initialized) return;
+  // Remove substreams of all streams
+  for (int i=0; i < log_streams_after; i++)
+    if (log_streams.ptr[i]->regnum >= 0)
+      log_rm_substream(log_streams.ptr[i], NULL);
 
-  for (i=0; i<log_streams_after; i++)
-  {
-    if (log_streams.ptr[i]->regnum>=0)
-      ls_close(log_streams.ptr[i]);
-    xfree(log_streams.ptr[i]);
-  }
+  // Close all streams that remain and free all cached structures
+  for (int i=0; i < log_streams_after; i++)
+    {
+      struct log_stream *ls = log_streams.ptr[i];
+      if (ls->regnum >= 0)
+       log_close_stream(ls);
+      ASSERT(ls->regnum < 0 || !ls->use_count);
+      xfree(ls);
+    }
 
-  /* set to the default state */
+  /* Back to the default state */
   lsbuf_done(&log_streams);
-  log_streams_after=0;
-  ls_streams_free=-1;
-  ls_initialized = 0;
+  log_streams_after = 0;
+  log_streams_free = ~0U;
+  log_initialized = 0;
 }
 
-/* add a new substream, malloc()-ate a new simp_node */
-void ls_add_substream(struct log_stream *where, struct log_stream *what)
+void
+log_add_substream(struct log_stream *where, struct log_stream *what)
 {
   ASSERT(where);
   ASSERT(what);
 
   simp_node *n = xmalloc(sizeof(simp_node));
-  n->p = what;
-  clist_add_tail(&(where->substreams), (cnode*)n);
+  n->p = log_ref_stream(what);
+  clist_add_tail(&where->substreams, &n->n);
 }
 
-/* remove all occurences of a substream, free() the simp_node */
-/* return number of deleted entries */
-int ls_rm_substream(struct log_stream *where, struct log_stream *what)
+int
+log_rm_substream(struct log_stream *where, struct log_stream *what)
 {
   void *tmp;
-  int cnt=0;
+  int cnt = 0;
   ASSERT(where);
-  ASSERT(what);
 
   CLIST_FOR_EACH_DELSAFE(simp_node *, i, where->substreams, tmp)
-    if (i->p == what)
-    {
-      clist_remove((cnode*)i);
-      xfree(i);
-      cnt++;
-    }
+    if (i->p == what || !what)
+      {
+       clist_remove(&i->n);
+       log_close_stream(i->p);
+       xfree(i);
+       cnt++;
+      }
   return cnt;
 }
 
-/* Return a pointer to a new stream with no handler and an empty substream list. */
-struct log_stream *ls_new(void)
+struct log_stream *
+log_new_stream(size_t size)
 {
   struct log_stream *l;
   int index;
 
-  /* initialize the array if not initialized already */
-  if (unlikely(ls_initialized==0))
-    ls_init_module();
-
-  /* there is no closed stream -- allocate a new one */
-  if (ls_streams_free==-1)
-  {
-    /* check the size of the pointer array */
-    lsbuf_grow(&log_streams, log_streams_after+1);
-    ls_streams_free = log_streams_after++;
-    log_streams.ptr[ls_streams_free] = xmalloc(sizeof(struct log_stream));
-    log_streams.ptr[ls_streams_free]->idata = -1;
-    log_streams.ptr[ls_streams_free]->regnum = -1;
-  }
-
-  ASSERT(ls_streams_free>=0);
-
-  /* initialize the stream */
-  index = ls_streams_free;
-  l = log_streams.ptr[index];
-  ls_streams_free = l->idata;
-  memset(l, 0, sizeof(struct log_stream));
-  l->levels = LS_ALL_LEVELS;
+  /* Initialize the data structures if needed */
+  log_init_module();
+
+  /* Get a free stream, possibly recycling a closed one */
+  if (log_streams_free == ~0U)
+    {
+      lsbuf_grow(&log_streams, log_streams_after+1);
+      index = log_streams_after++;
+      l = log_streams.ptr[index] = xmalloc(size);
+    }
+  else
+    {
+      index = log_streams_free;
+      l = xrealloc(log_streams.ptr[index], size);
+      log_streams.ptr[index] = l;
+      log_streams_free = l->levels;
+    }
+
+  /* Initialize the stream */
+  bzero(l, sizeof(*l));
+  l->levels = ~0U;
+  l->types = ~0U;
   l->regnum = LS_SET_STRNUM(index);
-  l->substreams.head.next = &(l->substreams.head);
-  l->substreams.head.prev = &(l->substreams.head);
-  return l;
+  clist_init(&l->substreams);
+  return log_ref_stream(l);
 }
 
-/* Close and remember given log_stream */
-/* does not affect substreams, but frees the .substreams list */
-void ls_close(struct log_stream *ls)
+int
+log_close_stream(struct log_stream *ls)
 {
-  void *tmp;
   ASSERT(ls);
+  ASSERT(ls->use_count);
+  if (--ls->use_count)
+    return 0;
 
-  /* xfree() all the simp_nodes from substreams */
-  CLIST_FOR_EACH_DELSAFE(simp_node *, i, ls->substreams, tmp)
-  {
-    clist_remove((cnode*)i);
-    xfree(i);
-  }
+  /* Unlink all subtreams */
+  log_rm_substream(ls, NULL);
 
-  /* close and remember the stream */
-  if (ls->close!=NULL)
+  /* Close the stream and add it to the free-list */
+  if (ls->close)
     ls->close(ls);
-  ls->idata = ls_streams_free;
-  ls_streams_free = LS_GET_STRNUM(ls->regnum);
+  ls->levels = log_streams_free;
+  log_streams_free = LS_GET_STRNUM(ls->regnum);
   ls->regnum = -1;
+  return 1;
+}
+
+void
+log_set_format(struct log_stream *ls, uns mask, uns data)
+{
+  ls->msgfmt = (ls->msgfmt & mask) | data;
+  CLIST_FOR_EACH(simp_node *, i, ls->substreams)
+    log_set_format(i->p, mask, data);
+}
+
+/*** Registry of type names ***/
+
+int log_register_type(const char *name)
+{
+  if (!log_type_names)
+    {
+      log_type_names = xmalloc_zero(LS_NUM_TYPES * sizeof(char *));
+      log_type_names[0] = "default";
+    }
+  uns id;
+  for (id=0; id < LS_NUM_TYPES && log_type_names[id]; id++)
+    if (!strcmp(log_type_names[id], name))
+      return LS_SET_TYPE(id);
+  ASSERT(id < LS_NUM_TYPES);
+  log_type_names[id] = xstrdup(name);
+  return LS_SET_TYPE(id);
+}
+
+/** Find a message type by name and return its ID encoded by `LS_SET_TYPE`. Returns -1 if no such type found. **/
+int log_find_type(const char *name)
+{
+  if (!strcmp(name, "default"))
+    return 0;
+  if (!log_type_names)
+    return -1;
+
+  for (uns id=0; id < LS_NUM_TYPES && log_type_names[id]; id++)
+    if (!strcmp(log_type_names[id], name))
+      return LS_SET_TYPE(id);
+  return -1;
 }