]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_asn1/lib/nsprPortX.c
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_asn1 / lib / nsprPortX.c
1 /*
2 * Copyright (c) 2003-2006,2008,2010-2012 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
42 NSPR_API(void *) PR_Malloc(PRSize size)
43 {
44 return malloc(size ? size : 1);
45 }
46 NSPR_API(void *) PR_Calloc(PRSize nelem, PRSize elsize)
47 {
48 return calloc(nelem, elsize);
49 }
50 NSPR_API(void *) PR_Realloc(void *ptr, PRSize size)
51 {
52 return realloc(ptr, size);
53 }
54 NSPR_API(void) PR_Free(void *ptr)
55 {
56 return free(ptr);
57 }
58
59 // MARK: *** locks ***
60
61 NSPR_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
74 NSPR_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
83 NSPR_API(void) PR_Lock(PRLock *lock)
84 {
85 if(lock == NULL) {
86 return;
87 }
88 pthread_mutex_lock((pthread_mutex_t *)lock);
89 }
90
91 NSPR_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 */
106 static pthread_key_t PR_threadKey;
107 static int PR_threadKeyInitFlag; // we have a PR_threadKey
108 static int PR_threadKeyErrorFlag; // unable to create PR_threadKey
109 static 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 */
117 typedef 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 */
128 static 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 */
166 static 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
196 PR_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
214 PR_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
227 PR_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 */
243 NSPR_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_ */