"Fossies" - the Fresh Open Source Software Archive 
Member "pigz-2.6/try.h" (6 Feb 2021, 20563 Bytes) of package /linux/privat/pigz-2.6.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "try.h" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
2.5_vs_2.6.
1 /* try.h -- try / catch / throw exception handling for C99
2 Copyright (C) 2013, 2015 Mark Adler
3 Version 1.2 19 January 2015
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the author be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20
21 Mark Adler madler@alumni.caltech.edu
22 */
23
24 /*
25 Version History
26 1.0 7 Jan 2013 - First version
27 1.1 2 Nov 2013 - Use variadic macros and functions instead of partial
28 structure assignment, allowing arbitrary arguments
29 to printf()
30 1.2 19 Jan 2015 - Obey setjmp() invocation limits from C standard
31 */
32
33 /* To use, include try.h in all source files that use these operations, and
34 compile and link try.c. If pthread threads are used, then there must be an
35 #include <pthread.h> in try.h to make the exception handling thread-safe.
36 (Uncomment the include below.) If threads other than pthread are being
37 used, then try.h and try.c must be modified to use that environment's
38 thread-local storage for the try_stack_ pointer. try.h and try.c assume
39 that the compiler and library conform to the C99 standard, at least with
40 respect to the use of variadic macro and function arguments. */
41
42 /*
43 try.h provides a try / catch / throw exception handler, which allows
44 catching exceptions across any number of levels of function calls. try
45 blocks can be nested as desired, with a throw going to the end of the
46 innermost enclosing try, passing the thrown information to the associated
47 catch block. A global try stack is used, to avoid having to pass exception
48 handler information through all of the functions down to the invocations of
49 throw. The try stack is thread-unique if requested by uncommenting the
50 pthread.h include below. In addition to the macros try, catch, and throw,
51 the macros always, retry, punt, and drop, and the type ball_t are created.
52 All other symbols are of the form try_*_ or TRY_*_, where the final
53 underscore should avoid conflicts with application symbols. The eight
54 exposed names can be changed easily in #defines below.
55
56 A try block encloses code that may throw an exception with the throw()
57 macro, either directly in the try block or in any function called directly
58 or indirectly from the try block. throw() must have at least one argument,
59 which is an integer. The try block is followed by a catch block whose code
60 will be executed when throw() is called with a non-zero first argument. If
61 the first argument of throw() is zero, then execution continues after the
62 catch block. If the try block completes normally, with no throw() being
63 called, then execution continues normally after the catch block.
64
65 There can be only one catch block. catch has one argument which must be a
66 ball_t type variable declared in the current function or block containing
67 the try and catch. That variable is loaded with the information sent by the
68 throw() for use in the catch block.
69
70 throw() may optionally include more information that is passed to the catch
71 block in the ball_t structure. throw() can have one or more arguments,
72 where the first (possibly only) argument is an integer code. The second
73 argument can be a pointer, which will be replaced by NULL in the ball_t
74 structure if not provided. The implementation of throw() in try.c assumes
75 that if the second argument is present and is not NULL, that it is a string.
76 If that string has any percent (%) signs in it, then throw() will run that
77 string through vsnprintf() with any other arguments provided after the
78 string in the throw() invocation, and save the resulting formatted string in
79 the ball_t structure. Information on whether or not the string was
80 allocated is also maintained in the ball_t structure.
81
82 throw() in try.c can be modified to not assume that the second argument is a
83 string. For example, an application may want to assume instead that the
84 second argument is a pointer to a set of information for use in the catch
85 block.
86
87 The catch block may conditionally do a punt(), where the argument of punt()
88 is the argument of catch. This passes the exception on to the next
89 enclosing try/catch handler.
90
91 If a catch block does not always end with a punt(), it should contain a
92 drop(), where the argument of drop() is the argument of catch. This frees
93 the allocated string made if vsnprintf() was used by throw() to generate the
94 string. If printf() format strings are never used, then drop() is not
95 required.
96
97 An always block may be placed between the try and catch block. The
98 statements in that block will be executed regardless of whether or not the
99 try block completed normally. As indicated by the ordering, the always
100 block will be executed before the catch block. This block is not named
101 "finally", since it is different from the finally block in other languages
102 which is executed after the catch block.
103
104 A naked break or continue in a try or always block will go directly to the
105 end of that block.
106
107 A retry from the try block or from any function called from the try block at
108 any level of nesting will restart the try block from the beginning.
109
110 try is thread-safe when compiled with pthread.h. A throw() in a thread can
111 only be caught in the same thread. If a throw() is attempted from a thread
112 without an enclosing try in that thread, even if in another thread there is
113 a try around the pthread_create() that spawned this thread, then the throw
114 will fail on an assert. Each thread has its own thread-unique try stack,
115 which starts off empty.
116
117 If an intermediate function does not have a need for operations in a catch
118 block other than punt, and does not need an always block, then that function
119 does not need a try block. "try { block } catch (err) { punt(err); }" is
120 the same as just "block". More precisely, it's equivalent to "do { block }
121 while (0);", which replicates the behavior of a naked break or continue in a
122 block when it follows try. throw() can be used from a function that has no
123 try. All that is necessary is that there is a try somewhere up the function
124 chain that called the current function in the current thread.
125
126 There must not be a return in any try block, nor a goto in any try block
127 that leaves that block. The always block does not catch a return from the
128 try block. There is no check or protection for an improper use of return or
129 goto. It is up to the user to assure that this doesn't happen. If it does
130 happen, then the reference to the current try block is left on the try
131 stack, and the next throw which is supposed to go to an enclosing try would
132 instead go to this try, possibly after the enclosing function has returned.
133 Mayhem will then ensue. This may be caught by the longjmp() implementation,
134 which would report "longjmp botch" and then abort.
135
136 Any automatic storage variables that are modified in the try block and used
137 in the catch or always block must be declared volatile. Otherwise their
138 value in the catch or always block is indeterminate.
139
140 Any statements between try and always, between try and catch if there is no
141 always, or between always and catch are part of those respective try or
142 always blocks. Use of { } to enclose those blocks is optional, but { }
143 should be used anyway for clarity, style, and to inform smart source editors
144 that the enclosed code is to be indented. Enclosing the catch block with {
145 } is not optional if there is more than one statement in the block.
146 However, even if there is just one statement in the catch block, it should
147 be enclosed in { } anyway for style and editing convenience.
148
149 The contents of the ball_t structure after the first element (int code) can
150 be customized for the application. If ball_t is customized, then the code
151 in try.c should be updated accordingly. If there is no memory allocation in
152 throw(), then drop() can be eliminated.
153
154 Example usage:
155
156 ball_t err;
157 volatile char *temp = NULL;
158 try {
159 ... do something ...
160 if (ret == -1)
161 throw(1, "bad thing happened to %s\n", me);
162 temp = malloc(sizeof(me) + 1);
163 if (temp == NULL)
164 throw(2, "out of memory");
165 ... do more ...
166 if (ret == -1)
167 throw(3, "worse thing happened to %s\n", temp);
168 ... some more code ...
169 }
170 always {
171 free(temp);
172 }
173 catch (err) {
174 fputs(err.why, stderr);
175 drop(err);
176 return err.code;
177 }
178 ... end up here if nothing bad happened ...
179
180
181 More involved example:
182
183 void check_part(void)
184 {
185 ball_t err;
186
187 try {
188 ...
189 if (part == bad1)
190 throw(1);
191 ...
192 if (part == bad2)
193 throw(1);
194 ...
195 }
196 catch (err) {
197 drop(err);
198 throw(3, "part was bad");
199 }
200 }
201
202 void check_input(void)
203 {
204 ...
205 if (input == wrong)
206 throw(4, "input was wrong");
207 ...
208 if (input == stupid)
209 throw(5, "input was stupid");
210 ...
211 check_part();
212 ...
213 }
214
215 void *build_something(void)
216 {
217 ball_t err;
218 volatile void *thing;
219 try {
220 thing = malloc(sizeof(struct thing));
221 ... build up thing ...
222 check_input();
223 ... finish building it ...
224 }
225 catch (err) {
226 free(thing);
227 punt(err);
228 }
229 return thing;
230 }
231
232 int grand_central(void)
233 {
234 ball_t err;
235 void *thing;
236 try {
237 thing = build_something();
238 }
239 catch (err) {
240 fputs(err.why, stderr);
241 drop(err);
242 return err.code;
243 }
244 ... use thing ...
245 free(thing);
246 return 0;
247 }
248
249 */
250
251 #ifndef _TRY_H
252 #define _TRY_H
253
254 #include <stdlib.h>
255 #include <string.h>
256 #include <assert.h>
257 #include <setjmp.h>
258
259 /* If pthreads are used, uncomment this include to make try thread-safe. */
260 #ifndef NOTHREAD
261 # include <pthread.h>
262 #endif
263
264 /* The exposed names can be changed here. */
265 #define ball_t try_ball_t_
266 #define try TRY_TRY_
267 #define always TRY_ALWAYS_
268 #define catch TRY_CATCH_
269 #define throw TRY_THROW_
270 #define retry TRY_RETRY_
271 #define punt TRY_PUNT_
272 #define drop TRY_DROP_
273
274 /* Package of an integer code and any other data to be thrown and caught. Here,
275 why is a string with information to be displayed to indicate why an
276 exception was thrown. free is true if why was allocated and should be freed
277 when no longer needed. This structure can be customized as needed, but it
278 must start with an int code. If it is customized, the try_throw_() function
279 in try.c must also be updated accordingly. As an example, why could be a
280 structure with information for use in the catch block. */
281 typedef struct {
282 int code; /* integer code (required) */
283 int free; /* if true, the message string was allocated */
284 char *why; /* informational string or NULL */
285 } try_ball_t_;
286
287 /* Element in the global try stack (a linked list). */
288 typedef struct try_s_ try_t_;
289 struct try_s_ {
290 jmp_buf env; /* state information for longjmp() to jump back */
291 try_ball_t_ ball; /* data passed from the throw() */
292 try_t_ *next; /* link to the next enclosing try_t, or NULL */
293 };
294
295 /* Global try stack. try.c must be compiled and linked to provide the stack
296 pointer. Use thread-local storage if pthread.h is included before this.
297 Note that a throw can only be caught within the same thread. A new and
298 unique try stack is created for each thread, so any attempt to throw across
299 threads will fail with an assert, by virtue of reaching the end of the
300 stack. */
301 #ifdef PTHREAD_ONCE_INIT
302 extern pthread_key_t try_key_;
303 void try_setup_(void);
304 # define try_stack_ ((try_t_ *)pthread_getspecific(try_key_))
305 # define try_stack_set_(next) \
306 do { \
307 assert(pthread_setspecific(try_key_, next) == 0 && \
308 "try: pthread_setspecific() failed"); \
309 } while (0)
310 #else /* !PTHREAD_ONCE_INIT */
311 extern try_t_ *try_stack_;
312 # define try_setup_()
313 # define try_stack_set_(next) try_stack_ = (next)
314 #endif /* PTHREAD_ONCE_INIT */
315
316 /* Try a block. The block should follow the invocation of try enclosed in { }.
317 The block must be immediately followed by an always or a catch. You must
318 not goto or return out of the try block. A naked break or continue in the
319 try block will go to the end of the block. */
320 #define TRY_TRY_ \
321 do { \
322 try_t_ try_this_; \
323 volatile int try_pushed_ = 1; \
324 try_this_.ball.code = 0; \
325 try_this_.ball.free = 0; \
326 try_this_.ball.why = NULL; \
327 try_setup_(); \
328 try_this_.next = try_stack_; \
329 try_stack_set_(&try_this_); \
330 if (setjmp(try_this_.env) < 2) \
331 do { \
332
333 /* Execute the code between always and catch, whether or not something was
334 thrown. An always block is optional. If present, the always block must
335 follow a try block and be followed by a catch block. The always block
336 should be enclosed in { }. A naked break or continue in the always block
337 will go to the end of the block. It is permitted to use throw in the always
338 block, which will fall up to the next enclosing try. However this will
339 result in a memory leak if the original throw() allocated space for the
340 informational string. So it's best to not throw() in an always block. Keep
341 the always block simple.
342
343 Great care must be taken if the always block uses an automatic storage
344 variable local to the enclosing function that can be modified in the try
345 block. Such variables must be declared volatile. If such a variable is not
346 declared volatile, and if the compiler elects to keep that variable in a
347 register, then the throw will restore that variable to its state at the
348 beginning of the try block, wiping out any change that occurred in the try
349 block. This can cause very confusing bugs until you remember that you
350 didn't follow this rule. */
351 #define TRY_ALWAYS_ \
352 } while (0); \
353 if (try_pushed_) { \
354 try_stack_set_(try_this_.next); \
355 try_pushed_ = 0; \
356 } \
357 do {
358
359 /* Catch an error thrown in the preceding try block. The catch block must
360 follow catch and its parameter, and must be enclosed in { }. The catch must
361 immediately follow the try or always block. It is permitted to use throw()
362 in the catch block, which will fall up to the next enclosing try. However
363 the ball_t passed by throw() must be freed using drop() before doing another
364 throw, to avoid a potential memory leak. The parameter of catch must be a
365 ball_t declared in the function or block containing the catch. It is set to
366 the parameters of the throw() that jumped to the catch. The catch block is
367 not executed if the first parameter of the throw() was zero.
368
369 A catch block should end with either a punt() or a drop().
370
371 Great care must be taken if the catch block uses an automatic storage
372 variable local to the enclosing function that can be modified in the try
373 block. Such variables must be declared volatile. If such a variable is not
374 declared volatile, and if the compiler elects to keep that variable in a
375 register, then the throw will restore that variable to its state at the
376 beginning of the try block, wiping out any change that occurred in the try
377 block. This can cause very confusing bugs until you remember that you
378 didn't follow this rule. */
379 #define TRY_CATCH_(try_ball_) \
380 } while (0); \
381 if (try_pushed_) { \
382 try_stack_set_(try_this_.next); \
383 try_pushed_ = 0; \
384 } \
385 try_ball_ = try_this_.ball; \
386 } while (0); \
387 if (try_ball_.code)
388
389 /* Throw an error. This can be in the try block or in any function called from
390 the try block, at any level of nesting. This will fall back to the end of
391 the first enclosing try block in the same thread, invoking the associated
392 catch block with a ball_t set to the arguments of throw(). throw() will
393 abort the program with an assert() if there is no nesting try. Make sure
394 that there's a nesting try!
395
396 try may have one or more arguments, where the first argument is an int, the
397 optional second argument is a string, and the remaining optional arguments
398 are referred to by printf() formatting commands in the string. If there are
399 formatting commands in the string, i.e. any percent (%) signs, then
400 vsnprintf() is used to generate the formatted string from the arguments
401 before jumping to the enclosing try block. This allows throw() to use
402 information on the stack in the scope of the throw() statement, which will
403 be lost after jumping back to the enclosing try block. That formatted
404 string will use allocated memory, which is why it is important to use drop()
405 in catch blocks to free that memory, or punt() to pass the string on to
406 another catch block. Eventually some catch block down the chain will have
407 to drop() it.
408
409 If a memory allocation fails during the execution of a throw(), then the
410 string provided to the catch block is not the formatted string at all, but
411 rather the string: "try: out of memory", with the integer code from the
412 throw() unchanged.
413
414 If the first argument of throw is zero, then the catch block is not
415 executed. A throw(0) from a function called in the try block is equivalent
416 to a break or continue in the try block. A throw(0) should not have any
417 other arguments, to avoid a potential memory leak. There is no opportunity
418 to make use of any arguments after the 0 anyway.
419
420 try.c must be compiled and linked to provide the try_throw_() function. */
421 void try_throw_(int code, char *fmt, ...);
422 #define TRY_THROW_(...) try_throw_(__VA_ARGS__, NULL)
423
424 /* Retry the try block. This will start over at the beginning of the try
425 block. This can be used in the try block or in any function called from the
426 try block at any level of nesting, just like throw. retry has no argument.
427 If there is a retry in the always or catch block, then it will retry the
428 next enclosing try, not the immediately preceding try.
429
430 If you use this, make sure you have carefully thought through how it will
431 work. It can be tricky to correctly rerun a chunk of code that has been
432 partially executed. Especially if there are different degrees of progress
433 that could have been made. Also note that automatic variables changed in
434 the try block and not declared volatile will have indeterminate values.
435
436 We use 1 here instead of 0, since some implementations prevent returning a
437 zero value from longjmp() to setjmp(). */
438 #define TRY_RETRY_ \
439 do { \
440 try_setup_(); \
441 assert(try_stack_ != NULL && "try: naked retry"); \
442 longjmp(try_stack_->env, 1); \
443 } while (0)
444
445 /* Punt a caught error on to the next enclosing catcher. This is normally used
446 in a catch block with same argument as the catch. */
447 #define TRY_PUNT_(try_ball_) \
448 do { \
449 try_setup_(); \
450 assert(try_stack_ != NULL && "try: naked punt"); \
451 try_stack_->ball = try_ball_; \
452 longjmp(try_stack_->env, 2); \
453 } while (0)
454
455 /* Clean up at the end of the line in a catch (no more punts). */
456 #define TRY_DROP_(try_ball_) \
457 do { \
458 if (try_ball_.free) { \
459 free(try_ball_.why); \
460 try_ball_.free = 0; \
461 try_ball_.why = NULL; \
462 } \
463 } while (0)
464
465 #endif /* _TRY_H */