]> mj.ucw.cz Git - moe.git/blob - ucw/log-stream.c
mo-create-public: rmdir+mkdir
[moe.git] / ucw / log-stream.c
1 /*
2  *      UCW Library -- Logging: Management of Log Streams
3  *
4  *      (c) 2008 Tomas Gavenciak <gavento@ucw.cz>
5  *      (c) 2009 Martin Mares <mj@ucw.cz>
6  *
7  *      This software may be freely distributed and used according to the terms
8  *      of the GNU Lesser General Public License.
9  */
10
11 #include "ucw/lib.h"
12 #include "ucw/log.h"
13 #include "ucw/log-internal.h"
14 #include "ucw/simple-lists.h"
15
16 #include <string.h>
17
18 /* Initial number of streams to allocate (must be >=2) */
19 #define LS_INIT_STREAMS 8
20
21 /* Flag indicating initialization of the module */
22 static int log_initialized = 0;
23
24 /* The head of the list of freed log_streams indexes in log_streams.ptr (~0U if none free).
25  * Freed positions in log_streams.ptr are connected into a linked list in the following way:
26  * log_streams.ptr[log_streams_free].levels is the index of next freed position (or ~0U) */
27 static uns log_streams_free = ~0U;
28
29 /* Initialize the logstream module.
30  * It is not neccessary to call this explicitely as it is called by
31  * the first log_new_stream()  (for backward compatibility and ease of use). */
32 static void
33 log_init_module(void)
34 {
35   if (log_initialized)
36     return;
37
38   /* Create the growing array */
39   lsbuf_init(&log_streams);
40   lsbuf_set_size(&log_streams, LS_INIT_STREAMS);
41
42   bzero(log_streams.ptr, sizeof(struct log_stream*) * (log_streams.len));
43   log_streams_free = ~0U;
44
45   log_initialized = 1;
46
47   /* init the default stream (0) as forwarder to fd2 */
48   struct log_stream *ls = log_new_stream(sizeof(*ls));
49   ASSERT(ls == log_streams.ptr[0]);
50   ASSERT(ls->regnum == 0);
51   ls->name = "default";
52   log_add_substream(ls, &log_stream_default);
53 }
54
55 void
56 log_close_all(void)
57 {
58   if (!log_initialized)
59     return;
60
61   // Remove substreams of all streams
62   for (int i=0; i < log_streams_after; i++)
63     if (log_streams.ptr[i]->regnum >= 0)
64       log_rm_substream(log_streams.ptr[i], NULL);
65
66   // Close all streams that remain and free all cached structures
67   for (int i=0; i < log_streams_after; i++)
68     {
69       struct log_stream *ls = log_streams.ptr[i];
70       if (ls->regnum >= 0)
71         log_close_stream(ls);
72       ASSERT(ls->regnum < 0 || !ls->use_count);
73       xfree(ls);
74     }
75
76   /* Back to the default state */
77   lsbuf_done(&log_streams);
78   log_streams_after = 0;
79   log_streams_free = ~0U;
80   log_initialized = 0;
81 }
82
83 void
84 log_add_substream(struct log_stream *where, struct log_stream *what)
85 {
86   ASSERT(where);
87   ASSERT(what);
88
89   simp_node *n = xmalloc(sizeof(simp_node));
90   n->p = log_ref_stream(what);
91   clist_add_tail(&where->substreams, &n->n);
92 }
93
94 int
95 log_rm_substream(struct log_stream *where, struct log_stream *what)
96 {
97   void *tmp;
98   int cnt = 0;
99   ASSERT(where);
100
101   CLIST_FOR_EACH_DELSAFE(simp_node *, i, where->substreams, tmp)
102     if (i->p == what || !what)
103       {
104         clist_remove(&i->n);
105         log_close_stream(i->p);
106         xfree(i);
107         cnt++;
108       }
109   return cnt;
110 }
111
112 struct log_stream *
113 log_new_stream(size_t size)
114 {
115   struct log_stream *l;
116   int index;
117
118   /* Initialize the data structures if needed */
119   log_init_module();
120
121   /* Get a free stream, possibly recycling a closed one */
122   if (log_streams_free == ~0U)
123     {
124       lsbuf_grow(&log_streams, log_streams_after+1);
125       index = log_streams_after++;
126       l = log_streams.ptr[index] = xmalloc(size);
127     }
128   else
129     {
130       index = log_streams_free;
131       l = xrealloc(log_streams.ptr[index], size);
132       log_streams.ptr[index] = l;
133       log_streams_free = l->levels;
134     }
135
136   /* Initialize the stream */
137   bzero(l, sizeof(*l));
138   l->levels = ~0U;
139   l->types = ~0U;
140   l->regnum = LS_SET_STRNUM(index);
141   clist_init(&l->substreams);
142   return log_ref_stream(l);
143 }
144
145 int
146 log_close_stream(struct log_stream *ls)
147 {
148   ASSERT(ls);
149   ASSERT(ls->use_count);
150   if (--ls->use_count)
151     return 0;
152
153   /* Unlink all subtreams */
154   log_rm_substream(ls, NULL);
155
156   /* Close the stream and add it to the free-list */
157   if (ls->close)
158     ls->close(ls);
159   ls->levels = log_streams_free;
160   log_streams_free = LS_GET_STRNUM(ls->regnum);
161   ls->regnum = -1;
162   return 1;
163 }
164
165 void
166 log_set_format(struct log_stream *ls, uns mask, uns data)
167 {
168   ls->msgfmt = (ls->msgfmt & mask) | data;
169   CLIST_FOR_EACH(simp_node *, i, ls->substreams)
170     log_set_format(i->p, mask, data);
171 }
172
173 /*** Registry of type names ***/
174
175 int log_register_type(const char *name)
176 {
177   if (!log_type_names)
178     {
179       log_type_names = xmalloc_zero(LS_NUM_TYPES * sizeof(char *));
180       log_type_names[0] = "default";
181     }
182   uns id;
183   for (id=0; id < LS_NUM_TYPES && log_type_names[id]; id++)
184     if (!strcmp(log_type_names[id], name))
185       return LS_SET_TYPE(id);
186   ASSERT(id < LS_NUM_TYPES);
187   log_type_names[id] = xstrdup(name);
188   return LS_SET_TYPE(id);
189 }
190
191 /** Find a message type by name and return its ID encoded by `LS_SET_TYPE`. Returns -1 if no such type found. **/
192 int log_find_type(const char *name)
193 {
194   if (!strcmp(name, "default"))
195     return 0;
196   if (!log_type_names)
197     return -1;
198
199   for (uns id=0; id < LS_NUM_TYPES && log_type_names[id]; id++)
200     if (!strcmp(log_type_names[id], name))
201       return LS_SET_TYPE(id);
202   return -1;
203 }