/* * Copyright (c) 2003 Apple Computer, Inc. All Rights Reserved. * * The contents of this file constitute Original Code as defined in and are * subject to the Apple Public Source License Version 1.2 (the 'License'). * You may not use this file except in compliance with the License. Please * obtain a copy of the License at http://www.apple.com/publicsource and * read it before using this file. * * This Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. */ /* * nsprPortX.c - minimal platform dependent NSPR functions to enable * use of DER libraries */ #ifndef _NSPR_PORT_X_H_ #define _NSPR_PORT_X_H_ #include "prmem.h" #include "prlock.h" #include "prerror.h" #include "prinit.h" #include "prbit.h" #include #include #include #include #include #include /* errSecErrnoBase */ #pragma mark *** Memory *** NSPR_API(void *) PR_Malloc(PRUint32 size) { return malloc(size ? size : 1); } NSPR_API(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize) { return calloc(nelem, elsize); } NSPR_API(void *) PR_Realloc(void *ptr, PRUint32 size) { return realloc(ptr, size); } NSPR_API(void) PR_Free(void *ptr) { return free(ptr); } #pragma mark *** locks *** NSPR_API(PRLock*) PR_NewLock(void) { pthread_mutex_t *pm = PR_Malloc(sizeof(pthread_mutex_t)); if(pm == NULL) { return NULL; } if(pthread_mutex_init(pm, NULL)) { PR_Free(pm); return NULL; } return (PRLock*)pm; } NSPR_API(void) PR_DestroyLock(PRLock *lock) { if(lock == NULL) { return; } pthread_mutex_destroy((pthread_mutex_t *)lock); PR_Free(lock); } NSPR_API(void) PR_Lock(PRLock *lock) { if(lock == NULL) { return; } pthread_mutex_lock((pthread_mutex_t *)lock); } NSPR_API(PRStatus) PR_Unlock(PRLock *lock) { if(lock == NULL) { return PR_FAILURE; } pthread_mutex_unlock((pthread_mutex_t *)lock); return PR_SUCCESS; } #pragma mark *** get/set error *** /* * key for pthread_{set,get}specific and a lock to ensure it gets * created once */ static pthread_key_t PR_threadKey; static int PR_threadKeyInitFlag; // we have a PR_threadKey static int PR_threadKeyErrorFlag; // unable to create PR_threadKey static pthread_mutex_t PR_threadKeyLock = PTHREAD_MUTEX_INITIALIZER; /* * The thing that gets stored on a per-thread basis. A pointer to * this is associated with key PR_threadKey. Mallocd in * PR_getThreadErrInfo(); freed directly by free() as * PR_threadKey's destructor. */ typedef struct { PRInt32 osError; PRErrorCode prError; } PR_threadErrInfo; /* * One-time init of PR_threadKey, returns nonzero on error. * Does not attempt to init PR_threadKey if doCreate is false and * a previous call to this routine resulted in error (i.e., this * is the GetXError() following a failed SetError()). */ static PRInt32 PR_initThreadKey( int doCreate) { PRInt32 prtn = 0; if(PR_threadKeyInitFlag) { /* thread safe since we never clear this flag; we're ready to go */ return noErr; } pthread_mutex_lock(&PR_threadKeyLock); if(PR_threadKeyErrorFlag && !doCreate) { /* no error to get because the last SetXError failed */ prtn = ioErr; } else if(!PR_threadKeyInitFlag) { prtn = pthread_key_create(&PR_threadKey, free); if(prtn) { /* out of pthread_key_t's */ PR_threadKeyErrorFlag = 1; /* convert to OSStatus */ prtn += errSecErrnoBase; } else { PR_threadKeyErrorFlag = 0; // in case of retry */ PR_threadKeyInitFlag = 1; // success } } pthread_mutex_unlock(&PR_threadKeyLock); return prtn; } /* * Get current thread's PR_threadErrInfo. Create one if doCreate is * true and one does not exist. * * -- A nonzero *threadKeyError on return indicates that we can * not create a pthread_key_t; in this case we return NULL. * -- Note that NULL return with zero threadKeyError and zero * doCreate indicates "no per-thread error set yet", which is * not an error. */ static PR_threadErrInfo *PR_getThreadErrInfo( int doCreate, PRInt32 *threadKeyError) // RETURNED, an OSStatus { *threadKeyError = PR_initThreadKey(doCreate); if(*threadKeyError) { return NULL; } PR_threadErrInfo *errInfo = pthread_getspecific(PR_threadKey); if((errInfo == NULL) && doCreate) { errInfo = (PR_threadErrInfo *)malloc(sizeof(*errInfo)); if(errInfo == NULL) { /* * malloc failure, retriable failure of this routine (not * a PR_threadKeyErrorFlag style error). * Note that this is *not* detected in a subsequent * GetXError() call, but it will allow for somewhat * graceful recovery in case some memory gets freed * up. */ *threadKeyError = memFullErr; } else { memset(errInfo, 0, sizeof(*errInfo)); pthread_setspecific(PR_threadKey, errInfo); } } return errInfo; } PR_IMPLEMENT(PRErrorCode) PR_GetError(void) { PRInt32 prtn; PR_threadErrInfo *errInfo = PR_getThreadErrInfo(0, &prtn); if(errInfo == NULL) { /* no error set or per-thread logic uninitialized */ if(prtn) { return PR_INSUFFICIENT_RESOURCES_ERROR; } else { return 0; } } else { return errInfo->prError; } } PR_IMPLEMENT(PRInt32) PR_GetOSError(void) { PRInt32 prtn; PR_threadErrInfo *errInfo = PR_getThreadErrInfo(0, &prtn); if(errInfo == NULL) { /* no error set or per-thread logic uninitialized */ return prtn; } else { return errInfo->osError; } } PR_IMPLEMENT(void) PR_SetError(PRErrorCode code, PRInt32 osErr) { PRInt32 prtn; PR_threadErrInfo *errInfo = PR_getThreadErrInfo(1, &prtn); if(errInfo != NULL) { errInfo->osError = osErr; errInfo->prError = code; } /* else per-thread logic uninitialized */ } #pragma mark *** misc. *** /* ** Compute the log of the least power of 2 greater than or equal to n */ NSPR_API(PRIntn) PR_CeilingLog2(PRUint32 i) { PRIntn r; PR_CEILING_LOG2(r,i); return r; } #endif /* _NSPR_PORT_X_H_ */