]> mj.ucw.cz Git - libucw.git/commitdiff
Logging: Introduce use counts on streams.
authorMartin Mares <mj@ucw.cz>
Fri, 13 Feb 2009 23:36:27 +0000 (00:36 +0100)
committerMartin Mares <mj@ucw.cz>
Fri, 13 Feb 2009 23:36:27 +0000 (00:36 +0100)
It turned out to be quite inconvenient to have to close the substreams in
topological order. I have introduced use counts on all streams: A newly
created stream has use count of 1, whenever it is used as a substream,
the use count increases; when the count drops to 0, the stream is
automatically destroyed.

A slightly unpleasant side-effect is that the default log stream
can no longer be constant, since we modify its counter.

I have also extended log_rm_substream() to remove all substreams
when what==NULL. This is useful in log_close_stream() and also
in log_file().

ucw/log-file.c
ucw/log-stream.c
ucw/log.c
ucw/log.h

index c74db01bea74535a0dbf8b8202701e19903c98f1..52a010876d76540d6aec4dbb0d5ae39a4a7809dd 100644 (file)
@@ -105,16 +105,9 @@ log_file(const char *name)
 
   struct log_stream *ls = log_new_file(name);
   struct log_stream *def = log_stream_by_flags(0);
-  simp_node *s;
-  while (s = clist_head(&def->substreams))
-    {
-      struct log_stream *old = s->p;
-      log_rm_substream(def, old);
-      if (old != LOG_STREAM_DEFAULT)
-       log_close_stream(old);
-    }
-  dup2(ls->idata, 2);                  // Let fd2 be an alias for the log file
+  log_rm_substream(def, NULL);
   log_add_substream(def, ls);
+  dup2(ls->idata, 2);                  // Let fd2 be an alias for the log file
 }
 
 /* destructor for standard files */
index 341dd500065a99bf6df4cdb185ec93c7db4422c9..3a8c1e1094361964eec3a64d08097882610003f0 100644 (file)
@@ -48,7 +48,7 @@ log_init_module(void)
   ASSERT(ls == log_streams.ptr[0]);
   ASSERT(ls->regnum == 0);
   ls->name = "default";
-  log_add_substream(ls, (struct log_stream *) &log_stream_default);
+  log_add_substream(ls, &log_stream_default);
 }
 
 /* Close all open streams, un-initialize the module, free all memory,
@@ -73,7 +73,8 @@ log_close_all(void)
   log_initialized = 0;
 }
 
-/* Add a new substream, xmalloc()-ate a new simp_node. */
+/* Add a new substream. The parent stream takes a reference on the substream,
+ * preventing it from being closed as long as it is linked. */
 void
 log_add_substream(struct log_stream *where, struct log_stream *what)
 {
@@ -81,24 +82,25 @@ log_add_substream(struct log_stream *where, struct log_stream *what)
   ASSERT(what);
 
   simp_node *n = xmalloc(sizeof(simp_node));
-  n->p = what;
+  n->p = log_ref_stream(what);
   clist_add_tail(&where->substreams, &n->n);
 }
 
-/* Remove all occurences of a substream, xfree() the simp_node. */
-/* Return the number of deleted entries. */
+/* Remove all occurences of a substream together with the references they
+ * keep. If a substream becomes unreferenced, it is closed. If what is NULL,
+ * all substreams are removed. Returns the number of deleted entries. */
 int
 log_rm_substream(struct log_stream *where, struct log_stream *what)
 {
   void *tmp;
   int cnt = 0;
   ASSERT(where);
-  ASSERT(what);
 
   CLIST_FOR_EACH_DELSAFE(simp_node *, i, where->substreams, tmp)
-    if (i->p == what)
+    if (i->p == what || !what)
       {
        clist_remove(&i->n);
+       log_close_stream(i->p);
        xfree(i);
        cnt++;
       }
@@ -125,7 +127,7 @@ log_new_stream(void)
   else
     {
       index = log_streams_free;
-  l = log_streams.ptr[index];
+      l = log_streams.ptr[index];
       log_streams_free = l->idata;
     }
 
@@ -134,22 +136,22 @@ log_new_stream(void)
   l->levels = LS_ALL_LEVELS;
   l->regnum = LS_SET_STRNUM(index);
   clist_init(&l->substreams);
-  return l;
+  return log_ref_stream(l);
 }
 
-/* Close a stream, unlink (but do not close) all its substreams */
-void
+/* Remove a reference on a stream and close it if it was the last reference.
+ * Closing automatically unlinks all substreams and closes them if they are
+ * no longer referenced. Returns 1 if the stream has been really closed. */
+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(&i->n);
-      xfree(i);
-    }
+  /* Unlink all subtreams */
+  log_rm_substream(ls, NULL);
 
   /* Close the stream and add it to the free-list */
   if (ls->close)
@@ -157,4 +159,5 @@ log_close_stream(struct log_stream *ls)
   ls->idata = log_streams_free;
   log_streams_free = LS_GET_STRNUM(ls->regnum);
   ls->regnum = -1;
+  return 1;
 }
index 1f7eea9deb59ed416bb37c675af41b934be593ba..afda7a0ca05c3521e9733d51a2e97d9e2eb119d9 100644 (file)
--- a/ucw/log.c
+++ b/ucw/log.c
@@ -34,9 +34,10 @@ static int default_log_handler(struct log_stream *ls, struct log_msg *m)
   return 0;
 }
 
-const struct log_stream log_stream_default = {
+struct log_stream log_stream_default = {
   .name = "stderr",
   .idata = 2,
+  .use_count = 1000000,
   .handler = default_log_handler,
   .levels = LS_ALL_LEVELS,
   .msgfmt = LSFMT_DEFAULT,
index 1a3bdf50d46bc0416ce86ab79178cca7f313b78c..d6c240a43642b41697e7c4a8023f634e988455a6 100644 (file)
--- a/ucw/log.h
+++ b/ucw/log.h
@@ -33,18 +33,19 @@ struct log_stream
   int regnum;                          // Stream number, already encoded by LS_SET_STRNUM(); -1 if closed
   uns levels;                          // Bitmask of accepted severity levels
   uns msgfmt;                          // Formatting flags (LSFMT_xxx)
+  uns use_count;                       // Number of references to the stream
   int (*filter)(struct log_stream* ls, struct log_msg *m);     // Filter function, return non-zero to discard the message
   struct clist substreams;             // Pass the message to these streams (simple_list of pointers)
   int (*handler)(struct log_stream *ls, struct log_msg *m);    // Called to commit the message
-  void (*close)(struct log_stream* ls);        // Called on log_close_stream()
+  void (*close)(struct log_stream* ls);        // Called upon log_close_stream()
   int idata;                           // Private data of the handler
   void *pdata;
   uns udata;
 };
 
 /* the default logger */
-extern const struct log_stream log_stream_default;
-#define LOG_STREAM_DEFAULT ((struct log_stream *) &log_stream_default)
+extern struct log_stream log_stream_default;
+#define LOG_STREAM_DEFAULT &log_stream_default
 
 /* A message is processed as follows:
  *  1. Discard if message level not in levels
@@ -128,7 +129,15 @@ struct log_stream *log_new_stream(void);
 
 /* Close and xfree() given log_stream */
 /* Does not affect substreams */
-void log_close_stream(struct log_stream *ls);
+int log_close_stream(struct log_stream *ls);
+
+/* Get a new reference on a stream */
+static inline struct log_stream *
+log_ref_stream(struct log_stream *ls)
+{
+  ls->use_count++;
+  return ls;
+}
 
 /* close all open streams, un-initialize the module, free all memory,
  * use only ls_default_log */