multithreaded caches in vector.c (same scheme as in errors.c). Declared all those...
[polylib.git] / source / arith / errors.c
blobef2dc347d053ed4f15936b03ed87744c5047357d
1 /*
2 This file is part of PolyLib.
4 PolyLib is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 PolyLib is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with PolyLib. If not, see <http://www.gnu.org/licenses/>.
19 $Id: errors.c,v 1.6 2006/03/15 19:59:37 verdoolaege Exp $
21 Exception management.
22 See "arithmetic_errors.h".
24 $Log: errors.c,v $
25 Revision 1.6 2006/03/15 19:59:37 verdoolaege
26 arith: add some missing consts
28 Revision 1.5 2004/08/31 18:01:56 verdoolaege
29 remove warning
31 Revision 1.4 2004/02/11 10:19:54 verdoolaege
32 add const qualifier
34 Revision 1.3 2004/02/08 21:53:27 kienhuis
35 Update from Fabien Coelho, via Bart Kienhuis
37 I've updated here in the C3/Linear library the arithmetic_error
38 package that I developped (with others) to handle exceptions in C.
39 It adds a simple callback feature which is needed for pips here.
40 If you do not use it, it should not harm;-)
42 Revision 1.27 2003/09/04 09:40:37 coelho
43 init added.
44 verbosity mask added.
46 Revision 1.26 2003/09/03 14:05:20 coelho
47 push/pop callbacks called.
49 Revision 1.20 2003/08/18 09:55:09 coelho
50 get_exception_name added...
52 Revision 1.19 2003/06/13 13:59:07 coelho
53 const out.
55 Revision 1.18 2003/06/13 13:54:47 coelho
56 hop.
58 Revision 1.17 2002/04/02 08:44:54 coelho
59 timeout_error ajoute.
61 Revision 1.16 2000/10/27 13:26:03 ancourt
62 exception_thrown -> linear_number_of_exception_thrown
64 Revision 1.15 2000/07/27 15:21:55 coelho
65 message++
67 Revision 1.14 2000/07/27 14:59:59 coelho
68 trace added.
70 Revision 1.13 2000/07/26 08:41:23 coelho
71 the_last_just_thrown_exception management added.
73 Revision 1.12 1998/10/26 18:48:34 coelho
74 message++.
76 Revision 1.11 1998/10/26 14:38:06 coelho
77 constants back in.
79 Revision 1.10 1998/10/26 14:35:47 coelho
80 constants in .h.
82 Revision 1.9 1998/10/24 15:36:22 coelho
83 better exception error messages...
85 Revision 1.8 1998/10/24 15:19:17 coelho
86 more verbose throw...
88 Revision 1.7 1998/10/24 14:31:13 coelho
89 new stack implementation.
90 checks for matching catch/uncatch.
91 debug mode.
93 Revision 1.6 1998/10/24 09:31:06 coelho
94 RCS headers.
95 'const' tried.
99 #include <stdio.h>
100 #include <stdlib.h>
101 #include <string.h>
103 //#define THREAD_SAFE_POLYLIB
105 #include "arithmetique.h"
107 /* global constants to designate exceptions.
108 to be put in the type field bellow.
109 cproto 4.6 does not line 'const'...
111 unsigned int overflow_error = 1;
112 unsigned int simplex_arithmetic_error = 2;
113 unsigned int user_exception_error = 4;
114 unsigned int parser_exception_error = 8;
115 unsigned int timeout_error = 16;
117 /* catch all */
118 unsigned int any_exception_error = ~0;
122 * On a few systems, type boolean and/or its values FALSE, TRUE may appear
123 * in standard header files. Or you may have conflicts with application-
124 * specific header files that you want to include together with these files.
125 * Defining HAVE_BOOLEAN before including jpeglib.h should make it work.
128 #ifndef HAVE_BOOLEAN
129 typedef int boolean;
130 #endif
131 #ifndef FALSE /* in case these macros already exist */
132 #define FALSE 0 /* values of boolean */
133 #endif
134 #ifndef TRUE
135 #define TRUE 1
136 #endif
138 const char *get_exception_name(unsigned int exception)
140 if (exception==overflow_error)
141 return "overflow_error exception";
142 if (exception==simplex_arithmetic_error)
143 return "simplex_arithmetic_error exception";
144 if (exception==user_exception_error)
145 return "user_exception_error exception";
146 if (exception==parser_exception_error)
147 return "parser_exception_error exception";
148 if (exception==timeout_error)
149 return "timeout_error exception";
150 if (exception==any_exception_error)
151 return "all exceptions mask";
153 return "unknown or mixed exception";
156 /* keep track of last thrown exception for RETHROW()
158 unsigned int the_last_just_thrown_exception = 0;
160 /* whether to run in debug mode (that is to trace catch/uncatch/throw)
162 static int linear_exception_debug_mode = FALSE;
163 static unsigned int linear_exception_verbose = 1 | 2 | 16 ;
165 /* A structure for the exception stack.
167 typedef struct
169 /* exception type.
171 int what;
173 /* where to jump to.
175 jmp_buf where;
177 /* location of the CATCH to be matched against the UNCATCH.
179 const char * function;
180 const char * file;
181 int line;
183 linear_exception_holder;
185 #define MAX_STACKED_CONTEXTS 64
188 /***************************************************/
189 /** Vincent's patch to enable POSIX multithreading */
190 /** Feb. 2012 */
191 /***************************************************/
192 #ifdef THREAD_SAFE_POLYLIB
193 #include <pthread.h>
194 #include <assert.h>
196 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
197 static pthread_key_t mt_key;
198 /* (int)exception_index is stored in the last+1 exception stack position */
199 #define exception_index (exception_stack[MAX_STACKED_CONTEXTS].what)
200 static linear_exception_holder *allocate_local_stack(void)
202 linear_exception_holder *exception_stack;
203 exception_stack = malloc( sizeof(linear_exception_holder)*(MAX_STACKED_CONTEXTS+1) );
204 assert( exception_stack!=NULL );
205 exception_index = 0;
206 assert( pthread_setspecific( mt_key, exception_stack ) == 0 );
207 return( exception_stack );
209 static void free_local_stack(void *es)
211 free(es);
212 assert( pthread_setspecific(mt_key, NULL) == 0 );
214 static void init_multithreaded_stacks(void)
216 pthread_key_create(&mt_key, free_local_stack);
218 #else // NO THREAD_SAFE_POLYLIB
220 /* exception stack.
221 maximum extension.
222 current index (next available bucket)
224 static linear_exception_holder exception_stack[MAX_STACKED_CONTEXTS];
225 static int exception_index = 0;
227 #endif // THREAD_SAFE_POLYLIB
229 /* callbacks...
231 static exception_callback_t push_callback = NULL;
232 static exception_callback_t pop_callback = NULL;
234 void set_exception_callbacks(exception_callback_t push,
235 exception_callback_t pop)
237 if (push_callback!=NULL || pop_callback!=NULL)
239 fprintf(stderr, "exception callbacks already defined! (%p, %p)\n",
240 push_callback, pop_callback);
241 abort();
244 push_callback = push;
245 pop_callback = pop;
248 /* total number of exceptions thrown, for statistics.
250 int linear_number_of_exception_thrown = 0;
252 /* dump stack
254 void dump_exception_stack_to_file(FILE * f)
256 int i;
257 #ifdef THREAD_SAFE_POLYLIB
258 linear_exception_holder *exception_stack;
259 if( (exception_stack = pthread_getspecific( mt_key )) == NULL )
260 exception_stack = allocate_local_stack();
261 #endif // THREAD_SAFE_POLYLIB
263 fprintf(f, "[dump_exception_stack_to_file] size=%d\n", exception_index);
264 for (i=0; i<exception_index; i++)
266 fprintf(f,
267 "%d: [%s:%d in %s (%d)]\n",
269 exception_stack[i].file,
270 exception_stack[i].line,
271 exception_stack[i].function,
272 exception_stack[i].what);
274 fprintf(f, "\n");
277 void dump_exception_stack()
279 dump_exception_stack_to_file(stderr);
282 #define exception_debug_message(type) \
283 fprintf(stderr, "%s[%s:%d %s (%s)/%d]\n", \
284 type, file, line, function, get_exception_name(what), exception_index)
286 #define exception_debug_trace(type) \
287 if (linear_exception_debug_mode) { exception_debug_message(type); }
289 /* push a what exception on stack.
291 jmp_buf *
292 push_exception_on_stack(
293 int what,
294 const char * function,
295 const char * file,
296 int line)
298 #ifdef THREAD_SAFE_POLYLIB
299 assert(pthread_once(&once_control, init_multithreaded_stacks) == 0);
300 linear_exception_holder *exception_stack;
301 if( (exception_stack = pthread_getspecific( mt_key )) == NULL )
302 exception_stack = allocate_local_stack();
303 #endif // THREAD_SAFE_POLYLIB
305 exception_debug_trace("PUSH ");
308 if (exception_index==MAX_STACKED_CONTEXTS)
310 exception_debug_message("push");
311 fprintf(stderr, "exception stack overflow\n");
312 dump_exception_stack();
313 abort();
316 if (push_callback) push_callback(file, function, line);
318 the_last_just_thrown_exception = 0;
320 exception_stack[exception_index].what = what;
321 exception_stack[exception_index].function = function;
322 exception_stack[exception_index].file = file;
323 exception_stack[exception_index].line = line;
325 return & exception_stack[exception_index++].where;
328 #if !defined(same_string_p)
329 #define same_string_p(s1, s2) (strcmp((s1),(s2))==0)
330 #endif
332 /* pop a what exception.
333 check for any mismatch!
335 void
336 pop_exception_from_stack(
337 int what,
338 const char * function,
339 const char * file,
340 int line)
342 #ifdef THREAD_SAFE_POLYLIB
343 assert(pthread_once(&once_control, init_multithreaded_stacks) == 0);
344 linear_exception_holder *exception_stack;
345 if( (exception_stack = pthread_getspecific( mt_key )) == NULL )
346 exception_stack = allocate_local_stack();
347 #endif // THREAD_SAFE_POLYLIB
349 exception_debug_trace("POP ");
351 if (exception_index==0)
353 exception_debug_message("pop");
354 fprintf(stderr, "exception stack underflow\n");
355 dump_exception_stack();
356 abort();
359 if (pop_callback) pop_callback(file, function, line);
361 exception_index--;
362 the_last_just_thrown_exception = 0;
364 if ((exception_stack[exception_index].what != what) ||
365 !same_string_p(exception_stack[exception_index].file, file) ||
366 !same_string_p(exception_stack[exception_index].function, function))
368 exception_debug_message("pop");
369 fprintf(stderr,
370 "exception stack mismatch at depth=%d:\n"
371 " CATCH: %s:%d in %s (%d)\n"
372 " UNCATCH: %s:%d in %s (%d)\n",
373 exception_index,
374 exception_stack[exception_index].file,
375 exception_stack[exception_index].line,
376 exception_stack[exception_index].function,
377 exception_stack[exception_index].what,
378 file, line, function, what);
379 dump_exception_stack();
380 abort();
384 /* throws an exception of a given type by searching for
385 the specified 'what' in the current exception stack.
387 void throw_exception(
388 int what,
389 const char * function,
390 const char * file,
391 int line)
393 int i;
394 #ifdef THREAD_SAFE_POLYLIB
395 assert(pthread_once(&once_control, init_multithreaded_stacks) == 0);
396 linear_exception_holder *exception_stack;
397 if( (exception_stack = pthread_getspecific( mt_key )) == NULL )
398 exception_stack = allocate_local_stack();
399 #endif // THREAD_SAFE_POLYLIB
401 exception_debug_trace("THROW");
403 the_last_just_thrown_exception = what; /* for rethrow */
405 for (i=exception_index-1; i>=0; i--)
407 if (pop_callback)
408 /* pop with push parameters! */
409 pop_callback(exception_stack[i].file,
410 exception_stack[i].function,
411 exception_stack[i].line);
413 if (exception_stack[i].what & what)
415 exception_index = i;
416 linear_number_of_exception_thrown++;
418 if (linear_exception_debug_mode)
419 fprintf(stderr, "---->[%s:%d %s (%d)/%d]\n",
420 exception_stack[i].file,
421 exception_stack[i].line,
422 exception_stack[i].function,
423 exception_stack[i].what,
426 /* trace some exceptions... */
427 if (linear_exception_verbose & what)
428 fprintf(stderr, "exception %d/%d: %s(%s:%d) -> %s(%s:%d)\n",
429 what, exception_stack[i].what,
430 function, file, line,
431 exception_stack[i].function,
432 exception_stack[i].file,
433 exception_stack[i].line);
435 longjmp(exception_stack[i].where, 0);
439 /* error. */
440 exception_debug_message("throw");
441 fprintf(stderr,
442 "exception not found in stack:\n"
443 "an exception was THROWN without a proper matching CATCH\n");
444 dump_exception_stack();
445 abort();
448 void linear_initialize_exception_stack(
449 unsigned int verbose_exceptions,
450 exception_callback_t push,
451 exception_callback_t pop)
453 linear_exception_verbose = verbose_exceptions;
454 set_exception_callbacks(push, pop);