blob: 61c882c435864c052497eb2afaabc55f35aa3a60 [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono9033e312005-11-21 02:08:39 +00005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pj/except.h>
21#include <pj/os.h>
22#include <pj/assert.h>
23#include <pj/log.h>
24#include <pj/errno.h>
Benny Prijono9df1d092006-07-03 01:09:20 +000025#include <pj/string.h>
Benny Prijono9033e312005-11-21 02:08:39 +000026
27static long thread_local_id = -1;
28
29#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0
30 static const char *exception_id_names[PJ_MAX_EXCEPTION_ID];
31#else
32 /*
33 * Start from 1 (not 0)!!!
34 * Exception 0 is reserved for normal path of setjmp()!!!
35 */
36 static int last_exception_id = 1;
37#endif /* PJ_HAS_EXCEPTION_NAMES */
38
39
Benny Prijonod0d44f52005-11-21 16:57:02 +000040#if !defined(PJ_EXCEPTION_USE_WIN32_SEH) || PJ_EXCEPTION_USE_WIN32_SEH==0
Benny Prijono9033e312005-11-21 02:08:39 +000041PJ_DEF(void) pj_throw_exception_(int exception_id)
42{
43 struct pj_exception_state_t *handler;
44
Benny Prijonoa1e69682007-05-11 15:14:34 +000045 handler = (struct pj_exception_state_t*)
46 pj_thread_local_get(thread_local_id);
Benny Prijono9033e312005-11-21 02:08:39 +000047 if (handler == NULL) {
Benny Prijono9df1d092006-07-03 01:09:20 +000048 PJ_LOG(1,("except.c", "!!!FATAL: unhandled exception %s!\n",
49 pj_exception_id_name(exception_id)));
Benny Prijono9033e312005-11-21 02:08:39 +000050 pj_assert(handler != NULL);
51 /* This will crash the system! */
52 }
Benny Prijonof561b7e2009-08-14 10:41:00 +000053 pj_pop_exception_handler_(handler);
Benny Prijono9033e312005-11-21 02:08:39 +000054 pj_longjmp(handler->state, exception_id);
55}
56
Benny Prijonoaf1bb1e2006-11-21 12:39:31 +000057static void exception_cleanup(void)
58{
59 if (thread_local_id != -1) {
60 pj_thread_local_free(thread_local_id);
61 thread_local_id = -1;
62 }
Benny Prijonof762ee72006-12-01 11:14:37 +000063
64#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0
65 {
66 unsigned i;
67 for (i=0; i<PJ_MAX_EXCEPTION_ID; ++i)
68 exception_id_names[i] = NULL;
69 }
70#else
71 last_exception_id = 1;
72#endif
Benny Prijonoaf1bb1e2006-11-21 12:39:31 +000073}
74
Benny Prijono9033e312005-11-21 02:08:39 +000075PJ_DEF(void) pj_push_exception_handler_(struct pj_exception_state_t *rec)
76{
77 struct pj_exception_state_t *parent_handler = NULL;
78
79 if (thread_local_id == -1) {
80 pj_thread_local_alloc(&thread_local_id);
81 pj_assert(thread_local_id != -1);
Benny Prijonoaf1bb1e2006-11-21 12:39:31 +000082 pj_atexit(&exception_cleanup);
Benny Prijono9033e312005-11-21 02:08:39 +000083 }
Benny Prijonoa1e69682007-05-11 15:14:34 +000084 parent_handler = (struct pj_exception_state_t *)
85 pj_thread_local_get(thread_local_id);
Benny Prijono9033e312005-11-21 02:08:39 +000086 rec->prev = parent_handler;
87 pj_thread_local_set(thread_local_id, rec);
88}
89
Benny Prijonof561b7e2009-08-14 10:41:00 +000090PJ_DEF(void) pj_pop_exception_handler_(struct pj_exception_state_t *rec)
Benny Prijono9033e312005-11-21 02:08:39 +000091{
92 struct pj_exception_state_t *handler;
93
Benny Prijonoa1e69682007-05-11 15:14:34 +000094 handler = (struct pj_exception_state_t *)
95 pj_thread_local_get(thread_local_id);
Benny Prijonof561b7e2009-08-14 10:41:00 +000096 if (handler && handler==rec) {
97 pj_thread_local_set(thread_local_id, handler->prev);
98 }
Benny Prijono9033e312005-11-21 02:08:39 +000099}
Benny Prijonod0d44f52005-11-21 16:57:02 +0000100#endif
Benny Prijono9033e312005-11-21 02:08:39 +0000101
102#if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0
103PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name,
104 pj_exception_id_t *id)
105{
106 unsigned i;
107
108 pj_enter_critical_section();
109
110 /*
111 * Start from 1 (not 0)!!!
112 * Exception 0 is reserved for normal path of setjmp()!!!
113 */
114 for (i=1; i<PJ_MAX_EXCEPTION_ID; ++i) {
115 if (exception_id_names[i] == NULL) {
116 exception_id_names[i] = name;
117 *id = i;
118 pj_leave_critical_section();
119 return PJ_SUCCESS;
120 }
121 }
122
123 pj_leave_critical_section();
124 return PJ_ETOOMANY;
125}
126
127PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id )
128{
129 /*
130 * Start from 1 (not 0)!!!
131 * Exception 0 is reserved for normal path of setjmp()!!!
132 */
133 PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, PJ_EINVAL);
134
135 pj_enter_critical_section();
136 exception_id_names[id] = NULL;
137 pj_leave_critical_section();
138
139 return PJ_SUCCESS;
140
141}
142
143PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id)
144{
Benny Prijono9df1d092006-07-03 01:09:20 +0000145 static char unknown_name[32];
146
Benny Prijono9033e312005-11-21 02:08:39 +0000147 /*
148 * Start from 1 (not 0)!!!
149 * Exception 0 is reserved for normal path of setjmp()!!!
150 */
151 PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, "<Invalid ID>");
152
Benny Prijono9df1d092006-07-03 01:09:20 +0000153 if (exception_id_names[id] == NULL) {
Benny Prijonoe85bc412006-07-29 20:29:24 +0000154 pj_ansi_snprintf(unknown_name, sizeof(unknown_name),
155 "exception %d", id);
Benny Prijono9df1d092006-07-03 01:09:20 +0000156 return unknown_name;
157 }
Benny Prijono9033e312005-11-21 02:08:39 +0000158
159 return exception_id_names[id];
160}
161
162#else /* PJ_HAS_EXCEPTION_NAMES */
163PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name,
164 pj_exception_id_t *id)
165{
166 PJ_ASSERT_RETURN(last_exception_id < PJ_MAX_EXCEPTION_ID-1, PJ_ETOOMANY);
167
Benny Prijono11852992006-03-18 12:28:03 +0000168 *id = last_exception_id++;
Benny Prijono9033e312005-11-21 02:08:39 +0000169 return PJ_SUCCESS;
170}
171
172PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id )
173{
174 return PJ_SUCCESS;
175}
176
177PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id)
178{
179 return "";
180}
181
182#endif /* PJ_HAS_EXCEPTION_NAMES */
183
184
185