source: mainline/uspace/srv/logger/logs.c@ 131d9a4

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 131d9a4 was 131d9a4, checked in by Vojtech Horky <vojtechhorky@…>, 13 years ago

Logger: destroy logs on client disconnect

  • Property mode set to 100644
File size: 8.3 KB
RevLine 
[cba45af]1/*
2 * Copyright (c) 2012 Vojtech Horky
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup logger
30 * @{
31 */
32#include <assert.h>
33#include <malloc.h>
34#include <str.h>
35#include <stdio.h>
36#include <errno.h>
37#include "logger.h"
38
39
[f039dba]40static FIBRIL_MUTEX_INITIALIZE(log_list_guard);
41static LIST_INITIALIZE(log_list);
42
43
[ae2c925]44static logger_log_t *find_log_by_name_and_parent_no_list_lock(const char *name, logger_log_t *parent)
[cba45af]45{
[f039dba]46 list_foreach(log_list, it) {
47 logger_log_t *log = list_get_instance(it, logger_log_t, link);
[ae2c925]48 if ((parent == log->parent) && (str_cmp(log->name, name) == 0))
[cba45af]49 return log;
50 }
51
52 return NULL;
53}
54
[f5da671]55static int create_dest(const char *name, logger_dest_t **dest)
[cba45af]56{
[f039dba]57 logger_dest_t *result = malloc(sizeof(logger_dest_t));
[f5da671]58 if (result == NULL)
59 return ENOMEM;
[90dc458]60 int rc = asprintf(&result->filename, "/log/%s", name);
[f5da671]61 if (rc < 0) {
62 free(result);
63 return ENOMEM;
64 }
[90dc458]65 result->logfile = NULL;
66 fibril_mutex_initialize(&result->guard);
[f5da671]67 *dest = result;
68 return EOK;
[f039dba]69}
[cba45af]70
[ae2c925]71static logger_log_t *create_log_no_locking(const char *name, logger_log_t *parent)
[f039dba]72{
[ae2c925]73 logger_log_t *result = calloc(1, sizeof(logger_log_t));
74 if (result == NULL)
75 return NULL;
[cba45af]76
77 result->name = str_dup(name);
[ae2c925]78 if (result->name == NULL)
79 goto error;
80
81 /*
82 * Notice that we create new dest as the last
83 * operation that can fail and thus there is no code
84 * to deallocate dest.
85 */
[f039dba]86 if (parent == NULL) {
87 result->full_name = str_dup(name);
[ae2c925]88 if (result->full_name == NULL)
89 goto error;
90 int rc = create_dest(name, &result->dest);
[f5da671]91 if (rc != EOK)
[ae2c925]92 goto error;
[f039dba]93 } else {
[ae2c925]94 int rc = asprintf(&result->full_name, "%s/%s",
[f5da671]95 parent->full_name, name);
96 if (rc < 0)
[ae2c925]97 goto error;
[f039dba]98 result->dest = parent->dest;
99 }
[cba45af]100
[ae2c925]101 /* Following initializations cannot fail. */
102 result->logged_level = LOG_LEVEL_USE_DEFAULT;
103 fibril_mutex_initialize(&result->guard);
[cba45af]104 link_initialize(&result->link);
[ae2c925]105 result->parent = parent;
[cba45af]106
[ae2c925]107 return result;
[cba45af]108
[ae2c925]109error:
110 free(result->name);
111 free(result->full_name);
112 free(result);
113 return NULL;
[f5da671]114
[ae2c925]115}
[f5da671]116
[1dec7cb]117logger_log_t *find_or_create_log_and_lock(const char *name, sysarg_t parent_id)
[ae2c925]118{
119 logger_log_t *result = NULL;
120 logger_log_t *parent = (logger_log_t *) parent_id;
[cba45af]121
[ae2c925]122 fibril_mutex_lock(&log_list_guard);
123
124 result = find_log_by_name_and_parent_no_list_lock(name, parent);
125 if (result == NULL) {
126 result = create_log_no_locking(name, parent);
127 if (result == NULL)
128 goto leave;
[92e963f]129 list_append(&result->link, &log_list);
[131d9a4]130 if (result->parent != NULL) {
131 fibril_mutex_lock(&result->parent->guard);
132 result->parent->ref_counter++;
133 fibril_mutex_unlock(&result->parent->guard);
134 }
[90dc458]135 }
136
[ae2c925]137 fibril_mutex_lock(&result->guard);
[f5da671]138
[ae2c925]139leave:
[f08ab0f]140 fibril_mutex_unlock(&log_list_guard);
141
[ae2c925]142 return result;
[cba45af]143}
144
[1dec7cb]145logger_log_t *find_log_by_name_and_lock(const char *name)
[cba45af]146{
[f039dba]147 logger_log_t *result = NULL;
148
149 fibril_mutex_lock(&log_list_guard);
150 list_foreach(log_list, it) {
151 logger_log_t *log = list_get_instance(it, logger_log_t, link);
152 if (str_cmp(log->full_name, name) == 0) {
[3cf862f]153 fibril_mutex_lock(&log->guard);
[f039dba]154 result = log;
155 break;
156 }
[cba45af]157 }
[f039dba]158 fibril_mutex_unlock(&log_list_guard);
[cba45af]159
[f039dba]160 return result;
[cba45af]161}
162
[1dec7cb]163logger_log_t *find_log_by_id_and_lock(sysarg_t id)
[cba45af]164{
[f039dba]165 logger_log_t *result = NULL;
166
167 fibril_mutex_lock(&log_list_guard);
168 list_foreach(log_list, it) {
169 logger_log_t *log = list_get_instance(it, logger_log_t, link);
170 if ((sysarg_t) log == id) {
[3cf862f]171 fibril_mutex_lock(&log->guard);
[f039dba]172 result = log;
173 break;
174 }
[cba45af]175 }
[f039dba]176 fibril_mutex_unlock(&log_list_guard);
[cba45af]177
[f039dba]178 return result;
[cba45af]179}
180
[f039dba]181static log_level_t get_actual_log_level(logger_log_t *log)
[cba45af]182{
[f039dba]183 /* Find recursively proper log level. */
184 if (log->logged_level == LOG_LEVEL_USE_DEFAULT) {
185 if (log->parent == NULL)
186 return get_default_logging_level();
187 else
188 return get_actual_log_level(log->parent);
189 }
190 return log->logged_level;
[cba45af]191}
192
[f039dba]193bool shall_log_message(logger_log_t *log, log_level_t level)
194{
[3cf862f]195 fibril_mutex_lock(&log_list_guard);
196 bool result = level <= get_actual_log_level(log);
197 fibril_mutex_unlock(&log_list_guard);
198 return result;
199}
200
[1dec7cb]201void log_unlock(logger_log_t *log)
[3cf862f]202{
203 assert(fibril_mutex_is_locked(&log->guard));
204 fibril_mutex_unlock(&log->guard);
[f039dba]205}
[cba45af]206
[131d9a4]207/** Decreases reference counter on the log and destory the log if
208 * necessary.
209 *
210 * Precondition: log is locked.
211 *
212 * @param log Log to release from using by the caller.
213 */
214void log_release(logger_log_t *log)
215{
216 assert(fibril_mutex_is_locked(&log->guard));
217 assert(log->ref_counter > 0);
218
219 /* We are definitely not the last ones. */
220 if (log->ref_counter > 1) {
221 log->ref_counter--;
222 fibril_mutex_unlock(&log->guard);
223 return;
224 }
225
226 /*
227 * To prevent deadlock, we need to get the list lock first.
228 * Deadlock scenario:
229 * Us: LOCKED(log), want to LOCK(list)
230 * Someone else calls find_log_by_name_and_lock(log->fullname) ->
231 * LOCKED(list), wants to LOCK(log)
232 */
233 fibril_mutex_unlock(&log->guard);
234
235 /* Ensuring correct locking order. */
236 fibril_mutex_lock(&log_list_guard);
237 /*
238 * The reference must be still valid because we have not decreased
239 * the reference counter.
240 */
241 fibril_mutex_lock(&log->guard);
242 assert(log->ref_counter > 0);
243 log->ref_counter--;
244
245 if (log->ref_counter > 0) {
246 /*
247 * Meanwhile, someone else increased the ref counter.
248 * No big deal, we just return immediatelly.
249 */
250 fibril_mutex_unlock(&log->guard);
251 fibril_mutex_unlock(&log_list_guard);
252 return;
253 }
254
255 /*
256 * Here we are on a destroy path. We need to
257 * - remove ourselves from the list
258 * - decrease reference of the parent (if not top-level log)
259 * - we must do that after we relaase list lock to prevent
260 * deadlock with ourselves
261 * - destroy dest (if top-level log)
262 */
263 assert(log->ref_counter == 0);
264
265 list_remove(&log->link);
266 fibril_mutex_unlock(&log_list_guard);
267 fibril_mutex_unlock(&log->guard);
268
269 if (log->parent == NULL) {
270 fclose(log->dest->logfile);
271 free(log->dest->filename);
272 free(log->dest);
273 } else {
274 fibril_mutex_lock(&log->parent->guard);
275 log_release(log->parent);
276 }
277
278 printf("Destroying log %s.\n", log->full_name);
279
280 free(log->name);
281 free(log->full_name);
282
283 free(log);
284}
285
286
[90dc458]287void write_to_log(logger_log_t *log, log_level_t level, const char *message)
288{
289 assert(fibril_mutex_is_locked(&log->guard));
290 assert(log->dest != NULL);
291 fibril_mutex_lock(&log->dest->guard);
292 if (log->dest->logfile == NULL)
293 log->dest->logfile = fopen(log->dest->filename, "a");
294
295 if (log->dest->logfile != NULL) {
296 fprintf(log->dest->logfile, "[%s] %s: %s\n",
297 log->full_name, log_level_str(level),
298 (const char *) message);
299 fflush(log->dest->logfile);
300 }
301
302 fibril_mutex_unlock(&log->dest->guard);
303}
304
[131d9a4]305void registered_logs_init(logger_registered_logs_t *logs)
306{
307 logs->logs_count = 0;
308}
309
310bool register_log(logger_registered_logs_t *logs, logger_log_t *new_log)
311{
312 if (logs->logs_count >= MAX_REFERENCED_LOGS_PER_CLIENT) {
313 return false;
314 }
315
316 assert(fibril_mutex_is_locked(&new_log->guard));
317 new_log->ref_counter++;
318
319 logs->logs[logs->logs_count] = new_log;
320 logs->logs_count++;
321
322 return true;
323}
324
325void unregister_logs(logger_registered_logs_t *logs)
326{
327 for (size_t i = 0; i < logs->logs_count; i++) {
328 logger_log_t *log = logs->logs[i];
329 fibril_mutex_lock(&log->guard);
330 log_release(log);
331 }
332}
333
[cba45af]334/**
335 * @}
336 */
Note: See TracBrowser for help on using the repository browser.