except.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /*
  2. * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
  3. * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
  4. *
  5. * 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.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * 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
  18. */
  19. #ifndef __PJ_EXCEPTION_H__
  20. #define __PJ_EXCEPTION_H__
  21. /**
  22. * @file except.h
  23. * @brief Exception Handling in C.
  24. */
  25. #include <pj/types.h>
  26. #include <pj/compat/setjmp.h>
  27. #include <pj/log.h>
  28. PJ_BEGIN_DECL
  29. /**
  30. * @defgroup PJ_EXCEPT Exception Handling
  31. * @ingroup PJ_MISC
  32. * @{
  33. *
  34. * \section pj_except_sample_sec Quick Example
  35. *
  36. * For the impatient, take a look at some examples:
  37. * - Exception Handling sample: \src{pjlib/src/pjlib-samples/except.c}
  38. * - Exception Handling test: \src{pjlib/src/pjlib-test/exception.c}
  39. *
  40. * \section pj_except_except Exception Handling
  41. *
  42. * This module provides exception handling syntactically similar to C++ in
  43. * C language. In Win32 systems, it uses Windows Structured Exception
  44. * Handling (SEH) if macro PJ_EXCEPTION_USE_WIN32_SEH is non-zero.
  45. * Otherwise it will use setjmp() and longjmp().
  46. *
  47. * On some platforms where setjmp/longjmp is not available, setjmp/longjmp
  48. * implementation is provided. See <pj/compat/setjmp.h> for compatibility.
  49. *
  50. * The exception handling mechanism is completely thread safe, so the exception
  51. * thrown by one thread will not interfere with other thread.
  52. *
  53. * The exception handling constructs are similar to C++. The blocks will be
  54. * constructed similar to the following sample:
  55. *
  56. * \verbatim
  57. #define NO_MEMORY 1
  58. #define SYNTAX_ERROR 2
  59. int sample1()
  60. {
  61. PJ_USE_EXCEPTION; // declare local exception stack.
  62. PJ_TRY {
  63. ...// do something..
  64. }
  65. PJ_CATCH(NO_MEMORY) {
  66. ... // handle exception 1
  67. }
  68. PJ_END;
  69. }
  70. int sample2()
  71. {
  72. PJ_USE_EXCEPTION; // declare local exception stack.
  73. PJ_TRY {
  74. ...// do something..
  75. }
  76. PJ_CATCH_ANY {
  77. if (PJ_GET_EXCEPTION() == NO_MEMORY)
  78. ...; // handle no memory situation
  79. else if (PJ_GET_EXCEPTION() == SYNTAX_ERROR)
  80. ...; // handle syntax error
  81. }
  82. PJ_END;
  83. }
  84. \endverbatim
  85. *
  86. * The above sample uses hard coded exception ID. It is @b strongly
  87. * recommended that applications request a unique exception ID instead
  88. * of hard coded value like above.
  89. *
  90. * \section pj_except_reg Exception ID Allocation
  91. *
  92. * To ensure that exception ID (number) are used consistently and to
  93. * prevent ID collisions in an application, it is strongly suggested that
  94. * applications allocate an exception ID for each possible exception
  95. * type. As a bonus of this process, the application can identify
  96. * the name of the exception when the particular exception is thrown.
  97. *
  98. * Exception ID management are performed with the following APIs:
  99. * - #pj_exception_id_alloc().
  100. * - #pj_exception_id_free().
  101. * - #pj_exception_id_name().
  102. *
  103. *
  104. * PJLIB itself automatically allocates one exception id, i.e.
  105. * #PJ_NO_MEMORY_EXCEPTION which is declared in <pj/pool.h>. This exception
  106. * ID is raised by default pool policy when it fails to allocate memory.
  107. *
  108. * CAVEATS:
  109. * - unlike C++ exception, the scheme here won't call destructors of local
  110. * objects if exception is thrown. Care must be taken when a function
  111. * hold some resorce such as pool or mutex etc.
  112. * - You CAN NOT make nested exception in one single function without using
  113. * a nested PJ_USE_EXCEPTION. Samples:
  114. \verbatim
  115. void wrong_sample()
  116. {
  117. PJ_USE_EXCEPTION;
  118. PJ_TRY {
  119. // Do stuffs
  120. ...
  121. }
  122. PJ_CATCH_ANY {
  123. // Do other stuffs
  124. ....
  125. ..
  126. // The following block is WRONG! You MUST declare
  127. // PJ_USE_EXCEPTION once again in this block.
  128. PJ_TRY {
  129. ..
  130. }
  131. PJ_CATCH_ANY {
  132. ..
  133. }
  134. PJ_END;
  135. }
  136. PJ_END;
  137. }
  138. \endverbatim
  139. * - You MUST NOT exit the function inside the PJ_TRY block. The correct way
  140. * is to return from the function after PJ_END block is executed.
  141. * For example, the following code will yield crash not in this code,
  142. * but rather in the subsequent execution of PJ_TRY block:
  143. \verbatim
  144. void wrong_sample()
  145. {
  146. PJ_USE_EXCEPTION;
  147. PJ_TRY {
  148. // do some stuffs
  149. ...
  150. return; <======= DO NOT DO THIS!
  151. }
  152. PJ_CATCH_ANY {
  153. }
  154. PJ_END;
  155. }
  156. \endverbatim
  157. * - You can not provide more than PJ_CATCH or PJ_CATCH_ANY nor use PJ_CATCH
  158. * and PJ_CATCH_ANY for a single PJ_TRY.
  159. * - Exceptions will always be caught by the first handler (unlike C++ where
  160. * exception is only caught if the type matches.
  161. * \section PJ_EX_KEYWORDS Keywords
  162. *
  163. * \subsection PJ_THROW PJ_THROW(expression)
  164. * Throw an exception. The expression thrown is an integer as the result of
  165. * the \a expression. This keyword can be specified anywhere within the
  166. * program.
  167. *
  168. * \subsection PJ_USE_EXCEPTION PJ_USE_EXCEPTION
  169. * Specify this in the variable definition section of the function block
  170. * (or any blocks) to specify that the block has \a PJ_TRY/PJ_CATCH exception
  171. * block.
  172. * Actually, this is just a macro to declare local variable which is used to
  173. * push the exception state to the exception stack.
  174. * Note: you must specify PJ_USE_EXCEPTION as the last statement in the
  175. * local variable declarations, since it may evaluate to nothing.
  176. *
  177. * \subsection PJ_TRY PJ_TRY
  178. * The \a PJ_TRY keyword is typically followed by a block. If an exception is
  179. * thrown in this block, then the execution will resume to the \a PJ_CATCH
  180. * handler.
  181. *
  182. * \subsection PJ_CATCH PJ_CATCH(expression)
  183. * The \a PJ_CATCH is normally followed by a block. This block will be executed
  184. * if the exception being thrown is equal to the expression specified in the
  185. * \a PJ_CATCH.
  186. *
  187. * \subsection PJ_CATCH_ANY PJ_CATCH_ANY
  188. * The \a PJ_CATCH is normally followed by a block. This block will be executed
  189. * if any exception was raised in the TRY block.
  190. *
  191. * \subsection PJ_END PJ_END
  192. * Specify this keyword to mark the end of \a PJ_TRY / \a PJ_CATCH blocks.
  193. *
  194. * \subsection PJ_GET_EXCEPTION PJ_GET_EXCEPTION(void)
  195. * Get the last exception thrown. This macro is normally called inside the
  196. * \a PJ_CATCH or \a PJ_CATCH_ANY block, altough it can be used anywhere where
  197. * the \a PJ_USE_EXCEPTION definition is in scope.
  198. *
  199. *
  200. * \section pj_except_examples_sec Examples
  201. *
  202. * For some examples on how to use the exception construct, please see:
  203. * - Exception Handling sample: \src{pjlib/src/pjlib-samples/except.c}
  204. * - Exception Handling test: \src{pjlib/src/pjlib-test/exception.c}
  205. */
  206. /**
  207. * Allocate a unique exception id.
  208. * Applications don't have to allocate a unique exception ID before using
  209. * the exception construct. However, by doing so it ensures that there is
  210. * no collisions of exception ID.
  211. *
  212. * As a bonus, when exception number is acquired through this function,
  213. * the library can assign name to the exception (only if
  214. * PJ_HAS_EXCEPTION_NAMES is enabled (default is yes)) and find out the
  215. * exception name when it catches an exception.
  216. *
  217. * @param name Name to be associated with the exception ID.
  218. * @param id Pointer to receive the ID.
  219. *
  220. * @return PJ_SUCCESS on success or PJ_ETOOMANY if the library
  221. * is running out out ids.
  222. */
  223. PJ_DECL(pj_status_t) pj_exception_id_alloc(const char *name,
  224. pj_exception_id_t *id);
  225. /**
  226. * Free an exception id.
  227. *
  228. * @param id The exception ID.
  229. *
  230. * @return PJ_SUCCESS or the appropriate error code.
  231. */
  232. PJ_DECL(pj_status_t) pj_exception_id_free(pj_exception_id_t id);
  233. /**
  234. * Retrieve name associated with the exception id.
  235. *
  236. * @param id The exception ID.
  237. *
  238. * @return The name associated with the specified ID.
  239. */
  240. PJ_DECL(const char*) pj_exception_id_name(pj_exception_id_t id);
  241. /** @} */
  242. #if defined(PJ_EXCEPTION_USE_WIN32_SEH) && PJ_EXCEPTION_USE_WIN32_SEH != 0
  243. /*****************************************************************************
  244. **
  245. ** IMPLEMENTATION OF EXCEPTION USING WINDOWS SEH
  246. **
  247. ****************************************************************************/
  248. #define WIN32_LEAN_AND_MEAN
  249. #include <windows.h>
  250. PJ_IDECL_NO_RETURN(void)
  251. pj_throw_exception_(pj_exception_id_t id) PJ_ATTR_NORETURN
  252. {
  253. RaiseException(id,1,0,NULL);
  254. }
  255. #define PJ_USE_EXCEPTION
  256. #define PJ_TRY __try
  257. #define PJ_CATCH(id) __except(GetExceptionCode()==id ? \
  258. EXCEPTION_EXECUTE_HANDLER : \
  259. EXCEPTION_CONTINUE_SEARCH)
  260. #define PJ_CATCH_ANY __except(EXCEPTION_EXECUTE_HANDLER)
  261. #define PJ_END
  262. #define PJ_THROW(id) pj_throw_exception_(id)
  263. #define PJ_GET_EXCEPTION() GetExceptionCode()
  264. #elif defined(PJ_SYMBIAN) && PJ_SYMBIAN!=0
  265. /*****************************************************************************
  266. **
  267. ** IMPLEMENTATION OF EXCEPTION USING SYMBIAN LEAVE/TRAP FRAMEWORK
  268. **
  269. ****************************************************************************/
  270. /* To include this file, the source file must be compiled as
  271. * C++ code!
  272. */
  273. #ifdef __cplusplus
  274. class TPjException
  275. {
  276. public:
  277. int code_;
  278. };
  279. #define PJ_USE_EXCEPTION
  280. #define PJ_TRY try
  281. //#define PJ_CATCH(id)
  282. #define PJ_CATCH_ANY catch (const TPjException & pj_excp_)
  283. #define PJ_END
  284. #define PJ_THROW(x_id) do { TPjException e; e.code_=x_id; throw e;} \
  285. while (0)
  286. #define PJ_GET_EXCEPTION() pj_excp_.code_
  287. #else
  288. #define PJ_USE_EXCEPTION
  289. #define PJ_TRY
  290. #define PJ_CATCH_ANY if (0)
  291. #define PJ_END
  292. #define PJ_THROW(x_id) do { PJ_LOG(1,("PJ_THROW"," error code = %d",x_id)); } while (0)
  293. #define PJ_GET_EXCEPTION() 0
  294. #endif /* __cplusplus */
  295. #else
  296. /*****************************************************************************
  297. **
  298. ** IMPLEMENTATION OF EXCEPTION USING GENERIC SETJMP/LONGJMP
  299. **
  300. ****************************************************************************/
  301. /**
  302. * This structure (which should be invisible to user) manages the TRY handler
  303. * stack.
  304. */
  305. struct pj_exception_state_t
  306. {
  307. pj_jmp_buf state; /**< jmp_buf. */
  308. struct pj_exception_state_t *prev; /**< Previous state in the list. */
  309. };
  310. /**
  311. * Throw exception.
  312. * @param id Exception Id.
  313. */
  314. PJ_DECL_NO_RETURN(void)
  315. pj_throw_exception_(pj_exception_id_t id) PJ_ATTR_NORETURN;
  316. /**
  317. * Push exception handler.
  318. */
  319. PJ_DECL(void) pj_push_exception_handler_(struct pj_exception_state_t *rec);
  320. /**
  321. * Pop exception handler.
  322. */
  323. PJ_DECL(void) pj_pop_exception_handler_(struct pj_exception_state_t *rec);
  324. /**
  325. * Declare that the function will use exception.
  326. * @hideinitializer
  327. */
  328. #define PJ_USE_EXCEPTION struct pj_exception_state_t pj_x_except__; int pj_x_code__
  329. /**
  330. * Start exception specification block.
  331. * @hideinitializer
  332. */
  333. #define PJ_TRY if (1) { \
  334. pj_push_exception_handler_(&pj_x_except__); \
  335. pj_x_code__ = pj_setjmp(pj_x_except__.state); \
  336. if (pj_x_code__ == 0)
  337. /**
  338. * Catch the specified exception Id.
  339. * @param id The exception number to catch.
  340. * @hideinitializer
  341. */
  342. #define PJ_CATCH(id) else if (pj_x_code__ == (id))
  343. /**
  344. * Catch any exception number.
  345. * @hideinitializer
  346. */
  347. #define PJ_CATCH_ANY else
  348. /**
  349. * End of exception specification block.
  350. * @hideinitializer
  351. */
  352. #define PJ_END pj_pop_exception_handler_(&pj_x_except__); \
  353. } else {}
  354. /**
  355. * Throw exception.
  356. * @param exception_id The exception number.
  357. * @hideinitializer
  358. */
  359. #define PJ_THROW(exception_id) pj_throw_exception_(exception_id)
  360. /**
  361. * Get current exception.
  362. * @return Current exception code.
  363. * @hideinitializer
  364. */
  365. #define PJ_GET_EXCEPTION() (pj_x_code__)
  366. #endif /* PJ_EXCEPTION_USE_WIN32_SEH */
  367. PJ_END_DECL
  368. #endif /* __PJ_EXCEPTION_H__ */