source: mainline/uspace/srv/logger/logs.c@ 8119363

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8119363 was b7fd2a0, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

Use errno_t in all uspace and kernel code.

Change type of every variable, parameter and return value that holds an
<errno.h> constant to either errno_t (the usual case), or sys_errno_t
(some places in kernel). This is for the purpose of self-documentation,
as well as for type-checking with a bit of type definition hackery.

Although this is a massive commit, it is a simple text replacement, and thus
is very easy to verify. Simply do the following:

`
git checkout <this commit's hash>
git reset HEAD
git add .
tools/srepl '\berrno_t\b' int
git add .
tools/srepl '\bsys_errno_t\b' sysarg_t
git reset
git diff
`

While this doesn't ensure that the replacements are correct, it does ensure
that the commit doesn't do anything except those replacements. Since errno_t
is typedef'd to int in the usual case (and sys_errno_t to sysarg_t), even if
incorrect, this commit cannot change behavior.

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