/src/pjsip/pjlib/src/pj/except.c
Line | Count | Source (jump to first uncovered line) |
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 | | #include <pj/except.h> |
20 | | #include <pj/os.h> |
21 | | #include <pj/assert.h> |
22 | | #include <pj/log.h> |
23 | | #include <pj/errno.h> |
24 | | #include <pj/string.h> |
25 | | |
26 | | static long thread_local_id = -1; |
27 | | |
28 | | #if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0 |
29 | | static const char *exception_id_names[PJ_MAX_EXCEPTION_ID]; |
30 | | #else |
31 | | /* |
32 | | * Start from 1 (not 0)!!! |
33 | | * Exception 0 is reserved for normal path of setjmp()!!! |
34 | | */ |
35 | | static int last_exception_id = 1; |
36 | | #endif /* PJ_HAS_EXCEPTION_NAMES */ |
37 | | |
38 | | |
39 | | #if !defined(PJ_EXCEPTION_USE_WIN32_SEH) || PJ_EXCEPTION_USE_WIN32_SEH==0 |
40 | | PJ_DEF(void) pj_throw_exception_(int exception_id) |
41 | 0 | { |
42 | 0 | struct pj_exception_state_t *handler; |
43 | |
|
44 | 0 | handler = (struct pj_exception_state_t*) |
45 | 0 | pj_thread_local_get(thread_local_id); |
46 | 0 | if (handler == NULL) { |
47 | 0 | PJ_LOG(1,("except.c", "!!!FATAL: unhandled exception %s!\n", |
48 | 0 | pj_exception_id_name(exception_id))); |
49 | 0 | pj_assert(handler != NULL); |
50 | | /* This will crash the system! */ |
51 | 0 | } |
52 | 0 | pj_pop_exception_handler_(handler); |
53 | 0 | pj_longjmp(handler->state, exception_id); |
54 | 0 | } |
55 | | |
56 | | static void exception_cleanup(void) |
57 | 0 | { |
58 | 0 | if (thread_local_id != -1) { |
59 | 0 | pj_thread_local_free(thread_local_id); |
60 | 0 | thread_local_id = -1; |
61 | 0 | } |
62 | |
|
63 | 0 | #if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0 |
64 | 0 | { |
65 | 0 | unsigned i; |
66 | 0 | for (i=0; i<PJ_MAX_EXCEPTION_ID; ++i) |
67 | 0 | exception_id_names[i] = NULL; |
68 | 0 | } |
69 | | #else |
70 | | last_exception_id = 1; |
71 | | #endif |
72 | 0 | } |
73 | | |
74 | | PJ_DEF(void) pj_push_exception_handler_(struct pj_exception_state_t *rec) |
75 | 0 | { |
76 | 0 | struct pj_exception_state_t *parent_handler = NULL; |
77 | |
|
78 | 0 | if (thread_local_id == -1) { |
79 | 0 | pj_thread_local_alloc(&thread_local_id); |
80 | 0 | pj_assert(thread_local_id != -1); |
81 | 0 | pj_atexit(&exception_cleanup); |
82 | 0 | } |
83 | 0 | parent_handler = (struct pj_exception_state_t *) |
84 | 0 | pj_thread_local_get(thread_local_id); |
85 | 0 | rec->prev = parent_handler; |
86 | 0 | pj_thread_local_set(thread_local_id, rec); |
87 | 0 | } |
88 | | |
89 | | PJ_DEF(void) pj_pop_exception_handler_(struct pj_exception_state_t *rec) |
90 | 0 | { |
91 | 0 | struct pj_exception_state_t *handler; |
92 | |
|
93 | 0 | handler = (struct pj_exception_state_t *) |
94 | 0 | pj_thread_local_get(thread_local_id); |
95 | 0 | if (handler && handler==rec) { |
96 | 0 | pj_thread_local_set(thread_local_id, handler->prev); |
97 | 0 | } |
98 | 0 | } |
99 | | #endif |
100 | | |
101 | | #if defined(PJ_HAS_EXCEPTION_NAMES) && PJ_HAS_EXCEPTION_NAMES != 0 |
102 | | PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name, |
103 | | pj_exception_id_t *id) |
104 | 1 | { |
105 | 1 | unsigned i; |
106 | | |
107 | 1 | pj_enter_critical_section(); |
108 | | |
109 | | /* |
110 | | * Start from 1 (not 0)!!! |
111 | | * Exception 0 is reserved for normal path of setjmp()!!! |
112 | | */ |
113 | 1 | for (i=1; i<PJ_MAX_EXCEPTION_ID; ++i) { |
114 | 1 | if (exception_id_names[i] == NULL) { |
115 | 1 | exception_id_names[i] = name; |
116 | 1 | *id = i; |
117 | 1 | pj_leave_critical_section(); |
118 | 1 | return PJ_SUCCESS; |
119 | 1 | } |
120 | 1 | } |
121 | | |
122 | 0 | pj_leave_critical_section(); |
123 | 0 | return PJ_ETOOMANY; |
124 | 1 | } |
125 | | |
126 | | PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id ) |
127 | 0 | { |
128 | | /* |
129 | | * Start from 1 (not 0)!!! |
130 | | * Exception 0 is reserved for normal path of setjmp()!!! |
131 | | */ |
132 | 0 | PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, PJ_EINVAL); |
133 | | |
134 | 0 | pj_enter_critical_section(); |
135 | 0 | exception_id_names[id] = NULL; |
136 | 0 | pj_leave_critical_section(); |
137 | |
|
138 | 0 | return PJ_SUCCESS; |
139 | |
|
140 | 0 | } |
141 | | |
142 | | PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id) |
143 | 0 | { |
144 | 0 | static char unknown_name[32]; |
145 | | |
146 | | /* |
147 | | * Start from 1 (not 0)!!! |
148 | | * Exception 0 is reserved for normal path of setjmp()!!! |
149 | | */ |
150 | 0 | PJ_ASSERT_RETURN(id>0 && id<PJ_MAX_EXCEPTION_ID, "<Invalid ID>"); |
151 | | |
152 | 0 | if (exception_id_names[id] == NULL) { |
153 | 0 | pj_ansi_snprintf(unknown_name, sizeof(unknown_name), |
154 | 0 | "exception %d", id); |
155 | 0 | return unknown_name; |
156 | 0 | } |
157 | | |
158 | 0 | return exception_id_names[id]; |
159 | 0 | } |
160 | | |
161 | | #else /* PJ_HAS_EXCEPTION_NAMES */ |
162 | | PJ_DEF(pj_status_t) pj_exception_id_alloc( const char *name, |
163 | | pj_exception_id_t *id) |
164 | | { |
165 | | PJ_ASSERT_RETURN(last_exception_id < PJ_MAX_EXCEPTION_ID-1, PJ_ETOOMANY); |
166 | | |
167 | | *id = last_exception_id++; |
168 | | return PJ_SUCCESS; |
169 | | } |
170 | | |
171 | | PJ_DEF(pj_status_t) pj_exception_id_free( pj_exception_id_t id ) |
172 | | { |
173 | | return PJ_SUCCESS; |
174 | | } |
175 | | |
176 | | PJ_DEF(const char*) pj_exception_id_name(pj_exception_id_t id) |
177 | | { |
178 | | return ""; |
179 | | } |
180 | | |
181 | | #endif /* PJ_HAS_EXCEPTION_NAMES */ |
182 | | |
183 | | |
184 | | |