Back to index

lightning-sunbird  0.9+nobinonly
error.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Netscape security libraries.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Netscape Communications Corporation.
00018  * Portions created by the Initial Developer are Copyright (C) 1994-2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 #ifdef DEBUG
00038 static const char CVS_ID[] = "@(#) $RCSfile: error.c,v $ $Revision: 1.6 $ $Date: 2005/01/20 02:25:45 $";
00039 #endif /* DEBUG */
00040 
00041 /*
00042  * error.c
00043  *
00044  * This file contains the code implementing the per-thread error 
00045  * stacks upon which most NSS routines report their errors.
00046  */
00047 
00048 #ifndef BASE_H
00049 #include "base.h"
00050 #endif /* BASE_H */
00051 #include <string.h> /* for memmove */
00052 
00053 #define NSS_MAX_ERROR_STACK_COUNT 16 /* error codes */
00054 
00055 /*
00056  * The stack itself has a header, and a sequence of integers.
00057  * The header records the amount of space (as measured in stack
00058  * slots) already allocated for the stack, and the count of the
00059  * number of records currently being used.
00060  */
00061 
00062 struct stack_header_str {
00063   PRUint16 space;
00064   PRUint16 count;
00065 };
00066 
00067 struct error_stack_str {
00068   struct stack_header_str header;
00069   PRInt32 stack[1];
00070 };
00071 typedef struct error_stack_str error_stack;
00072 
00073 /*
00074  * error_stack_index
00075  *
00076  * Thread-private data must be indexed.  This is that index.
00077  * See PR_NewThreadPrivateIndex for more information.
00078  */
00079 
00080 static PRUintn error_stack_index;
00081 
00082 /*
00083  * call_once
00084  *
00085  * The thread-private index must be obtained (once!) at runtime.
00086  * This block is used for that one-time call.
00087  */
00088 
00089 static PRCallOnceType error_call_once;
00090 
00091 /*
00092  * error_once_function
00093  *
00094  * This is the once-called callback.
00095  */
00096 static PRStatus
00097 error_once_function ( void)
00098 {
00099   return nss_NewThreadPrivateIndex(&error_stack_index,PR_Free);
00100   /* return PR_NewThreadPrivateIndex(&error_stack_index, PR_Free); */
00101 }
00102 
00103 /*
00104  * error_get_my_stack
00105  *
00106  * This routine returns the calling thread's error stack, creating
00107  * it if necessary.  It may return NULL upon error, which implicitly
00108  * means that it ran out of memory.
00109  */
00110 
00111 static error_stack *
00112 error_get_my_stack ( void)
00113 {
00114   PRStatus st;
00115   error_stack *rv;
00116   PRUintn new_size;
00117   PRUint32 new_bytes;
00118   error_stack *new_stack;
00119 
00120   if( 0 == error_stack_index ) {
00121     st = PR_CallOnce(&error_call_once, error_once_function);
00122     if( PR_SUCCESS != st ) {
00123       return (error_stack *)NULL;
00124     }
00125   }
00126 
00127   rv = (error_stack *)nss_GetThreadPrivate(error_stack_index);
00128   if( (error_stack *)NULL == rv ) {
00129     /* Doesn't exist; create one */
00130     new_size = 16;
00131   } else if( rv->header.count == rv->header.space  &&
00132              rv->header.count  < NSS_MAX_ERROR_STACK_COUNT ) {
00133     /* Too small, expand it */
00134     new_size = PR_MIN( rv->header.space * 2, NSS_MAX_ERROR_STACK_COUNT);
00135   } else {
00136     /* Okay, return it */
00137     return rv;
00138   }
00139 
00140   new_bytes = (new_size * sizeof(PRInt32)) + sizeof(error_stack);
00141   /* Use NSPR's calloc/realloc, not NSS's, to avoid loops! */
00142   new_stack = PR_Calloc(1, new_bytes);
00143   
00144   if( (error_stack *)NULL != new_stack ) {
00145     if( (error_stack *)NULL != rv ) {
00146        (void)nsslibc_memcpy(new_stack,rv,rv->header.space);
00147     }
00148     new_stack->header.space = new_size;
00149   }
00150 
00151   /* Set the value, whether or not the allocation worked */
00152   nss_SetThreadPrivate(error_stack_index, new_stack);
00153   return new_stack;
00154 }
00155 
00156 /*
00157  * The error stack
00158  *
00159  * The public methods relating to the error stack are:
00160  *
00161  *  NSS_GetError
00162  *  NSS_GetErrorStack
00163  *
00164  * The nonpublic methods relating to the error stack are:
00165  *
00166  *  nss_SetError
00167  *  nss_ClearErrorStack
00168  *
00169  */
00170 
00171 /*
00172  * NSS_GetError
00173  *
00174  * This routine returns the highest-level (most general) error set
00175  * by the most recent NSS library routine called by the same thread
00176  * calling this routine.
00177  *
00178  * This routine cannot fail.  However, it may return zero, which
00179  * indicates that the previous NSS library call did not set an error.
00180  *
00181  * Return value:
00182  *  0 if no error has been set
00183  *  A nonzero error number
00184  */
00185 
00186 NSS_IMPLEMENT PRInt32
00187 NSS_GetError ( void)
00188 {
00189   error_stack *es = error_get_my_stack();
00190 
00191   if( (error_stack *)NULL == es ) {
00192     return NSS_ERROR_NO_MEMORY; /* Good guess! */
00193   }
00194 
00195   if( 0 == es->header.count ) {
00196     return 0;
00197   }
00198 
00199   return es->stack[ es->header.count-1 ];
00200 }
00201 
00202 /*
00203  * NSS_GetErrorStack
00204  *
00205  * This routine returns a pointer to an array of integers, containing
00206  * the entire sequence or "stack" of errors set by the most recent NSS
00207  * library routine called by the same thread calling this routine.
00208  * NOTE: the caller DOES NOT OWN the memory pointed to by the return
00209  * value.  The pointer will remain valid until the calling thread
00210  * calls another NSS routine.  The lowest-level (most specific) error 
00211  * is first in the array, and the highest-level is last.  The array is
00212  * zero-terminated.  This routine may return NULL upon error; this
00213  * indicates a low-memory situation.
00214  *
00215  * Return value:
00216  *  NULL upon error, which is an implied NSS_ERROR_NO_MEMORY
00217  *  A NON-caller-owned pointer to an array of integers
00218  */
00219 
00220 NSS_IMPLEMENT PRInt32 *
00221 NSS_GetErrorStack ( void)
00222 {
00223   error_stack *es = error_get_my_stack();
00224 
00225   if( (error_stack *)NULL == es ) {
00226     return (PRInt32 *)NULL;
00227   }
00228 
00229   /* Make sure it's terminated */
00230   es->stack[ es->header.count ] = 0;
00231 
00232   return es->stack;
00233 }
00234 
00235 /*
00236  * nss_SetError
00237  *
00238  * This routine places a new error code on the top of the calling 
00239  * thread's error stack.  Calling this routine wiht an error code
00240  * of zero will clear the error stack.
00241  */
00242 
00243 NSS_IMPLEMENT void
00244 nss_SetError ( PRUint32 error)
00245 {
00246   error_stack *es;
00247 
00248   if( 0 == error ) {
00249     nss_ClearErrorStack();
00250     return;
00251   }
00252 
00253   es = error_get_my_stack();
00254   if( (error_stack *)NULL == es ) {
00255     /* Oh, well. */
00256     return;
00257   }
00258 
00259   if (es->header.count < es->header.space) {
00260     es->stack[ es->header.count++ ] = error;
00261   } else {
00262     memmove(es->stack, es->stack + 1, 
00263               (es->header.space - 1) * (sizeof es->stack[0]));
00264     es->stack[ es->header.space - 1 ] = error;
00265   }
00266   return;
00267 }
00268 
00269 /*
00270  * nss_ClearErrorStack
00271  *
00272  * This routine clears the calling thread's error stack.
00273  */
00274 
00275 NSS_IMPLEMENT void
00276 nss_ClearErrorStack ( void)
00277 {
00278   error_stack *es = error_get_my_stack();
00279   if( (error_stack *)NULL == es ) {
00280     /* Oh, well. */
00281     return;
00282   }
00283 
00284   es->header.count = 0;
00285   es->stack[0] = 0;
00286   return;
00287 }