source: mainline/uspace/srv/logger/namespace.c@ 01b8c2e4

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

Fix deadlock (recursive mutex locking)

  • Property mode set to 100644
File size: 6.8 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 <malloc.h>
34#include <str.h>
35#include <stdio.h>
36#include "logger.h"
37
38/** @file
39 * Logging namespaces.
40 */
41
42struct logging_namespace {
43 fibril_mutex_t guard;
44 size_t writers_count;
45 fibril_condvar_t reader_appeared_cv;
46 bool has_reader;
47 const char *name;
48 link_t link;
49 prodcons_t messages;
50};
51
52static FIBRIL_MUTEX_INITIALIZE(namespace_list_guard);
53static LIST_INITIALIZE(namespace_list);
54
55log_message_t *message_create(const char *name, log_level_t level)
56{
57 log_message_t *message = malloc(sizeof(log_message_t));
58 if (message == NULL)
59 return NULL;
60
61 message->message = str_dup(name);
62 if (message->message == NULL) {
63 free(message);
64 return NULL;
65 }
66
67 message->level = level;
68 link_initialize(&message->link);
69
70 return message;
71}
72
73void message_destroy(log_message_t *message)
74{
75 assert(message);
76 free(message->message);
77 free(message);
78}
79
80static logging_namespace_t *namespace_find_no_lock(const char *name)
81{
82 list_foreach(namespace_list, it) {
83 logging_namespace_t *namespace = list_get_instance(it, logging_namespace_t, link);
84 if (str_cmp(namespace->name, name) == 0) {
85 return namespace;
86 }
87 }
88
89 return NULL;
90}
91
92static logging_namespace_t *namespace_create_no_lock(const char *name)
93{
94 logging_namespace_t *existing = namespace_find_no_lock(name);
95 if (existing != NULL) {
96 return NULL;
97 }
98
99 logging_namespace_t *namespace = malloc(sizeof(logging_namespace_t));
100 if (namespace == NULL) {
101 return NULL;
102 }
103
104 namespace->name = str_dup(name);
105 if (namespace->name == NULL) {
106 free(namespace);
107 return NULL;
108 }
109
110 fibril_mutex_initialize(&namespace->guard);
111 prodcons_initialize(&namespace->messages);
112 namespace->has_reader = false;
113 namespace->writers_count = 0;
114 link_initialize(&namespace->link);
115
116 list_append(&namespace->link, &namespace_list);
117
118 return namespace;
119}
120
121
122logging_namespace_t *namespace_create(const char *name)
123{
124 fibril_mutex_lock(&namespace_list_guard);
125 logging_namespace_t *result = namespace_create_no_lock(name);
126 fibril_mutex_unlock(&namespace_list_guard);
127 return result;
128}
129
130const char *namespace_get_name(logging_namespace_t *namespace)
131{
132 assert(namespace);
133 return namespace->name;
134}
135
136static void namespace_destroy_careful(logging_namespace_t *namespace)
137{
138 assert(namespace);
139 fibril_mutex_lock(&namespace_list_guard);
140
141 fibril_mutex_lock(&namespace->guard);
142 if (namespace->has_reader || (namespace->writers_count > 0)) {
143 fibril_mutex_unlock(&namespace->guard);
144 fibril_mutex_unlock(&namespace_list_guard);
145 return;
146 }
147
148 list_remove(&namespace->link);
149
150 fibril_mutex_unlock(&namespace->guard);
151 fibril_mutex_unlock(&namespace_list_guard);
152
153 // TODO - destroy pending messages
154 free(namespace->name);
155 free(namespace);
156}
157
158void namespace_destroy(logging_namespace_t *namespace)
159{
160 namespace_destroy_careful(namespace);
161}
162
163logging_namespace_t *namespace_reader_attach(const char *name)
164{
165 logging_namespace_t *namespace = NULL;
166
167 fibril_mutex_lock(&namespace_list_guard);
168
169 namespace = namespace_find_no_lock(name);
170
171 if (namespace != NULL) {
172 fibril_mutex_lock(&namespace->guard);
173 namespace->has_reader = true;
174 fibril_condvar_broadcast(&namespace->reader_appeared_cv);
175 fibril_mutex_unlock(&namespace->guard);
176 }
177
178 fibril_mutex_unlock(&namespace_list_guard);
179
180 return namespace;
181}
182
183logging_namespace_t *namespace_writer_attach(const char *name)
184{
185 logging_namespace_t *namespace = NULL;
186
187 fibril_mutex_lock(&namespace_list_guard);
188
189 namespace = namespace_find_no_lock(name);
190
191 if (namespace == NULL) {
192 namespace = namespace_create_no_lock(name);
193 }
194
195 fibril_mutex_lock(&namespace->guard);
196 namespace->writers_count++;
197 fibril_mutex_unlock(&namespace->guard);
198
199 fibril_mutex_unlock(&namespace_list_guard);
200
201 return namespace;
202}
203
204void namespace_reader_detach(logging_namespace_t *namespace)
205{
206 fibril_mutex_lock(&namespace->guard);
207 namespace->has_reader = false;
208 fibril_condvar_broadcast(&namespace->reader_appeared_cv);
209 fibril_mutex_unlock(&namespace->guard);
210
211 namespace_destroy_careful(namespace);
212}
213
214void namespace_writer_detach(logging_namespace_t *namespace)
215{
216 fibril_mutex_lock(&namespace->guard);
217 assert(namespace->writers_count > 0);
218 namespace->writers_count--;
219 fibril_mutex_unlock(&namespace->guard);
220
221 namespace_destroy_careful(namespace);
222}
223
224bool namespace_has_reader(logging_namespace_t *namespace)
225{
226 fibril_mutex_lock(&namespace->guard);
227 bool has_reader = namespace->has_reader;
228 fibril_mutex_unlock(&namespace->guard);
229 return has_reader;
230}
231
232void namespace_wait_for_reader_change(logging_namespace_t *namespace, bool *has_reader_now)
233{
234 fibril_mutex_lock(&namespace->guard);
235 bool had_reader = namespace->has_reader;
236 while (had_reader == namespace->has_reader) {
237 fibril_condvar_wait(&namespace->reader_appeared_cv, &namespace->guard);
238 }
239 *has_reader_now = namespace->has_reader;
240 fibril_mutex_unlock(&namespace->guard);
241}
242
243
244void namespace_add_message(logging_namespace_t *namespace, const char *message, log_level_t level)
245{
246 if (level <= DEFAULT_LOGGING_LEVEL) {
247 printf("[%s %d]: %s\n", namespace->name, level, message);
248 }
249
250 fibril_mutex_lock(&namespace->guard);
251 if (namespace->has_reader) {
252 log_message_t *msg = message_create(message, level);
253 if (msg != NULL) {
254 prodcons_produce(&namespace->messages, &msg->link);
255 }
256 }
257 fibril_mutex_unlock(&namespace->guard);
258}
259
260log_message_t *namespace_get_next_message(logging_namespace_t *namespace)
261{
262 link_t *message = prodcons_consume(&namespace->messages);
263
264 return list_get_instance(message, log_message_t, link);
265}
266
267
268/**
269 * @}
270 */
Note: See TracBrowser for help on using the repository browser.