| 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 |