Mercurial > trustbridge > nss-cmake-static
comparison nspr/pr/src/misc/pratom.c @ 0:1e5118fa0cb1
This is NSS with a Cmake Buildsyste
To compile a static NSS library for Windows we've used the
Chromium-NSS fork and added a Cmake buildsystem to compile
it statically for Windows. See README.chromium for chromium
changes and README.trustbridge for our modifications.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Mon, 28 Jul 2014 10:47:06 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:1e5118fa0cb1 |
---|---|
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ | |
2 /* This Source Code Form is subject to the terms of the Mozilla Public | |
3 * License, v. 2.0. If a copy of the MPL was not distributed with this | |
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | |
5 | |
6 /* | |
7 ** PR Atomic operations | |
8 */ | |
9 | |
10 | |
11 #include "pratom.h" | |
12 #include "primpl.h" | |
13 | |
14 #include <string.h> | |
15 | |
16 /* | |
17 * The following is a fallback implementation that emulates | |
18 * atomic operations for platforms without atomic operations. | |
19 * If a platform has atomic operations, it should define the | |
20 * macro _PR_HAVE_ATOMIC_OPS, and the following will not be | |
21 * compiled in. | |
22 */ | |
23 | |
24 #if !defined(_PR_HAVE_ATOMIC_OPS) | |
25 | |
26 #if defined(_PR_PTHREADS) && !defined(_PR_DCETHREADS) | |
27 /* | |
28 * PR_AtomicDecrement() is used in NSPR's thread-specific data | |
29 * destructor. Because thread-specific data destructors may be | |
30 * invoked after a PR_Cleanup() call, we need an implementation | |
31 * of the atomic routines that doesn't need NSPR to be initialized. | |
32 */ | |
33 | |
34 /* | |
35 * We use a set of locks for all the emulated atomic operations. | |
36 * By hashing on the address of the integer to be locked the | |
37 * contention between multiple threads should be lessened. | |
38 * | |
39 * The number of atomic locks can be set by the environment variable | |
40 * NSPR_ATOMIC_HASH_LOCKS | |
41 */ | |
42 | |
43 /* | |
44 * lock counts should be a power of 2 | |
45 */ | |
46 #define DEFAULT_ATOMIC_LOCKS 16 /* should be in sync with the number of initializers | |
47 below */ | |
48 #define MAX_ATOMIC_LOCKS (4 * 1024) | |
49 | |
50 static pthread_mutex_t static_atomic_locks[DEFAULT_ATOMIC_LOCKS] = { | |
51 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, | |
52 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, | |
53 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, | |
54 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, | |
55 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, | |
56 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, | |
57 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, | |
58 PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER }; | |
59 | |
60 #ifdef DEBUG | |
61 static PRInt32 static_hash_lock_counts[DEFAULT_ATOMIC_LOCKS]; | |
62 static PRInt32 *hash_lock_counts = static_hash_lock_counts; | |
63 #endif | |
64 | |
65 static PRUint32 num_atomic_locks = DEFAULT_ATOMIC_LOCKS; | |
66 static pthread_mutex_t *atomic_locks = static_atomic_locks; | |
67 static PRUint32 atomic_hash_mask = DEFAULT_ATOMIC_LOCKS - 1; | |
68 | |
69 #define _PR_HASH_FOR_LOCK(ptr) \ | |
70 ((PRUint32) (((PRUptrdiff) (ptr) >> 2) ^ \ | |
71 ((PRUptrdiff) (ptr) >> 8)) & \ | |
72 atomic_hash_mask) | |
73 | |
74 void _PR_MD_INIT_ATOMIC() | |
75 { | |
76 char *eval; | |
77 int index; | |
78 | |
79 | |
80 PR_ASSERT(PR_FloorLog2(MAX_ATOMIC_LOCKS) == | |
81 PR_CeilingLog2(MAX_ATOMIC_LOCKS)); | |
82 | |
83 PR_ASSERT(PR_FloorLog2(DEFAULT_ATOMIC_LOCKS) == | |
84 PR_CeilingLog2(DEFAULT_ATOMIC_LOCKS)); | |
85 | |
86 if (((eval = getenv("NSPR_ATOMIC_HASH_LOCKS")) != NULL) && | |
87 ((num_atomic_locks = atoi(eval)) != DEFAULT_ATOMIC_LOCKS)) { | |
88 | |
89 if (num_atomic_locks > MAX_ATOMIC_LOCKS) | |
90 num_atomic_locks = MAX_ATOMIC_LOCKS; | |
91 else if (num_atomic_locks < 1) | |
92 num_atomic_locks = 1; | |
93 else { | |
94 num_atomic_locks = PR_FloorLog2(num_atomic_locks); | |
95 num_atomic_locks = 1L << num_atomic_locks; | |
96 } | |
97 atomic_locks = (pthread_mutex_t *) PR_Malloc(sizeof(pthread_mutex_t) * | |
98 num_atomic_locks); | |
99 if (atomic_locks) { | |
100 for (index = 0; index < num_atomic_locks; index++) { | |
101 if (pthread_mutex_init(&atomic_locks[index], NULL)) { | |
102 PR_DELETE(atomic_locks); | |
103 atomic_locks = NULL; | |
104 break; | |
105 } | |
106 } | |
107 } | |
108 #ifdef DEBUG | |
109 if (atomic_locks) { | |
110 hash_lock_counts = PR_CALLOC(num_atomic_locks * sizeof(PRInt32)); | |
111 if (hash_lock_counts == NULL) { | |
112 PR_DELETE(atomic_locks); | |
113 atomic_locks = NULL; | |
114 } | |
115 } | |
116 #endif | |
117 if (atomic_locks == NULL) { | |
118 /* | |
119 * Use statically allocated locks | |
120 */ | |
121 atomic_locks = static_atomic_locks; | |
122 num_atomic_locks = DEFAULT_ATOMIC_LOCKS; | |
123 #ifdef DEBUG | |
124 hash_lock_counts = static_hash_lock_counts; | |
125 #endif | |
126 } | |
127 atomic_hash_mask = num_atomic_locks - 1; | |
128 } | |
129 PR_ASSERT(PR_FloorLog2(num_atomic_locks) == | |
130 PR_CeilingLog2(num_atomic_locks)); | |
131 } | |
132 | |
133 PRInt32 | |
134 _PR_MD_ATOMIC_INCREMENT(PRInt32 *val) | |
135 { | |
136 PRInt32 rv; | |
137 PRInt32 idx = _PR_HASH_FOR_LOCK(val); | |
138 | |
139 pthread_mutex_lock(&atomic_locks[idx]); | |
140 rv = ++(*val); | |
141 #ifdef DEBUG | |
142 hash_lock_counts[idx]++; | |
143 #endif | |
144 pthread_mutex_unlock(&atomic_locks[idx]); | |
145 return rv; | |
146 } | |
147 | |
148 PRInt32 | |
149 _PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) | |
150 { | |
151 PRInt32 rv; | |
152 PRInt32 idx = _PR_HASH_FOR_LOCK(ptr); | |
153 | |
154 pthread_mutex_lock(&atomic_locks[idx]); | |
155 rv = ((*ptr) += val); | |
156 #ifdef DEBUG | |
157 hash_lock_counts[idx]++; | |
158 #endif | |
159 pthread_mutex_unlock(&atomic_locks[idx]); | |
160 return rv; | |
161 } | |
162 | |
163 PRInt32 | |
164 _PR_MD_ATOMIC_DECREMENT(PRInt32 *val) | |
165 { | |
166 PRInt32 rv; | |
167 PRInt32 idx = _PR_HASH_FOR_LOCK(val); | |
168 | |
169 pthread_mutex_lock(&atomic_locks[idx]); | |
170 rv = --(*val); | |
171 #ifdef DEBUG | |
172 hash_lock_counts[idx]++; | |
173 #endif | |
174 pthread_mutex_unlock(&atomic_locks[idx]); | |
175 return rv; | |
176 } | |
177 | |
178 PRInt32 | |
179 _PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) | |
180 { | |
181 PRInt32 rv; | |
182 PRInt32 idx = _PR_HASH_FOR_LOCK(val); | |
183 | |
184 pthread_mutex_lock(&atomic_locks[idx]); | |
185 rv = *val; | |
186 *val = newval; | |
187 #ifdef DEBUG | |
188 hash_lock_counts[idx]++; | |
189 #endif | |
190 pthread_mutex_unlock(&atomic_locks[idx]); | |
191 return rv; | |
192 } | |
193 #else /* _PR_PTHREADS && !_PR_DCETHREADS */ | |
194 /* | |
195 * We use a single lock for all the emulated atomic operations. | |
196 * The lock contention should be acceptable. | |
197 */ | |
198 static PRLock *atomic_lock = NULL; | |
199 void _PR_MD_INIT_ATOMIC(void) | |
200 { | |
201 if (atomic_lock == NULL) { | |
202 atomic_lock = PR_NewLock(); | |
203 } | |
204 } | |
205 | |
206 PRInt32 | |
207 _PR_MD_ATOMIC_INCREMENT(PRInt32 *val) | |
208 { | |
209 PRInt32 rv; | |
210 | |
211 if (!_pr_initialized) { | |
212 _PR_ImplicitInitialization(); | |
213 } | |
214 PR_Lock(atomic_lock); | |
215 rv = ++(*val); | |
216 PR_Unlock(atomic_lock); | |
217 return rv; | |
218 } | |
219 | |
220 PRInt32 | |
221 _PR_MD_ATOMIC_ADD(PRInt32 *ptr, PRInt32 val) | |
222 { | |
223 PRInt32 rv; | |
224 | |
225 if (!_pr_initialized) { | |
226 _PR_ImplicitInitialization(); | |
227 } | |
228 PR_Lock(atomic_lock); | |
229 rv = ((*ptr) += val); | |
230 PR_Unlock(atomic_lock); | |
231 return rv; | |
232 } | |
233 | |
234 PRInt32 | |
235 _PR_MD_ATOMIC_DECREMENT(PRInt32 *val) | |
236 { | |
237 PRInt32 rv; | |
238 | |
239 if (!_pr_initialized) { | |
240 _PR_ImplicitInitialization(); | |
241 } | |
242 PR_Lock(atomic_lock); | |
243 rv = --(*val); | |
244 PR_Unlock(atomic_lock); | |
245 return rv; | |
246 } | |
247 | |
248 PRInt32 | |
249 _PR_MD_ATOMIC_SET(PRInt32 *val, PRInt32 newval) | |
250 { | |
251 PRInt32 rv; | |
252 | |
253 if (!_pr_initialized) { | |
254 _PR_ImplicitInitialization(); | |
255 } | |
256 PR_Lock(atomic_lock); | |
257 rv = *val; | |
258 *val = newval; | |
259 PR_Unlock(atomic_lock); | |
260 return rv; | |
261 } | |
262 #endif /* _PR_PTHREADS && !_PR_DCETHREADS */ | |
263 | |
264 #endif /* !_PR_HAVE_ATOMIC_OPS */ | |
265 | |
266 void _PR_InitAtomic(void) | |
267 { | |
268 _PR_MD_INIT_ATOMIC(); | |
269 } | |
270 | |
271 PR_IMPLEMENT(PRInt32) | |
272 PR_AtomicIncrement(PRInt32 *val) | |
273 { | |
274 return _PR_MD_ATOMIC_INCREMENT(val); | |
275 } | |
276 | |
277 PR_IMPLEMENT(PRInt32) | |
278 PR_AtomicDecrement(PRInt32 *val) | |
279 { | |
280 return _PR_MD_ATOMIC_DECREMENT(val); | |
281 } | |
282 | |
283 PR_IMPLEMENT(PRInt32) | |
284 PR_AtomicSet(PRInt32 *val, PRInt32 newval) | |
285 { | |
286 return _PR_MD_ATOMIC_SET(val, newval); | |
287 } | |
288 | |
289 PR_IMPLEMENT(PRInt32) | |
290 PR_AtomicAdd(PRInt32 *ptr, PRInt32 val) | |
291 { | |
292 return _PR_MD_ATOMIC_ADD(ptr, val); | |
293 } | |
294 /* | |
295 * For platforms, which don't support the CAS (compare-and-swap) instruction | |
296 * (or an equivalent), the stack operations are implemented by use of PRLock | |
297 */ | |
298 | |
299 PR_IMPLEMENT(PRStack *) | |
300 PR_CreateStack(const char *stack_name) | |
301 { | |
302 PRStack *stack; | |
303 | |
304 if (!_pr_initialized) { | |
305 _PR_ImplicitInitialization(); | |
306 } | |
307 | |
308 if ((stack = PR_NEW(PRStack)) == NULL) { | |
309 return NULL; | |
310 } | |
311 if (stack_name) { | |
312 stack->prstk_name = (char *) PR_Malloc(strlen(stack_name) + 1); | |
313 if (stack->prstk_name == NULL) { | |
314 PR_DELETE(stack); | |
315 return NULL; | |
316 } | |
317 strcpy(stack->prstk_name, stack_name); | |
318 } else | |
319 stack->prstk_name = NULL; | |
320 | |
321 #ifndef _PR_HAVE_ATOMIC_CAS | |
322 stack->prstk_lock = PR_NewLock(); | |
323 if (stack->prstk_lock == NULL) { | |
324 PR_Free(stack->prstk_name); | |
325 PR_DELETE(stack); | |
326 return NULL; | |
327 } | |
328 #endif /* !_PR_HAVE_ATOMIC_CAS */ | |
329 | |
330 stack->prstk_head.prstk_elem_next = NULL; | |
331 | |
332 return stack; | |
333 } | |
334 | |
335 PR_IMPLEMENT(PRStatus) | |
336 PR_DestroyStack(PRStack *stack) | |
337 { | |
338 if (stack->prstk_head.prstk_elem_next != NULL) { | |
339 PR_SetError(PR_INVALID_STATE_ERROR, 0); | |
340 return PR_FAILURE; | |
341 } | |
342 | |
343 if (stack->prstk_name) | |
344 PR_Free(stack->prstk_name); | |
345 #ifndef _PR_HAVE_ATOMIC_CAS | |
346 PR_DestroyLock(stack->prstk_lock); | |
347 #endif /* !_PR_HAVE_ATOMIC_CAS */ | |
348 PR_DELETE(stack); | |
349 | |
350 return PR_SUCCESS; | |
351 } | |
352 | |
353 #ifndef _PR_HAVE_ATOMIC_CAS | |
354 | |
355 PR_IMPLEMENT(void) | |
356 PR_StackPush(PRStack *stack, PRStackElem *stack_elem) | |
357 { | |
358 PR_Lock(stack->prstk_lock); | |
359 stack_elem->prstk_elem_next = stack->prstk_head.prstk_elem_next; | |
360 stack->prstk_head.prstk_elem_next = stack_elem; | |
361 PR_Unlock(stack->prstk_lock); | |
362 return; | |
363 } | |
364 | |
365 PR_IMPLEMENT(PRStackElem *) | |
366 PR_StackPop(PRStack *stack) | |
367 { | |
368 PRStackElem *element; | |
369 | |
370 PR_Lock(stack->prstk_lock); | |
371 element = stack->prstk_head.prstk_elem_next; | |
372 if (element != NULL) { | |
373 stack->prstk_head.prstk_elem_next = element->prstk_elem_next; | |
374 element->prstk_elem_next = NULL; /* debugging aid */ | |
375 } | |
376 PR_Unlock(stack->prstk_lock); | |
377 return element; | |
378 } | |
379 #endif /* !_PR_HAVE_ATOMIC_CAS */ |