OLD | NEW |
1 /* This Source Code Form is subject to the terms of the Mozilla Public | 1 /* This Source Code Form is subject to the terms of the Mozilla Public |
2 * License, v. 2.0. If a copy of the MPL was not distributed with this | 2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
4 | 4 |
5 /* | 5 /* |
6 * error.c | 6 * error.c |
7 * | 7 * |
8 * This file contains the code implementing the per-thread error | 8 * This file contains the code implementing the per-thread error |
9 * stacks upon which most NSS routines report their errors. | 9 * stacks upon which most NSS routines report their errors. |
10 */ | 10 */ |
11 | 11 |
12 #ifndef BASE_H | 12 #ifndef BASE_H |
13 #include "base.h" | 13 #include "base.h" |
14 #endif /* BASE_H */ | 14 #endif /* BASE_H */ |
15 #include <limits.h> /* for UINT_MAX */ | 15 #include <limits.h> /* for UINT_MAX */ |
16 #include <string.h> /* for memmove */ | 16 #include <string.h> /* for memmove */ |
17 | 17 |
18 #define NSS_MAX_ERROR_STACK_COUNT 16 /* error codes */ | 18 #define NSS_MAX_ERROR_STACK_COUNT 16 /* error codes */ |
19 | 19 |
20 /* | 20 /* |
21 * The stack itself has a header, and a sequence of integers. | 21 * The stack itself has a header, and a sequence of integers. |
22 * The header records the amount of space (as measured in stack | 22 * The header records the amount of space (as measured in stack |
23 * slots) already allocated for the stack, and the count of the | 23 * slots) already allocated for the stack, and the count of the |
24 * number of records currently being used. | 24 * number of records currently being used. |
25 */ | 25 */ |
26 | 26 |
27 struct stack_header_str { | 27 struct stack_header_str { |
28 PRUint16 space; | 28 PRUint16 space; |
29 PRUint16 count; | 29 PRUint16 count; |
30 }; | 30 }; |
31 | 31 |
32 struct error_stack_str { | 32 struct error_stack_str { |
33 struct stack_header_str header; | 33 struct stack_header_str header; |
34 PRInt32 stack[1]; | 34 PRInt32 stack[1]; |
35 }; | 35 }; |
36 typedef struct error_stack_str error_stack; | 36 typedef struct error_stack_str error_stack; |
37 | 37 |
38 /* | 38 /* |
39 * error_stack_index | 39 * error_stack_index |
40 * | 40 * |
41 * Thread-private data must be indexed. This is that index. | 41 * Thread-private data must be indexed. This is that index. |
42 * See PR_NewThreadPrivateIndex for more information. | 42 * See PR_NewThreadPrivateIndex for more information. |
43 * | 43 * |
44 * Thread-private data indexes are in the range [0, 127]. | 44 * Thread-private data indexes are in the range [0, 127]. |
(...skipping 10 matching lines...) Expand all Loading... |
55 */ | 55 */ |
56 | 56 |
57 static PRCallOnceType error_call_once; | 57 static PRCallOnceType error_call_once; |
58 | 58 |
59 /* | 59 /* |
60 * error_once_function | 60 * error_once_function |
61 * | 61 * |
62 * This is the once-called callback. | 62 * This is the once-called callback. |
63 */ | 63 */ |
64 static PRStatus | 64 static PRStatus |
65 error_once_function ( void) | 65 error_once_function(void) |
66 { | 66 { |
67 return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free); | 67 return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free); |
68 } | 68 } |
69 | 69 |
70 /* | 70 /* |
71 * error_get_my_stack | 71 * error_get_my_stack |
72 * | 72 * |
73 * This routine returns the calling thread's error stack, creating | 73 * This routine returns the calling thread's error stack, creating |
74 * it if necessary. It may return NULL upon error, which implicitly | 74 * it if necessary. It may return NULL upon error, which implicitly |
75 * means that it ran out of memory. | 75 * means that it ran out of memory. |
76 */ | 76 */ |
77 | 77 |
78 static error_stack * | 78 static error_stack * |
79 error_get_my_stack ( void) | 79 error_get_my_stack(void) |
80 { | 80 { |
81 PRStatus st; | 81 PRStatus st; |
82 error_stack *rv; | 82 error_stack *rv; |
83 PRUintn new_size; | 83 PRUintn new_size; |
84 PRUint32 new_bytes; | 84 PRUint32 new_bytes; |
85 error_stack *new_stack; | 85 error_stack *new_stack; |
86 | 86 |
87 if( INVALID_TPD_INDEX == error_stack_index ) { | 87 if (INVALID_TPD_INDEX == error_stack_index) { |
88 st = PR_CallOnce(&error_call_once, error_once_function); | 88 st = PR_CallOnce(&error_call_once, error_once_function); |
89 if( PR_SUCCESS != st ) { | 89 if (PR_SUCCESS != st) { |
90 return (error_stack *)NULL; | 90 return (error_stack *)NULL; |
| 91 } |
91 } | 92 } |
92 } | |
93 | 93 |
94 rv = (error_stack *)PR_GetThreadPrivate(error_stack_index); | 94 rv = (error_stack *)PR_GetThreadPrivate(error_stack_index); |
95 if( (error_stack *)NULL == rv ) { | 95 if ((error_stack *)NULL == rv) { |
96 /* Doesn't exist; create one */ | 96 /* Doesn't exist; create one */ |
97 new_size = 16; | 97 new_size = 16; |
98 } else if( rv->header.count == rv->header.space && | 98 } else if (rv->header.count == rv->header.space && |
99 rv->header.count < NSS_MAX_ERROR_STACK_COUNT ) { | 99 rv->header.count < NSS_MAX_ERROR_STACK_COUNT) { |
100 /* Too small, expand it */ | 100 /* Too small, expand it */ |
101 new_size = PR_MIN( rv->header.space * 2, NSS_MAX_ERROR_STACK_COUNT); | 101 new_size = PR_MIN(rv->header.space * 2, NSS_MAX_ERROR_STACK_COUNT); |
102 } else { | 102 } else { |
103 /* Okay, return it */ | 103 /* Okay, return it */ |
104 return rv; | 104 return rv; |
105 } | 105 } |
106 | 106 |
107 new_bytes = (new_size * sizeof(PRInt32)) + sizeof(error_stack); | 107 new_bytes = (new_size * sizeof(PRInt32)) + sizeof(error_stack); |
108 /* Use NSPR's calloc/realloc, not NSS's, to avoid loops! */ | 108 /* Use NSPR's calloc/realloc, not NSS's, to avoid loops! */ |
109 new_stack = PR_Calloc(1, new_bytes); | 109 new_stack = PR_Calloc(1, new_bytes); |
110 | 110 |
111 if( (error_stack *)NULL != new_stack ) { | 111 if ((error_stack *)NULL != new_stack) { |
112 if( (error_stack *)NULL != rv ) { | 112 if ((error_stack *)NULL != rv) { |
113 » (void)nsslibc_memcpy(new_stack,rv,rv->header.space); | 113 (void)nsslibc_memcpy(new_stack, rv, rv->header.space); |
| 114 } |
| 115 new_stack->header.space = new_size; |
114 } | 116 } |
115 new_stack->header.space = new_size; | |
116 } | |
117 | 117 |
118 /* Set the value, whether or not the allocation worked */ | 118 /* Set the value, whether or not the allocation worked */ |
119 PR_SetThreadPrivate(error_stack_index, new_stack); | 119 PR_SetThreadPrivate(error_stack_index, new_stack); |
120 return new_stack; | 120 return new_stack; |
121 } | 121 } |
122 | 122 |
123 /* | 123 /* |
124 * The error stack | 124 * The error stack |
125 * | 125 * |
126 * The public methods relating to the error stack are: | 126 * The public methods relating to the error stack are: |
127 * | 127 * |
128 * NSS_GetError | 128 * NSS_GetError |
129 * NSS_GetErrorStack | 129 * NSS_GetErrorStack |
130 * | 130 * |
(...skipping 13 matching lines...) Expand all Loading... |
144 * | 144 * |
145 * This routine cannot fail. However, it may return zero, which | 145 * This routine cannot fail. However, it may return zero, which |
146 * indicates that the previous NSS library call did not set an error. | 146 * indicates that the previous NSS library call did not set an error. |
147 * | 147 * |
148 * Return value: | 148 * Return value: |
149 * 0 if no error has been set | 149 * 0 if no error has been set |
150 * A nonzero error number | 150 * A nonzero error number |
151 */ | 151 */ |
152 | 152 |
153 NSS_IMPLEMENT PRInt32 | 153 NSS_IMPLEMENT PRInt32 |
154 NSS_GetError ( void) | 154 NSS_GetError(void) |
155 { | 155 { |
156 error_stack *es = error_get_my_stack(); | 156 error_stack *es = error_get_my_stack(); |
157 | 157 |
158 if( (error_stack *)NULL == es ) { | 158 if ((error_stack *)NULL == es) { |
159 return NSS_ERROR_NO_MEMORY; /* Good guess! */ | 159 return NSS_ERROR_NO_MEMORY; /* Good guess! */ |
160 } | 160 } |
161 | 161 |
162 if( 0 == es->header.count ) { | 162 if (0 == es->header.count) { |
163 return 0; | 163 return 0; |
164 } | 164 } |
165 | 165 |
166 return es->stack[ es->header.count-1 ]; | 166 return es->stack[es->header.count - 1]; |
167 } | 167 } |
168 | 168 |
169 /* | 169 /* |
170 * NSS_GetErrorStack | 170 * NSS_GetErrorStack |
171 * | 171 * |
172 * This routine returns a pointer to an array of integers, containing | 172 * This routine returns a pointer to an array of integers, containing |
173 * the entire sequence or "stack" of errors set by the most recent NSS | 173 * the entire sequence or "stack" of errors set by the most recent NSS |
174 * library routine called by the same thread calling this routine. | 174 * library routine called by the same thread calling this routine. |
175 * NOTE: the caller DOES NOT OWN the memory pointed to by the return | 175 * NOTE: the caller DOES NOT OWN the memory pointed to by the return |
176 * value. The pointer will remain valid until the calling thread | 176 * value. The pointer will remain valid until the calling thread |
177 * calls another NSS routine. The lowest-level (most specific) error | 177 * calls another NSS routine. The lowest-level (most specific) error |
178 * is first in the array, and the highest-level is last. The array is | 178 * is first in the array, and the highest-level is last. The array is |
179 * zero-terminated. This routine may return NULL upon error; this | 179 * zero-terminated. This routine may return NULL upon error; this |
180 * indicates a low-memory situation. | 180 * indicates a low-memory situation. |
181 * | 181 * |
182 * Return value: | 182 * Return value: |
183 * NULL upon error, which is an implied NSS_ERROR_NO_MEMORY | 183 * NULL upon error, which is an implied NSS_ERROR_NO_MEMORY |
184 * A NON-caller-owned pointer to an array of integers | 184 * A NON-caller-owned pointer to an array of integers |
185 */ | 185 */ |
186 | 186 |
187 NSS_IMPLEMENT PRInt32 * | 187 NSS_IMPLEMENT PRInt32 * |
188 NSS_GetErrorStack ( void) | 188 NSS_GetErrorStack(void) |
189 { | 189 { |
190 error_stack *es = error_get_my_stack(); | 190 error_stack *es = error_get_my_stack(); |
191 | 191 |
192 if( (error_stack *)NULL == es ) { | 192 if ((error_stack *)NULL == es) { |
193 return (PRInt32 *)NULL; | 193 return (PRInt32 *)NULL; |
194 } | 194 } |
195 | 195 |
196 /* Make sure it's terminated */ | 196 /* Make sure it's terminated */ |
197 es->stack[ es->header.count ] = 0; | 197 es->stack[es->header.count] = 0; |
198 | 198 |
199 return es->stack; | 199 return es->stack; |
200 } | 200 } |
201 | 201 |
202 /* | 202 /* |
203 * nss_SetError | 203 * nss_SetError |
204 * | 204 * |
205 * This routine places a new error code on the top of the calling | 205 * This routine places a new error code on the top of the calling |
206 * thread's error stack. Calling this routine wiht an error code | 206 * thread's error stack. Calling this routine wiht an error code |
207 * of zero will clear the error stack. | 207 * of zero will clear the error stack. |
208 */ | 208 */ |
209 | 209 |
210 NSS_IMPLEMENT void | 210 NSS_IMPLEMENT void |
211 nss_SetError ( PRUint32 error) | 211 nss_SetError(PRUint32 error) |
212 { | 212 { |
213 error_stack *es; | 213 error_stack *es; |
214 | 214 |
215 if( 0 == error ) { | 215 if (0 == error) { |
216 nss_ClearErrorStack(); | 216 nss_ClearErrorStack(); |
| 217 return; |
| 218 } |
| 219 |
| 220 es = error_get_my_stack(); |
| 221 if ((error_stack *)NULL == es) { |
| 222 /* Oh, well. */ |
| 223 return; |
| 224 } |
| 225 |
| 226 if (es->header.count < es->header.space) { |
| 227 es->stack[es->header.count++] = error; |
| 228 } else { |
| 229 memmove(es->stack, es->stack + 1, |
| 230 (es->header.space - 1) * (sizeof es->stack[0])); |
| 231 es->stack[es->header.space - 1] = error; |
| 232 } |
217 return; | 233 return; |
218 } | |
219 | |
220 es = error_get_my_stack(); | |
221 if( (error_stack *)NULL == es ) { | |
222 /* Oh, well. */ | |
223 return; | |
224 } | |
225 | |
226 if (es->header.count < es->header.space) { | |
227 es->stack[ es->header.count++ ] = error; | |
228 } else { | |
229 memmove(es->stack, es->stack + 1, | |
230 (es->header.space - 1) * (sizeof es->stack[0])); | |
231 es->stack[ es->header.space - 1 ] = error; | |
232 } | |
233 return; | |
234 } | 234 } |
235 | 235 |
236 /* | 236 /* |
237 * nss_ClearErrorStack | 237 * nss_ClearErrorStack |
238 * | 238 * |
239 * This routine clears the calling thread's error stack. | 239 * This routine clears the calling thread's error stack. |
240 */ | 240 */ |
241 | 241 |
242 NSS_IMPLEMENT void | 242 NSS_IMPLEMENT void |
243 nss_ClearErrorStack ( void) | 243 nss_ClearErrorStack(void) |
244 { | 244 { |
245 error_stack *es = error_get_my_stack(); | 245 error_stack *es = error_get_my_stack(); |
246 if( (error_stack *)NULL == es ) { | 246 if ((error_stack *)NULL == es) { |
247 /* Oh, well. */ | 247 /* Oh, well. */ |
| 248 return; |
| 249 } |
| 250 |
| 251 es->header.count = 0; |
| 252 es->stack[0] = 0; |
248 return; | 253 return; |
249 } | |
250 | |
251 es->header.count = 0; | |
252 es->stack[0] = 0; | |
253 return; | |
254 } | 254 } |
255 | 255 |
256 /* | 256 /* |
257 * nss_DestroyErrorStack | 257 * nss_DestroyErrorStack |
258 * | 258 * |
259 * This routine frees the calling thread's error stack. | 259 * This routine frees the calling thread's error stack. |
260 */ | 260 */ |
261 | 261 |
262 NSS_IMPLEMENT void | 262 NSS_IMPLEMENT void |
263 nss_DestroyErrorStack ( void) | 263 nss_DestroyErrorStack(void) |
264 { | 264 { |
265 if( INVALID_TPD_INDEX != error_stack_index ) { | 265 if (INVALID_TPD_INDEX != error_stack_index) { |
266 PR_SetThreadPrivate(error_stack_index, NULL); | 266 PR_SetThreadPrivate(error_stack_index, NULL); |
267 } | 267 } |
268 return; | 268 return; |
269 } | 269 } |
OLD | NEW |