1 /**************************************************************************\
2 * Copyright (c) Kongsberg Oil & Gas Technologies AS
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 are
7 * met:
8 *
9 * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32
33 /*! \file error.h */
34 #include <Inventor/C/errors/error.h>
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif /* HAVE_CONFIG_H */
39
40 #include <cstdio>
41 #include <cassert>
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h> /* STDERR_FILENO */
44 #endif /* HAVE_UNISTD_H */
45
46 #ifdef COIN_THREADSAFE
47 #include <Inventor/C/threads/mutex.h>
48 #include "threads/mutexp.h"
49 #endif /* COIN_THREADSAFE */
50
51 #include "coindefs.h"
52 #include "tidbitsp.h"
53
54 /* ********************************************************************** */
55
56 /*!
57 \struct cc_error error.h Inventor/C/errors/error.h
58 \typedef struct cc_error cc_error
59 \brief The cc_error type is an internal Coin structure for error management.
60
61 \ingroup errors
62
63 This is a Coin extension.
64 */
65
66 /*!
67 \var cc_error::debugstring
68
69 The error message.
70 */
71
72 /*!
73 \typedef void cc_error_cb(const cc_error * err, void * data)
74
75 The definition for an error callback handler.
76 */
77
78 #ifdef __cplusplus
79 extern "C" {
80 #endif /* __cplusplus */
81
82 #ifdef COIN_THREADSAFE
83 static cc_mutex * cc_error_mutex = NULL;
cc_error_mutex_cleanup(void)84 static void cc_error_mutex_cleanup(void) {
85 if (cc_error_mutex) {
86 cc_mutex_destruct(cc_error_mutex);
87 cc_error_mutex = NULL;
88 }
89 }
90 #endif /* COIN_THREADSAFE */
91
92 /* FIXME: should be hidden from public API, and only visible to
93 subclasses. 20020526 mortene. */
94 /*!
95 \relates cc_error
96 */
97
98 void
cc_error_default_handler_cb(const cc_error * err,void * COIN_UNUSED_ARG (data))99 cc_error_default_handler_cb(const cc_error * err, void * COIN_UNUSED_ARG(data))
100 {
101 /* It is not possible to "pass" C library data from the application
102 to a MSWin .DLL, so this is necessary to get hold of the stderr
103 FILE*. Just using fprintf(stderr, ...) or fprintf(stdout, ...)
104 directly will result in a crash when Coin has been compiled as a
105 .DLL. */
106 FILE * coin_stderr = coin_get_stderr();
107
108 if (coin_stderr) {
109 const cc_string * str = cc_error_get_debug_string(err);
110 (void)fprintf(coin_stderr, "%s\n", cc_string_get_text(str));
111 (void)fflush(coin_stderr);
112 }
113 }
114
115 static cc_error_cb * cc_error_callback = cc_error_default_handler_cb;
116 static void * cc_error_callback_data = NULL;
117 static SbBool cc_error_cleanup_function_set = FALSE;
118
119 static void
cc_error_cleanup(void)120 cc_error_cleanup(void)
121 {
122 cc_error_callback = cc_error_default_handler_cb;
123 cc_error_callback_data = NULL;
124 cc_error_cleanup_function_set = FALSE;
125 }
126
127 /*!
128 \relates cc_error
129 */
130
131 void
cc_error_init(cc_error * me)132 cc_error_init(cc_error * me)
133 {
134 cc_string_construct(&(me->debugstring));
135 }
136
137 /*!
138 \relates cc_error
139 */
140
141 void
cc_error_clean(cc_error * me)142 cc_error_clean(cc_error * me)
143 {
144 cc_string_clean(&(me->debugstring));
145 }
146
147 /*!
148 \relates cc_error
149 */
150
151 void
cc_error_copy(const cc_error * src,cc_error * dst)152 cc_error_copy(const cc_error * src, cc_error * dst)
153 {
154 cc_string_set_string(&dst->debugstring, &src->debugstring);
155 }
156
157 /*!
158 \relates cc_error
159 */
160
161 void
cc_error_set_debug_string(cc_error * me,const char * str)162 cc_error_set_debug_string(cc_error * me, const char * str)
163 {
164 cc_string_set_text(&(me->debugstring), str);
165 }
166
167 /*!
168 \relates cc_error
169 */
170
171 void
cc_error_append_to_debug_string(cc_error * me,const char * str)172 cc_error_append_to_debug_string(cc_error * me, const char * str)
173 {
174 cc_string_append_text(&(me->debugstring), str);
175 }
176
177 /*!
178 \relates cc_error
179 */
180
181 void
cc_error_handle(cc_error * me)182 cc_error_handle(cc_error * me)
183 {
184 void * arg = NULL;
185
186 cc_error_cb * function = cc_error_get_handler(&arg);
187 assert(function != NULL);
188
189 #ifdef COIN_THREADSAFE
190 if (!cc_error_mutex) {
191 /* extra locking to avoid that two threads create the mutex */
192 /* FIXME: this is not smart, as it means that if the first call to
193 e.g. SoDebugError::post*() will hang if it happens within a
194 region where the global lock is already taken. 20050708 mortene.*/
195 cc_mutex_global_lock();
196 if (cc_error_mutex == NULL) {
197 cc_error_mutex = cc_mutex_construct();
198 coin_atexit(cc_error_mutex_cleanup, CC_ATEXIT_MSG_SUBSYSTEM);
199 }
200 cc_mutex_global_unlock();
201 }
202 cc_mutex_lock(cc_error_mutex);
203 #endif /* COIN_THREADSAFE */
204
205 (*function)(me, arg);
206
207 #ifdef COIN_THREADSAFE
208 cc_mutex_unlock(cc_error_mutex);
209 #endif /* COIN_THREADSAFE */
210 }
211
212 /*!
213 \relates cc_error
214 */
215
216 void
cc_error_set_handler_callback(cc_error_cb * func,void * data)217 cc_error_set_handler_callback(cc_error_cb * func, void * data)
218 {
219 cc_error_callback = func;
220 cc_error_callback_data = data;
221
222 if (!cc_error_cleanup_function_set) {
223 coin_atexit((coin_atexit_f*) cc_error_cleanup, CC_ATEXIT_MSG_SUBSYSTEM);
224 cc_error_cleanup_function_set = TRUE;
225 }
226 }
227
228 /*!
229 \relates cc_error
230 */
231
232 cc_error_cb *
cc_error_get_handler_callback(void)233 cc_error_get_handler_callback(void)
234 {
235 return cc_error_callback;
236 }
237
238 /*!
239 \relates cc_error
240 */
241
242 void *
cc_error_get_handler_data(void)243 cc_error_get_handler_data(void)
244 {
245 return cc_error_callback_data;
246 }
247
248 /*!
249 \relates cc_error
250 */
251
252 cc_error_cb *
cc_error_get_handler(void ** data)253 cc_error_get_handler(void ** data)
254 {
255 *data = cc_error_callback_data;
256 return cc_error_callback;
257 }
258
259 /*!
260 \relates cc_error
261 */
262
263 const cc_string *
cc_error_get_debug_string(const cc_error * me)264 cc_error_get_debug_string(const cc_error * me)
265 {
266 return &(me->debugstring);
267 }
268
269 /*!
270 \relates cc_error
271 */
272
273 void
cc_error_post_arglist(const char * format,va_list args)274 cc_error_post_arglist(const char * format, va_list args)
275 {
276 cc_string s;
277 cc_error err;
278
279 cc_string_construct(&s);
280
281 cc_string_vsprintf(&s, format, args);
282
283 cc_error_init(&err);
284 cc_error_set_debug_string(&err, cc_string_get_text(&s));
285 cc_error_handle(&err);
286 cc_error_clean(&err);
287
288 cc_string_clean(&s);
289 }
290
291 /*!
292 \relates cc_error
293 */
294
295 void
cc_error_post(const char * format,...)296 cc_error_post(const char * format, ...)
297 {
298 va_list argptr;
299 va_start(argptr, format);
300 cc_error_post_arglist(format, argptr);
301 va_end(argptr);
302 }
303
304 #ifdef __cplusplus
305 } /* extern "C" */
306 #endif /* __cplusplus */
307