blob: a0143b9c375fdcc1c876a9cb16b6c073063e5f41 [file] [log] [blame]
Benny Prijonoe0312a72005-11-18 00:16:43 +00001/* $Id$ */
Benny Prijonoe7224612005-11-13 19:40:44 +00002/*
Benny Prijonoe0312a72005-11-18 00:16:43 +00003 * Copyright (C)2003-2006 Benny Prijono <benny@prijono.org>
Benny Prijonoe7224612005-11-13 19:40:44 +00004 *
Benny Prijonoe0312a72005-11-18 00:16:43 +00005 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
Benny Prijonoe7224612005-11-13 19:40:44 +00009 *
Benny Prijonoe0312a72005-11-18 00:16:43 +000010 * This program is distributed in the hope that it will be useful,
Benny Prijonoe7224612005-11-13 19:40:44 +000011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Benny Prijonoe0312a72005-11-18 00:16:43 +000012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Benny Prijonoe7224612005-11-13 19:40:44 +000018 */
Benny Prijonoe7224612005-11-13 19:40:44 +000019#ifndef __PJ_EXCEPTION_H__
20#define __PJ_EXCEPTION_H__
21
22/**
23 * @file except.h
24 * @brief Exception Handling in C.
25 */
26
27#include <pj/types.h>
28#include <pj/compat/setjmp.h>
29
30
31PJ_BEGIN_DECL
32
33
34/**
35 * @defgroup PJ_EXCEPT Exception Handling
36 * @ingroup PJ_MISC
37 * @{
38 *
39 * \section pj_except_sample_sec Quick Example
40 *
41 * For the impatient, take a look at some examples:
42 * - @ref page_pjlib_samples_except_c
43 * - @ref page_pjlib_exception_test
44 *
45 * \section pj_except_except Exception Handling
46 *
47 * This module provides exception handling syntactically similar to C++ in
48 * C language. The underlying mechanism use setjmp() and longjmp(), and since
49 * these constructs are ANSI standard, the mechanism here should be available
50 * on most platforms/compilers which are ANSI compliant.
51 *
52 * If ANSI libc is not available, then setjmp()/longjmp() implementation will
53 * be provided. See <pj/compat/setjmp.h> for compatibility.
54 *
55 * The exception handling mechanism is completely thread safe, so the exception
56 * thrown by one thread will not interfere with other thread.
57 *
58 * CAVEATS:
59 * - unlike C++ exception, the scheme here won't call destructors of local
60 * objects if exception is thrown. Care must be taken when a function
61 * hold some resorce such as pool or mutex etc.
62 * - You CAN NOT make nested exception in one single function without using
63 * a nested PJ_USE_EXCEPTION.
64 * - Exceptions will always be caught by the first handle (unlike C++ where
65 * exception is only caught if the type matches.
66 *
67 * The exception handling constructs are similar to C++. The blocks will be
68 * constructed similar to the following sample:
69 *
70 * \verbatim
71 #define NO_MEMORY 1
72 #define SYNTAX_ERROR 2
73
74 int main()
75 {
76 PJ_USE_EXCEPTION; // declare local exception stack.
77
78 PJ_TRY {
79 ...// do something..
80 }
81 PJ_CATCH(NO_MEMORY) {
82 ... // handle exception 1
83 }
84 PJ_CATCH(SYNTAX_ERROR) {
85 ... // handle exception 2
86 }
87 PJ_DEFAULT {
88 ... // handle other exceptions.
89 }
90 PJ_END;
91 }
92 \endverbatim
93 *
94 * The above sample uses hard coded exception ID. It is @b strongly
95 * recommended that applications request a unique exception ID instead
96 * of hard coded value like above.
97 *
98 * \section pj_except_reg Exception ID Allocation
99 *
100 * To ensure that exception ID (number) are used consistently and to
101 * prevent ID collisions in an application, it is strongly suggested that
102 * applications allocate an exception ID for each possible exception
103 * type. As a bonus of this process, the application can identify
104 * the name of the exception when the particular exception is thrown.
105 *
106 * Exception ID management are performed with the following APIs:
107 * - #pj_exception_id_alloc().
108 * - #pj_exception_id_free().
109 * - #pj_exception_id_name().
110 *
111 *
112 * PJLIB itself automatically allocates one exception id, i.e.
113 * #PJ_NO_MEMORY_EXCEPTION which is declared in <pj/pool.h>. This exception
114 * ID is raised by default pool policy when it fails to allocate memory.
115 *
116 * \section PJ_EX_KEYWORDS Keywords
117 *
118 * \subsection PJ_THROW PJ_THROW(expression)
119 * Throw an exception. The expression thrown is an integer as the result of
120 * the \a expression. This keyword can be specified anywhere within the
121 * program.
122 *
123 * \subsection PJ_USE_EXCEPTION PJ_USE_EXCEPTION
124 * Specify this in the variable definition section of the function block
125 * (or any blocks) to specify that the block has \a PJ_TRY/PJ_CATCH exception
126 * block.
127 * Actually, this is just a macro to declare local variable which is used to
128 * push the exception state to the exception stack.
129 *
130 * \subsection PJ_TRY PJ_TRY
131 * The \a PJ_TRY keyword is typically followed by a block. If an exception is
132 * thrown in this block, then the execution will resume to the \a PJ_CATCH
133 * handler.
134 *
135 * \subsection PJ_CATCH PJ_CATCH(expression)
136 * The \a PJ_CATCH is normally followed by a block. This block will be executed
137 * if the exception being thrown is equal to the expression specified in the
138 * \a PJ_CATCH.
139 *
140 * \subsection PJ_DEFAULT PJ_DEFAULT
141 * The \a PJ_DEFAULT keyword is normally followed by a block. This block will
142 * be executed if the exception being thrown doesn't match any of the \a
143 * PJ_CATCH specification. The \a PJ_DEFAULT block \b MUST be placed as the
144 * last block of the handlers.
145 *
146 * \subsection PJ_END PJ_END
147 * Specify this keyword to mark the end of \a PJ_TRY / \a PJ_CATCH blocks.
148 *
149 * \subsection PJ_GET_EXCEPTION PJ_GET_EXCEPTION(void)
150 * Get the last exception thrown. This macro is normally called inside the
151 * \a PJ_CATCH or \a PJ_DEFAULT block, altough it can be used anywhere where
152 * the \a PJ_USE_EXCEPTION definition is in scope.
153 *
154 *
155 * \section pj_except_examples_sec Examples
156 *
157 * For some examples on how to use the exception construct, please see:
158 * - @ref page_pjlib_samples_except_c
159 * - @ref page_pjlib_exception_test
160 */
161
162/**
163 * Allocate a unique exception id.
164 * Applications don't have to allocate a unique exception ID before using
165 * the exception construct. However, by doing so it ensures that there is
166 * no collisions of exception ID.
167 *
168 * As a bonus, when exception number is acquired through this function,
169 * the library can assign name to the exception (only if
170 * PJ_HAS_EXCEPTION_NAMES is enabled (default is yes)) and find out the
171 * exception name when it catches an exception.
172 *
173 * @param name Name to be associated with the exception ID.
174 * @param id Pointer to receive the ID.
175 *
176 * @return PJ_SUCCESS on success or PJ_ETOOMANY if the library
177 * is running out out ids.
178 */
179PJ_DECL(pj_status_t) pj_exception_id_alloc(const char *name,
180 pj_exception_id_t *id);
181
182/**
183 * Free an exception id.
184 *
185 * @param id The exception ID.
186 *
187 * @return PJ_SUCCESS or the appropriate error code.
188 */
189PJ_DECL(pj_status_t) pj_exception_id_free(pj_exception_id_t id);
190
191/**
192 * Retrieve name associated with the exception id.
193 *
194 * @param id The exception ID.
195 *
196 * @return The name associated with the specified ID.
197 */
198PJ_DECL(const char*) pj_exception_id_name(pj_exception_id_t id);
199
200
201/** @} */
202
203/**
204 * This structure (which should be invisible to user) manages the TRY handler
205 * stack.
206 */
207struct pj_exception_state_t
208{
209 struct pj_exception_state_t *prev; /**< Previous state in the list. */
210 pj_jmp_buf state; /**< jmp_buf. */
211};
212
213/**
214 * Throw exception.
215 * @param id Exception Id.
216 */
217PJ_DECL_NO_RETURN(void)
218pj_throw_exception_(pj_exception_id_t id) PJ_ATTR_NORETURN;
219
220/**
221 * Push exception handler.
222 */
223PJ_DECL(void) pj_push_exception_handler_(struct pj_exception_state_t *rec);
224
225/**
226 * Pop exception handler.
227 */
228PJ_DECL(void) pj_pop_exception_handler_(void);
229
230/**
231 * Declare that the function will use exception.
232 * @hideinitializer
233 */
234#define PJ_USE_EXCEPTION struct pj_exception_state_t pj_x_except__; int pj_x_code__
235
236/**
237 * Start exception specification block.
238 * @hideinitializer
239 */
240#define PJ_TRY if (1) { \
241 pj_push_exception_handler_(&pj_x_except__); \
242 pj_x_code__ = pj_setjmp(pj_x_except__.state); \
243 if (pj_x_code__ == 0)
244/**
245 * Catch the specified exception Id.
246 * @param id The exception number to catch.
247 * @hideinitializer
248 */
249#define PJ_CATCH(id) else if (pj_x_code__ == (id))
250
251/**
252 * Catch any exception number.
253 * @hideinitializer
254 */
255#define PJ_DEFAULT else
256
257/**
258 * End of exception specification block.
259 * @hideinitializer
260 */
261#define PJ_END pj_pop_exception_handler_(); \
262 } else {}
263
264/**
265 * Throw exception.
266 * @param exception_id The exception number.
267 * @hideinitializer
268 */
269#define PJ_THROW(exception_id) pj_throw_exception_(exception_id)
270
271/**
272 * Get current exception.
273 * @return Current exception code.
274 * @hideinitializer
275 */
276#define PJ_GET_EXCEPTION() (pj_x_code__)
277
278PJ_END_DECL
279
280
281
282#endif /* __PJ_EXCEPTION_H__ */
283
284