1/* 2 * Copyright (c) 2003-2006,2008,2010 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 * 23 * nsprPortX.c - minimal platform dependent NSPR functions to enable 24 * use of DER libraries 25 */ 26 27#ifndef _NSPR_PORT_X_H_ 28#define _NSPR_PORT_X_H_ 29 30#include "prmem.h" 31#include "prlock.h" 32#include "prerror.h" 33#include "prinit.h" 34#include "prbit.h" 35 36#include <stdlib.h> 37#include <pthread.h> 38#include <string.h> 39 40// MARK: *** Memory *** 41 42NSPR_API(void *) PR_Malloc(PRSize size) 43{ 44 return malloc(size ? size : 1); 45} 46NSPR_API(void *) PR_Calloc(PRSize nelem, PRSize elsize) 47{ 48 return calloc(nelem, elsize); 49} 50NSPR_API(void *) PR_Realloc(void *ptr, PRSize size) 51{ 52 return realloc(ptr, size); 53} 54NSPR_API(void) PR_Free(void *ptr) 55{ 56 return free(ptr); 57} 58 59// MARK: *** locks *** 60 61NSPR_API(PRLock*) PR_NewLock(void) 62{ 63 pthread_mutex_t *pm = PR_Malloc(sizeof(pthread_mutex_t)); 64 if(pm == NULL) { 65 return NULL; 66 } 67 if(pthread_mutex_init(pm, NULL)) { 68 PR_Free(pm); 69 return NULL; 70 } 71 return (PRLock*)pm; 72} 73 74NSPR_API(void) PR_DestroyLock(PRLock *lock) 75{ 76 if(lock == NULL) { 77 return; 78 } 79 pthread_mutex_destroy((pthread_mutex_t *)lock); 80 PR_Free(lock); 81} 82 83NSPR_API(void) PR_Lock(PRLock *lock) 84{ 85 if(lock == NULL) { 86 return; 87 } 88 pthread_mutex_lock((pthread_mutex_t *)lock); 89} 90 91NSPR_API(PRStatus) PR_Unlock(PRLock *lock) 92{ 93 if(lock == NULL) { 94 return PR_FAILURE; 95 } 96 pthread_mutex_unlock((pthread_mutex_t *)lock); 97 return PR_SUCCESS; 98} 99 100// MARK: *** get/set error *** 101 102/* 103 * key for pthread_{set,get}specific and a lock to ensure it gets 104 * created once 105 */ 106static pthread_key_t PR_threadKey; 107static int PR_threadKeyInitFlag; // we have a PR_threadKey 108static int PR_threadKeyErrorFlag; // unable to create PR_threadKey 109static pthread_mutex_t PR_threadKeyLock = PTHREAD_MUTEX_INITIALIZER; 110 111/* 112 * The thing that gets stored on a per-thread basis. A pointer to 113 * this is associated with key PR_threadKey. Mallocd in 114 * PR_getThreadErrInfo(); freed directly by free() as 115 * PR_threadKey's destructor. 116 */ 117typedef struct { 118 PRInt32 osError; 119 PRErrorCode prError; 120} PR_threadErrInfo; 121 122/* 123 * One-time init of PR_threadKey, returns nonzero on error. 124 * Does not attempt to init PR_threadKey if doCreate is false and 125 * a previous call to this routine resulted in error (i.e., this 126 * is the GetXError() following a failed SetError()). 127 */ 128static PRInt32 PR_initThreadKey( 129 int doCreate) 130{ 131 PRInt32 prtn = 0; 132 if(PR_threadKeyInitFlag) { 133 /* thread safe since we never clear this flag; we're ready to go */ 134 return 0; 135 } 136 pthread_mutex_lock(&PR_threadKeyLock); 137 if(PR_threadKeyErrorFlag && !doCreate) { 138 /* no error to get because the last SetXError failed */ 139 prtn = PR_IO_ERROR; 140 } 141 else if(!PR_threadKeyInitFlag) { 142 prtn = pthread_key_create(&PR_threadKey, free); 143 if(prtn) { 144 /* out of pthread_key_t's */ 145 PR_threadKeyErrorFlag = 1; 146 } 147 else { 148 PR_threadKeyErrorFlag = 0; // in case of retry */ 149 PR_threadKeyInitFlag = 1; // success 150 } 151 } 152 pthread_mutex_unlock(&PR_threadKeyLock); 153 return prtn; 154} 155 156/* 157 * Get current thread's PR_threadErrInfo. Create one if doCreate is 158 * true and one does not exist. 159 * 160 * -- A nonzero *threadKeyError on return indicates that we can 161 * not create a pthread_key_t; in this case we return NULL. 162 * -- Note that NULL return with zero threadKeyError and zero 163 * doCreate indicates "no per-thread error set yet", which is 164 * not an error. 165 */ 166static PR_threadErrInfo *PR_getThreadErrInfo( 167 int doCreate, 168 PRInt32 *threadKeyError) // RETURNED, an OSStatus 169{ 170 *threadKeyError = PR_initThreadKey(doCreate); 171 if(*threadKeyError) { 172 return NULL; 173 } 174 PR_threadErrInfo *errInfo = pthread_getspecific(PR_threadKey); 175 if((errInfo == NULL) && doCreate) { 176 errInfo = (PR_threadErrInfo *)malloc(sizeof(*errInfo)); 177 if(errInfo == NULL) { 178 /* 179 * malloc failure, retriable failure of this routine (not 180 * a PR_threadKeyErrorFlag style error). 181 * Note that this is *not* detected in a subsequent 182 * GetXError() call, but it will allow for somewhat 183 * graceful recovery in case some memory gets freed 184 * up. 185 */ 186 *threadKeyError = PR_OUT_OF_MEMORY_ERROR; 187 } 188 else { 189 memset(errInfo, 0, sizeof(*errInfo)); 190 pthread_setspecific(PR_threadKey, errInfo); 191 } 192 } 193 return errInfo; 194} 195 196PR_IMPLEMENT(PRErrorCode) PR_GetError(void) 197{ 198 PRInt32 prtn; 199 PR_threadErrInfo *errInfo = PR_getThreadErrInfo(0, &prtn); 200 if(errInfo == NULL) { 201 /* no error set or per-thread logic uninitialized */ 202 if(prtn) { 203 return PR_INSUFFICIENT_RESOURCES_ERROR; 204 } 205 else { 206 return 0; 207 } 208 } 209 else { 210 return errInfo->prError; 211 } 212} 213 214PR_IMPLEMENT(PRInt32) PR_GetOSError(void) 215{ 216 PRInt32 prtn; 217 PR_threadErrInfo *errInfo = PR_getThreadErrInfo(0, &prtn); 218 if(errInfo == NULL) { 219 /* no error set or per-thread logic uninitialized */ 220 return prtn; 221 } 222 else { 223 return errInfo->osError; 224 } 225} 226 227PR_IMPLEMENT(void) PR_SetError(PRErrorCode code, PRInt32 osErr) 228{ 229 PRInt32 prtn; 230 PR_threadErrInfo *errInfo = PR_getThreadErrInfo(1, &prtn); 231 if(errInfo != NULL) { 232 errInfo->osError = osErr; 233 errInfo->prError = code; 234 } 235 /* else per-thread logic uninitialized */ 236} 237 238// MARK: *** misc. *** 239 240/* 241** Compute the log of the least power of 2 greater than or equal to n 242*/ 243NSPR_API(PRIntn) PR_CeilingLog2(PRUint32 i) 244{ 245 PRIntn r; 246 PR_CEILING_LOG2(r,i); 247 return r; 248} 249 250#endif /* _NSPR_PORT_X_H_ */ 251