From de742f43adad78a5bdda6ace083106f7264a2e16 Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sat, 14 Feb 2009 00:36:27 +0100 Subject: [PATCH] Logging: Introduce use counts on streams. 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 | 11 ++--------- ucw/log-stream.c | 39 +++++++++++++++++++++------------------ ucw/log.c | 3 ++- ucw/log.h | 17 +++++++++++++---- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/ucw/log-file.c b/ucw/log-file.c index c74db01b..52a01087 100644 --- a/ucw/log-file.c +++ b/ucw/log-file.c @@ -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 */ diff --git a/ucw/log-stream.c b/ucw/log-stream.c index 341dd500..3a8c1e10 100644 --- a/ucw/log-stream.c +++ b/ucw/log-stream.c @@ -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; } diff --git a/ucw/log.c b/ucw/log.c index 1f7eea9d..afda7a0c 100644 --- 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, diff --git a/ucw/log.h b/ucw/log.h index 1a3bdf50..d6c240a4 100644 --- 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 */ -- 2.39.2