source: mainline/uspace/srv/logger/logs.c@ 42d08592

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 42d08592 was feeac0d, checked in by Jiri Svoboda <jiri@…>, 12 years ago

Simplify use of list_foreach.

  • Property mode set to 100644
File size: 8.4 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{
[feeac0d]46 list_foreach(log_list, link, logger_log_t, log) {
[ae2c925]47 if ((parent == log->parent) && (str_cmp(log->name, name) == 0))
[cba45af]48 return log;
49 }
50
51 return NULL;
52}
53
[f5da671]54static int create_dest(const char *name, logger_dest_t **dest)
[cba45af]55{
[f039dba]56 logger_dest_t *result = malloc(sizeof(logger_dest_t));
[f5da671]57 if (result == NULL)
58 return ENOMEM;
[90dc458]59 int rc = asprintf(&result->filename, "/log/%s", name);
[f5da671]60 if (rc < 0) {
61 free(result);
62 return ENOMEM;
63 }
[90dc458]64 result->logfile = NULL;
65 fibril_mutex_initialize(&result->guard);
[f5da671]66 *dest = result;
67 return EOK;
[f039dba]68}
[cba45af]69
[ae2c925]70static logger_log_t *create_log_no_locking(const char *name, logger_log_t *parent)
[f039dba]71{
[ae2c925]72 logger_log_t *result = calloc(1, sizeof(logger_log_t));
73 if (result == NULL)
74 return NULL;
[cba45af]75
76 result->name = str_dup(name);
[ae2c925]77 if (result->name == NULL)
78 goto error;
79
80 /*
81 * Notice that we create new dest as the last
82 * operation that can fail and thus there is no code
83 * to deallocate dest.
84 */
[f039dba]85 if (parent == NULL) {
86 result->full_name = str_dup(name);
[ae2c925]87 if (result->full_name == NULL)
88 goto error;
89 int rc = create_dest(name, &result->dest);
[f5da671]90 if (rc != EOK)
[ae2c925]91 goto error;
[f039dba]92 } else {
[ae2c925]93 int rc = asprintf(&result->full_name, "%s/%s",
[f5da671]94 parent->full_name, name);
95 if (rc < 0)
[ae2c925]96 goto error;
[f039dba]97 result->dest = parent->dest;
98 }
[cba45af]99
[ae2c925]100 /* Following initializations cannot fail. */
101 result->logged_level = LOG_LEVEL_USE_DEFAULT;
102 fibril_mutex_initialize(&result->guard);
[cba45af]103 link_initialize(&result->link);
[ae2c925]104 result->parent = parent;
[cba45af]105
[ae2c925]106 return result;
[cba45af]107
[ae2c925]108error:
109 free(result->name);
110 free(result->full_name);
111 free(result);
112 return NULL;
[f5da671]113
[ae2c925]114}
[f5da671]115
[1dec7cb]116logger_log_t *find_or_create_log_and_lock(const char *name, sysarg_t parent_id)
[ae2c925]117{
118 logger_log_t *result = NULL;
119 logger_log_t *parent = (logger_log_t *) parent_id;
[cba45af]120
[ae2c925]121 fibril_mutex_lock(&log_list_guard);
122
123 result = find_log_by_name_and_parent_no_list_lock(name, parent);
124 if (result == NULL) {
125 result = create_log_no_locking(name, parent);
126 if (result == NULL)
127 goto leave;
[92e963f]128 list_append(&result->link, &log_list);
[131d9a4]129 if (result->parent != NULL) {
130 fibril_mutex_lock(&result->parent->guard);
131 result->parent->ref_counter++;
132 fibril_mutex_unlock(&result->parent->guard);
133 }
[90dc458]134 }
135
[ae2c925]136 fibril_mutex_lock(&result->guard);
[f5da671]137
[ae2c925]138leave:
[f08ab0f]139 fibril_mutex_unlock(&log_list_guard);
140
[ae2c925]141 return result;
[cba45af]142}
143
[1dec7cb]144logger_log_t *find_log_by_name_and_lock(const char *name)
[cba45af]145{
[f039dba]146 logger_log_t *result = NULL;
147
148 fibril_mutex_lock(&log_list_guard);
[feeac0d]149 list_foreach(log_list, link, logger_log_t, log) {
[f039dba]150 if (str_cmp(log->full_name, name) == 0) {
[3cf862f]151 fibril_mutex_lock(&log->guard);
[f039dba]152 result = log;
153 break;
154 }
[cba45af]155 }
[f039dba]156 fibril_mutex_unlock(&log_list_guard);
[cba45af]157
[f039dba]158 return result;
[cba45af]159}
160
[1dec7cb]161logger_log_t *find_log_by_id_and_lock(sysarg_t id)
[cba45af]162{
[f039dba]163 logger_log_t *result = NULL;
164
165 fibril_mutex_lock(&log_list_guard);
[feeac0d]166 list_foreach(log_list, link, logger_log_t, log) {
[f039dba]167 if ((sysarg_t) log == id) {
[3cf862f]168 fibril_mutex_lock(&log->guard);
[f039dba]169 result = log;
170 break;
171 }
[cba45af]172 }
[f039dba]173 fibril_mutex_unlock(&log_list_guard);
[cba45af]174
[f039dba]175 return result;
[cba45af]176}
177
[f039dba]178static log_level_t get_actual_log_level(logger_log_t *log)
[cba45af]179{
[f039dba]180 /* Find recursively proper log level. */
181 if (log->logged_level == LOG_LEVEL_USE_DEFAULT) {
182 if (log->parent == NULL)
183 return get_default_logging_level();
184 else
185 return get_actual_log_level(log->parent);
186 }
187 return log->logged_level;
[cba45af]188}
189
[f039dba]190bool shall_log_message(logger_log_t *log, log_level_t level)
191{
[3cf862f]192 fibril_mutex_lock(&log_list_guard);
193 bool result = level <= get_actual_log_level(log);
194 fibril_mutex_unlock(&log_list_guard);
195 return result;
196}
197
[1dec7cb]198void log_unlock(logger_log_t *log)
[3cf862f]199{
200 assert(fibril_mutex_is_locked(&log->guard));
201 fibril_mutex_unlock(&log->guard);
[f039dba]202}
[cba45af]203
[131d9a4]204/** Decreases reference counter on the log and destory the log if
205 * necessary.
206 *
207 * Precondition: log is locked.
208 *
209 * @param log Log to release from using by the caller.
210 */
211void log_release(logger_log_t *log)
212{
213 assert(fibril_mutex_is_locked(&log->guard));
214 assert(log->ref_counter > 0);
215
216 /* We are definitely not the last ones. */
217 if (log->ref_counter > 1) {
218 log->ref_counter--;
219 fibril_mutex_unlock(&log->guard);
220 return;
221 }
222
223 /*
224 * To prevent deadlock, we need to get the list lock first.
225 * Deadlock scenario:
226 * Us: LOCKED(log), want to LOCK(list)
227 * Someone else calls find_log_by_name_and_lock(log->fullname) ->
228 * LOCKED(list), wants to LOCK(log)
229 */
230 fibril_mutex_unlock(&log->guard);
231
232 /* Ensuring correct locking order. */
233 fibril_mutex_lock(&log_list_guard);
234 /*
235 * The reference must be still valid because we have not decreased
236 * the reference counter.
237 */
238 fibril_mutex_lock(&log->guard);
239 assert(log->ref_counter > 0);
240 log->ref_counter--;
241
242 if (log->ref_counter > 0) {
243 /*
244 * Meanwhile, someone else increased the ref counter.
245 * No big deal, we just return immediatelly.
246 */
247 fibril_mutex_unlock(&log->guard);
248 fibril_mutex_unlock(&log_list_guard);
249 return;
250 }
251
252 /*
253 * Here we are on a destroy path. We need to
254 * - remove ourselves from the list
255 * - decrease reference of the parent (if not top-level log)
256 * - we must do that after we relaase list lock to prevent
257 * deadlock with ourselves
258 * - destroy dest (if top-level log)
259 */
260 assert(log->ref_counter == 0);
261
262 list_remove(&log->link);
263 fibril_mutex_unlock(&log_list_guard);
264 fibril_mutex_unlock(&log->guard);
265
266 if (log->parent == NULL) {
[87e9392]267 /*
268 * Due to lazy file opening in write_to_log(),
269 * it is possible that no file was actually opened.
270 */
271 if (log->dest->logfile != NULL) {
272 fclose(log->dest->logfile);
273 }
[131d9a4]274 free(log->dest->filename);
275 free(log->dest);
276 } else {
277 fibril_mutex_lock(&log->parent->guard);
278 log_release(log->parent);
279 }
280
[42bde6a]281 logger_log("Destroyed log %s.\n", log->full_name);
[131d9a4]282
283 free(log->name);
284 free(log->full_name);
285
286 free(log);
287}
288
289
[90dc458]290void write_to_log(logger_log_t *log, log_level_t level, const char *message)
291{
292 assert(fibril_mutex_is_locked(&log->guard));
293 assert(log->dest != NULL);
294 fibril_mutex_lock(&log->dest->guard);
295 if (log->dest->logfile == NULL)
296 log->dest->logfile = fopen(log->dest->filename, "a");
297
298 if (log->dest->logfile != NULL) {
299 fprintf(log->dest->logfile, "[%s] %s: %s\n",
300 log->full_name, log_level_str(level),
301 (const char *) message);
302 fflush(log->dest->logfile);
303 }
304
305 fibril_mutex_unlock(&log->dest->guard);
306}
307
[131d9a4]308void registered_logs_init(logger_registered_logs_t *logs)
309{
310 logs->logs_count = 0;
311}
312
313bool register_log(logger_registered_logs_t *logs, logger_log_t *new_log)
314{
315 if (logs->logs_count >= MAX_REFERENCED_LOGS_PER_CLIENT) {
316 return false;
317 }
318
319 assert(fibril_mutex_is_locked(&new_log->guard));
320 new_log->ref_counter++;
321
322 logs->logs[logs->logs_count] = new_log;
323 logs->logs_count++;
324
325 return true;
326}
327
328void unregister_logs(logger_registered_logs_t *logs)
329{
330 for (size_t i = 0; i < logs->logs_count; i++) {
331 logger_log_t *log = logs->logs[i];
332 fibril_mutex_lock(&log->guard);
333 log_release(log);
334 }
335}
336
[cba45af]337/**
338 * @}
339 */
Note: See TracBrowser for help on using the repository browser.