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 */
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,
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)
{
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++;
}
else
{
index = log_streams_free;
- l = log_streams.ptr[index];
+ l = log_streams.ptr[index];
log_streams_free = l->idata;
}
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)
ls->idata = log_streams_free;
log_streams_free = LS_GET_STRNUM(ls->regnum);
ls->regnum = -1;
+ return 1;
}
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
/* 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 */