Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(47)

Side by Side Diff: nss/lib/base/arena.c

Issue 2078763002: Delete bundled copy of NSS and replace with README. (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/nss@master
Patch Set: Delete bundled copy of NSS and replace with README. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « nss/COPYING ('k') | nss/lib/base/base.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 /*
6 * arena.c
7 *
8 * This contains the implementation of NSS's thread-safe arenas.
9 */
10
11 #ifndef BASE_H
12 #include "base.h"
13 #endif /* BASE_H */
14
15 #ifdef ARENA_THREADMARK
16 #include "prthread.h"
17 #endif /* ARENA_THREADMARK */
18
19 #include "prlock.h"
20 #include "plarena.h"
21
22 #include <string.h>
23
24 /*
25 * NSSArena
26 *
27 * This is based on NSPR's arena code, but it is threadsafe.
28 *
29 * The public methods relating to this type are:
30 *
31 * NSSArena_Create -- constructor
32 * NSSArena_Destroy
33 * NSS_ZAlloc
34 * NSS_ZRealloc
35 * NSS_ZFreeIf
36 *
37 * The nonpublic methods relating to this type are:
38 *
39 * nssArena_Create -- constructor
40 * nssArena_Destroy
41 * nssArena_Mark
42 * nssArena_Release
43 * nssArena_Unmark
44 *
45 * nss_ZAlloc
46 * nss_ZFreeIf
47 * nss_ZRealloc
48 *
49 * In debug builds, the following calls are available:
50 *
51 * nssArena_verifyPointer
52 * nssArena_registerDestructor
53 * nssArena_deregisterDestructor
54 */
55
56 struct NSSArenaStr {
57 PLArenaPool pool;
58 PRLock *lock;
59 #ifdef ARENA_THREADMARK
60 PRThread *marking_thread;
61 nssArenaMark *first_mark;
62 nssArenaMark *last_mark;
63 #endif /* ARENA_THREADMARK */
64 #ifdef ARENA_DESTRUCTOR_LIST
65 struct arena_destructor_node *first_destructor;
66 struct arena_destructor_node *last_destructor;
67 #endif /* ARENA_DESTRUCTOR_LIST */
68 };
69
70 /*
71 * nssArenaMark
72 *
73 * This type is used to mark the current state of an NSSArena.
74 */
75
76 struct nssArenaMarkStr {
77 PRUint32 magic;
78 void *mark;
79 #ifdef ARENA_THREADMARK
80 nssArenaMark *next;
81 #endif /* ARENA_THREADMARK */
82 #ifdef ARENA_DESTRUCTOR_LIST
83 struct arena_destructor_node *next_destructor;
84 struct arena_destructor_node *prev_destructor;
85 #endif /* ARENA_DESTRUCTOR_LIST */
86 };
87
88 #define MARK_MAGIC 0x4d41524b /* "MARK" how original */
89
90 /*
91 * But first, the pointer-tracking code
92 */
93 #ifdef DEBUG
94 extern const NSSError NSS_ERROR_INTERNAL_ERROR;
95
96 static nssPointerTracker arena_pointer_tracker;
97
98 static PRStatus
99 arena_add_pointer(const NSSArena *arena)
100 {
101 PRStatus rv;
102
103 rv = nssPointerTracker_initialize(&arena_pointer_tracker);
104 if (PR_SUCCESS != rv) {
105 return rv;
106 }
107
108 rv = nssPointerTracker_add(&arena_pointer_tracker, arena);
109 if (PR_SUCCESS != rv) {
110 NSSError e = NSS_GetError();
111 if (NSS_ERROR_NO_MEMORY != e) {
112 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
113 }
114
115 return rv;
116 }
117
118 return PR_SUCCESS;
119 }
120
121 static PRStatus
122 arena_remove_pointer(const NSSArena *arena)
123 {
124 PRStatus rv;
125
126 rv = nssPointerTracker_remove(&arena_pointer_tracker, arena);
127 if (PR_SUCCESS != rv) {
128 nss_SetError(NSS_ERROR_INTERNAL_ERROR);
129 }
130
131 return rv;
132 }
133
134 /*
135 * nssArena_verifyPointer
136 *
137 * This method is only present in debug builds.
138 *
139 * If the specified pointer is a valid pointer to an NSSArena object,
140 * this routine will return PR_SUCCESS. Otherwise, it will put an
141 * error on the error stack and return PR_FAILURE.
142 *
143 * The error may be one of the following values:
144 * NSS_ERROR_INVALID_ARENA
145 *
146 * Return value:
147 * PR_SUCCESS if the pointer is valid
148 * PR_FAILURE if it isn't
149 */
150
151 NSS_IMPLEMENT PRStatus
152 nssArena_verifyPointer(const NSSArena *arena)
153 {
154 PRStatus rv;
155
156 rv = nssPointerTracker_initialize(&arena_pointer_tracker);
157 if (PR_SUCCESS != rv) {
158 /*
159 * This is a little disingenious. We have to initialize the
160 * tracker, because someone could "legitimately" try to verify
161 * an arena pointer before one is ever created. And this step
162 * might fail, due to lack of memory. But the only way that
163 * this step can fail is if it's doing the call_once stuff,
164 * (later calls just no-op). And if it didn't no-op, there
165 * aren't any valid arenas.. so the argument certainly isn't one.
166 */
167 nss_SetError(NSS_ERROR_INVALID_ARENA);
168 return PR_FAILURE;
169 }
170
171 rv = nssPointerTracker_verify(&arena_pointer_tracker, arena);
172 if (PR_SUCCESS != rv) {
173 nss_SetError(NSS_ERROR_INVALID_ARENA);
174 return PR_FAILURE;
175 }
176
177 return PR_SUCCESS;
178 }
179 #endif /* DEBUG */
180
181 #ifdef ARENA_DESTRUCTOR_LIST
182
183 struct arena_destructor_node {
184 struct arena_destructor_node *next;
185 struct arena_destructor_node *prev;
186 void (*destructor)(void *argument);
187 void *arg;
188 };
189
190 /*
191 * nssArena_registerDestructor
192 *
193 * This routine stores a pointer to a callback and an arbitrary
194 * pointer-sized argument in the arena, at the current point in
195 * the mark stack. If the arena is destroyed, or an "earlier"
196 * mark is released, then this destructor will be called at that
197 * time. Note that the destructor will be called with the arena
198 * locked, which means the destructor may free memory in that
199 * arena, but it may not allocate or cause to be allocated any
200 * memory. This callback facility was included to support our
201 * debug-version pointer-tracker feature; overuse runs counter to
202 * the the original intent of arenas. This routine returns a
203 * PRStatus value; if successful, it will return PR_SUCCESS. If
204 * unsuccessful, it will set an error on the error stack and
205 * return PR_FAILURE.
206 *
207 * The error may be one of the following values:
208 * NSS_ERROR_INVALID_ARENA
209 * NSS_ERROR_NO_MEMORY
210 *
211 * Return value:
212 * PR_SUCCESS
213 * PR_FAILURE
214 */
215
216 NSS_IMPLEMENT PRStatus
217 nssArena_registerDestructor(NSSArena *arena, void (*destructor)(void *argument),
218 void *arg)
219 {
220 struct arena_destructor_node *it;
221
222 #ifdef NSSDEBUG
223 if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
224 return PR_FAILURE;
225 }
226 #endif /* NSSDEBUG */
227
228 it = nss_ZNEW(arena, struct arena_destructor_node);
229 if ((struct arena_destructor_node *)NULL == it) {
230 return PR_FAILURE;
231 }
232
233 it->prev = arena->last_destructor;
234 arena->last_destructor->next = it;
235 arena->last_destructor = it;
236 it->destructor = destructor;
237 it->arg = arg;
238
239 if ((nssArenaMark *)NULL != arena->last_mark) {
240 arena->last_mark->prev_destructor = it->prev;
241 arena->last_mark->next_destructor = it->next;
242 }
243
244 return PR_SUCCESS;
245 }
246
247 NSS_IMPLEMENT PRStatus
248 nssArena_deregisterDestructor(NSSArena *arena,
249 void (*destructor)(void *argument), void *arg)
250 {
251 struct arena_destructor_node *it;
252
253 #ifdef NSSDEBUG
254 if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
255 return PR_FAILURE;
256 }
257 #endif /* NSSDEBUG */
258
259 for (it = arena->first_destructor; it; it = it->next) {
260 if ((it->destructor == destructor) && (it->arg == arg)) {
261 break;
262 }
263 }
264
265 if ((struct arena_destructor_node *)NULL == it) {
266 nss_SetError(NSS_ERROR_NOT_FOUND);
267 return PR_FAILURE;
268 }
269
270 if (it == arena->first_destructor) {
271 arena->first_destructor = it->next;
272 }
273
274 if (it == arena->last_destructor) {
275 arena->last_destructor = it->prev;
276 }
277
278 if ((struct arena_destructor_node *)NULL != it->prev) {
279 it->prev->next = it->next;
280 }
281
282 if ((struct arena_destructor_node *)NULL != it->next) {
283 it->next->prev = it->prev;
284 }
285
286 {
287 nssArenaMark *m;
288 for (m = arena->first_mark; m; m = m->next) {
289 if (m->next_destructor == it) {
290 m->next_destructor = it->next;
291 }
292 if (m->prev_destructor == it) {
293 m->prev_destructor = it->prev;
294 }
295 }
296 }
297
298 nss_ZFreeIf(it);
299 return PR_SUCCESS;
300 }
301
302 static void
303 nss_arena_call_destructor_chain(struct arena_destructor_node *it)
304 {
305 for (; it; it = it->next) {
306 (*(it->destructor))(it->arg);
307 }
308 }
309
310 #endif /* ARENA_DESTRUCTOR_LIST */
311
312 /*
313 * NSSArena_Create
314 *
315 * This routine creates a new memory arena. This routine may return
316 * NULL upon error, in which case it will have created an error stack.
317 *
318 * The top-level error may be one of the following values:
319 * NSS_ERROR_NO_MEMORY
320 *
321 * Return value:
322 * NULL upon error
323 * A pointer to an NSSArena upon success
324 */
325
326 NSS_IMPLEMENT NSSArena *
327 NSSArena_Create(void)
328 {
329 nss_ClearErrorStack();
330 return nssArena_Create();
331 }
332
333 /*
334 * nssArena_Create
335 *
336 * This routine creates a new memory arena. This routine may return
337 * NULL upon error, in which case it will have set an error on the
338 * error stack.
339 *
340 * The error may be one of the following values:
341 * NSS_ERROR_NO_MEMORY
342 *
343 * Return value:
344 * NULL upon error
345 * A pointer to an NSSArena upon success
346 */
347
348 NSS_IMPLEMENT NSSArena *
349 nssArena_Create(void)
350 {
351 NSSArena *rv = (NSSArena *)NULL;
352
353 rv = nss_ZNEW((NSSArena *)NULL, NSSArena);
354 if ((NSSArena *)NULL == rv) {
355 nss_SetError(NSS_ERROR_NO_MEMORY);
356 return (NSSArena *)NULL;
357 }
358
359 rv->lock = PR_NewLock();
360 if ((PRLock *)NULL == rv->lock) {
361 (void)nss_ZFreeIf(rv);
362 nss_SetError(NSS_ERROR_NO_MEMORY);
363 return (NSSArena *)NULL;
364 }
365
366 /*
367 * Arena sizes. The current security code has 229 occurrences of
368 * PORT_NewArena. The default chunksizes specified break down as
369 *
370 * Size Mult. Specified as
371 * 512 1 512
372 * 1024 7 1024
373 * 2048 5 2048
374 * 2048 5 CRMF_DEFAULT_ARENA_SIZE
375 * 2048 190 DER_DEFAULT_CHUNKSIZE
376 * 2048 20 SEC_ASN1_DEFAULT_ARENA_SIZE
377 * 4096 1 4096
378 *
379 * Obviously this "default chunksize" flexibility isn't very
380 * useful to us, so I'll just pick 2048.
381 */
382
383 PL_InitArenaPool(&rv->pool, "NSS", 2048, sizeof(double));
384
385 #ifdef DEBUG
386 {
387 PRStatus st;
388 st = arena_add_pointer(rv);
389 if (PR_SUCCESS != st) {
390 PL_FinishArenaPool(&rv->pool);
391 PR_DestroyLock(rv->lock);
392 (void)nss_ZFreeIf(rv);
393 return (NSSArena *)NULL;
394 }
395 }
396 #endif /* DEBUG */
397
398 return rv;
399 }
400
401 /*
402 * NSSArena_Destroy
403 *
404 * This routine will destroy the specified arena, freeing all memory
405 * allocated from it. This routine returns a PRStatus value; if
406 * successful, it will return PR_SUCCESS. If unsuccessful, it will
407 * create an error stack and return PR_FAILURE.
408 *
409 * The top-level error may be one of the following values:
410 * NSS_ERROR_INVALID_ARENA
411 *
412 * Return value:
413 * PR_SUCCESS upon success
414 * PR_FAILURE upon failure
415 */
416
417 NSS_IMPLEMENT PRStatus
418 NSSArena_Destroy(NSSArena *arena)
419 {
420 nss_ClearErrorStack();
421
422 #ifdef DEBUG
423 if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
424 return PR_FAILURE;
425 }
426 #endif /* DEBUG */
427
428 return nssArena_Destroy(arena);
429 }
430
431 /*
432 * nssArena_Destroy
433 *
434 * This routine will destroy the specified arena, freeing all memory
435 * allocated from it. This routine returns a PRStatus value; if
436 * successful, it will return PR_SUCCESS. If unsuccessful, it will
437 * set an error on the error stack and return PR_FAILURE.
438 *
439 * The error may be one of the following values:
440 * NSS_ERROR_INVALID_ARENA
441 *
442 * Return value:
443 * PR_SUCCESS
444 * PR_FAILURE
445 */
446
447 NSS_IMPLEMENT PRStatus
448 nssArena_Destroy(NSSArena *arena)
449 {
450 PRLock *lock;
451
452 #ifdef NSSDEBUG
453 if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
454 return PR_FAILURE;
455 }
456 #endif /* NSSDEBUG */
457
458 if ((PRLock *)NULL == arena->lock) {
459 /* Just got destroyed */
460 nss_SetError(NSS_ERROR_INVALID_ARENA);
461 return PR_FAILURE;
462 }
463 PR_Lock(arena->lock);
464
465 #ifdef DEBUG
466 if (PR_SUCCESS != arena_remove_pointer(arena)) {
467 PR_Unlock(arena->lock);
468 return PR_FAILURE;
469 }
470 #endif /* DEBUG */
471
472 #ifdef ARENA_DESTRUCTOR_LIST
473 /* Note that the arena is locked at this time */
474 nss_arena_call_destructor_chain(arena->first_destructor);
475 #endif /* ARENA_DESTRUCTOR_LIST */
476
477 PL_FinishArenaPool(&arena->pool);
478 lock = arena->lock;
479 arena->lock = (PRLock *)NULL;
480 PR_Unlock(lock);
481 PR_DestroyLock(lock);
482 (void)nss_ZFreeIf(arena);
483 return PR_SUCCESS;
484 }
485
486 static void *nss_zalloc_arena_locked(NSSArena *arena, PRUint32 size);
487
488 /*
489 * nssArena_Mark
490 *
491 * This routine "marks" the current state of an arena. Space
492 * allocated after the arena has been marked can be freed by
493 * releasing the arena back to the mark with nssArena_Release,
494 * or committed by calling nssArena_Unmark. When successful,
495 * this routine returns a valid nssArenaMark pointer. This
496 * routine may return NULL upon error, in which case it will
497 * have set an error on the error stack.
498 *
499 * The error may be one of the following values:
500 * NSS_ERROR_INVALID_ARENA
501 * NSS_ERROR_NO_MEMORY
502 * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
503 *
504 * Return value:
505 * NULL upon failure
506 * An nssArenaMark pointer upon success
507 */
508
509 NSS_IMPLEMENT nssArenaMark *
510 nssArena_Mark(NSSArena *arena)
511 {
512 nssArenaMark *rv;
513 void *p;
514
515 #ifdef NSSDEBUG
516 if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
517 return (nssArenaMark *)NULL;
518 }
519 #endif /* NSSDEBUG */
520
521 if ((PRLock *)NULL == arena->lock) {
522 /* Just got destroyed */
523 nss_SetError(NSS_ERROR_INVALID_ARENA);
524 return (nssArenaMark *)NULL;
525 }
526 PR_Lock(arena->lock);
527
528 #ifdef ARENA_THREADMARK
529 if ((PRThread *)NULL == arena->marking_thread) {
530 /* Unmarked. Store our thread ID */
531 arena->marking_thread = PR_GetCurrentThread();
532 /* This call never fails. */
533 } else {
534 /* Marked. Verify it's the current thread */
535 if (PR_GetCurrentThread() != arena->marking_thread) {
536 PR_Unlock(arena->lock);
537 nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
538 return (nssArenaMark *)NULL;
539 }
540 }
541 #endif /* ARENA_THREADMARK */
542
543 p = PL_ARENA_MARK(&arena->pool);
544 /* No error possible */
545
546 /* Do this after the mark */
547 rv = (nssArenaMark *)nss_zalloc_arena_locked(arena, sizeof(nssArenaMark));
548 if ((nssArenaMark *)NULL == rv) {
549 PR_Unlock(arena->lock);
550 nss_SetError(NSS_ERROR_NO_MEMORY);
551 return (nssArenaMark *)NULL;
552 }
553
554 #ifdef ARENA_THREADMARK
555 if ((nssArenaMark *)NULL == arena->first_mark) {
556 arena->first_mark = rv;
557 arena->last_mark = rv;
558 } else {
559 arena->last_mark->next = rv;
560 arena->last_mark = rv;
561 }
562 #endif /* ARENA_THREADMARK */
563
564 rv->mark = p;
565 rv->magic = MARK_MAGIC;
566
567 #ifdef ARENA_DESTRUCTOR_LIST
568 rv->prev_destructor = arena->last_destructor;
569 #endif /* ARENA_DESTRUCTOR_LIST */
570
571 PR_Unlock(arena->lock);
572
573 return rv;
574 }
575
576 /*
577 * nss_arena_unmark_release
578 *
579 * This static routine implements the routines nssArena_Release
580 * ans nssArena_Unmark, which are almost identical.
581 */
582
583 static PRStatus
584 nss_arena_unmark_release(NSSArena *arena, nssArenaMark *arenaMark,
585 PRBool release)
586 {
587 void *inner_mark;
588
589 #ifdef NSSDEBUG
590 if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
591 return PR_FAILURE;
592 }
593 #endif /* NSSDEBUG */
594
595 if (MARK_MAGIC != arenaMark->magic) {
596 nss_SetError(NSS_ERROR_INVALID_ARENA_MARK);
597 return PR_FAILURE;
598 }
599
600 if ((PRLock *)NULL == arena->lock) {
601 /* Just got destroyed */
602 nss_SetError(NSS_ERROR_INVALID_ARENA);
603 return PR_FAILURE;
604 }
605 PR_Lock(arena->lock);
606
607 #ifdef ARENA_THREADMARK
608 if ((PRThread *)NULL != arena->marking_thread) {
609 if (PR_GetCurrentThread() != arena->marking_thread) {
610 PR_Unlock(arena->lock);
611 nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
612 return PR_FAILURE;
613 }
614 }
615 #endif /* ARENA_THREADMARK */
616
617 if (MARK_MAGIC != arenaMark->magic) {
618 /* Just got released */
619 PR_Unlock(arena->lock);
620 nss_SetError(NSS_ERROR_INVALID_ARENA_MARK);
621 return PR_FAILURE;
622 }
623
624 arenaMark->magic = 0;
625 inner_mark = arenaMark->mark;
626
627 #ifdef ARENA_THREADMARK
628 {
629 nssArenaMark **pMark = &arena->first_mark;
630 nssArenaMark *rest;
631 nssArenaMark *last = (nssArenaMark *)NULL;
632
633 /* Find this mark */
634 while (*pMark != arenaMark) {
635 last = *pMark;
636 pMark = &(*pMark)->next;
637 }
638
639 /* Remember the pointer, then zero it */
640 rest = (*pMark)->next;
641 *pMark = (nssArenaMark *)NULL;
642
643 arena->last_mark = last;
644
645 /* Invalidate any later marks being implicitly released */
646 for (; (nssArenaMark *)NULL != rest; rest = rest->next) {
647 rest->magic = 0;
648 }
649
650 /* If we just got rid of the first mark, clear the thread ID */
651 if ((nssArenaMark *)NULL == arena->first_mark) {
652 arena->marking_thread = (PRThread *)NULL;
653 }
654 }
655 #endif /* ARENA_THREADMARK */
656
657 if (release) {
658 #ifdef ARENA_DESTRUCTOR_LIST
659 if ((struct arena_destructor_node *)NULL !=
660 arenaMark->prev_destructor) {
661 arenaMark->prev_destructor->next =
662 (struct arena_destructor_node *)NULL;
663 }
664 arena->last_destructor = arenaMark->prev_destructor;
665
666 /* Note that the arena is locked at this time */
667 nss_arena_call_destructor_chain(arenaMark->next_destructor);
668 #endif /* ARENA_DESTRUCTOR_LIST */
669
670 PL_ARENA_RELEASE(&arena->pool, inner_mark);
671 /* No error return */
672 }
673
674 PR_Unlock(arena->lock);
675 return PR_SUCCESS;
676 }
677
678 /*
679 * nssArena_Release
680 *
681 * This routine invalidates and releases all memory allocated from
682 * the specified arena after the point at which the specified mark
683 * was obtained. This routine returns a PRStatus value; if successful,
684 * it will return PR_SUCCESS. If unsuccessful, it will set an error
685 * on the error stack and return PR_FAILURE.
686 *
687 * The error may be one of the following values:
688 * NSS_ERROR_INVALID_ARENA
689 * NSS_ERROR_INVALID_ARENA_MARK
690 * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
691 *
692 * Return value:
693 * PR_SUCCESS
694 * PR_FAILURE
695 */
696
697 NSS_IMPLEMENT PRStatus
698 nssArena_Release(NSSArena *arena, nssArenaMark *arenaMark)
699 {
700 return nss_arena_unmark_release(arena, arenaMark, PR_TRUE);
701 }
702
703 /*
704 * nssArena_Unmark
705 *
706 * This routine "commits" the indicated mark and any marks after
707 * it, making them unreleasable. Note that any earlier marks can
708 * still be released, and such a release will invalidate these
709 * later unmarked regions. If an arena is to be safely shared by
710 * more than one thread, all marks must be either released or
711 * unmarked. This routine returns a PRStatus value; if successful,
712 * it will return PR_SUCCESS. If unsuccessful, it will set an error
713 * on the error stack and return PR_FAILURE.
714 *
715 * The error may be one of the following values:
716 * NSS_ERROR_INVALID_ARENA
717 * NSS_ERROR_INVALID_ARENA_MARK
718 * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
719 *
720 * Return value:
721 * PR_SUCCESS
722 * PR_FAILURE
723 */
724
725 NSS_IMPLEMENT PRStatus
726 nssArena_Unmark(NSSArena *arena, nssArenaMark *arenaMark)
727 {
728 return nss_arena_unmark_release(arena, arenaMark, PR_FALSE);
729 }
730
731 /*
732 * We prefix this header to all allocated blocks. It is a multiple
733 * of the alignment size. Note that this usage of a header may make
734 * purify spew bogus warnings about "potentially leaked blocks" of
735 * memory; if that gets too annoying we can add in a pointer to the
736 * header in the header itself. There's not a lot of safety here;
737 * maybe we should add a magic value?
738 */
739 struct pointer_header {
740 NSSArena *arena;
741 PRUint32 size;
742 };
743
744 static void *
745 nss_zalloc_arena_locked(NSSArena *arena, PRUint32 size)
746 {
747 void *p;
748 void *rv;
749 struct pointer_header *h;
750 PRUint32 my_size = size + sizeof(struct pointer_header);
751 PL_ARENA_ALLOCATE(p, &arena->pool, my_size);
752 if ((void *)NULL == p) {
753 nss_SetError(NSS_ERROR_NO_MEMORY);
754 return (void *)NULL;
755 }
756 /*
757 * Do this before we unlock. This way if the user is using
758 * an arena in one thread while destroying it in another, he'll
759 * fault/FMR in his code, not ours.
760 */
761 h = (struct pointer_header *)p;
762 h->arena = arena;
763 h->size = size;
764 rv = (void *)((char *)h + sizeof(struct pointer_header));
765 (void)nsslibc_memset(rv, 0, size);
766 return rv;
767 }
768
769 /*
770 * NSS_ZAlloc
771 *
772 * This routine allocates and zeroes a section of memory of the
773 * size, and returns to the caller a pointer to that memory. If
774 * the optional arena argument is non-null, the memory will be
775 * obtained from that arena; otherwise, the memory will be obtained
776 * from the heap. This routine may return NULL upon error, in
777 * which case it will have set an error upon the error stack. The
778 * value specified for size may be zero; in which case a valid
779 * zero-length block of memory will be allocated. This block may
780 * be expanded by calling NSS_ZRealloc.
781 *
782 * The error may be one of the following values:
783 * NSS_ERROR_INVALID_ARENA
784 * NSS_ERROR_NO_MEMORY
785 * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
786 *
787 * Return value:
788 * NULL upon error
789 * A pointer to the new segment of zeroed memory
790 */
791
792 NSS_IMPLEMENT void *
793 NSS_ZAlloc(NSSArena *arenaOpt, PRUint32 size)
794 {
795 return nss_ZAlloc(arenaOpt, size);
796 }
797
798 /*
799 * nss_ZAlloc
800 *
801 * This routine allocates and zeroes a section of memory of the
802 * size, and returns to the caller a pointer to that memory. If
803 * the optional arena argument is non-null, the memory will be
804 * obtained from that arena; otherwise, the memory will be obtained
805 * from the heap. This routine may return NULL upon error, in
806 * which case it will have set an error upon the error stack. The
807 * value specified for size may be zero; in which case a valid
808 * zero-length block of memory will be allocated. This block may
809 * be expanded by calling nss_ZRealloc.
810 *
811 * The error may be one of the following values:
812 * NSS_ERROR_INVALID_ARENA
813 * NSS_ERROR_NO_MEMORY
814 * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
815 *
816 * Return value:
817 * NULL upon error
818 * A pointer to the new segment of zeroed memory
819 */
820
821 NSS_IMPLEMENT void *
822 nss_ZAlloc(NSSArena *arenaOpt, PRUint32 size)
823 {
824 struct pointer_header *h;
825 PRUint32 my_size = size + sizeof(struct pointer_header);
826
827 if (my_size < sizeof(struct pointer_header)) {
828 /* Wrapped */
829 nss_SetError(NSS_ERROR_NO_MEMORY);
830 return (void *)NULL;
831 }
832
833 if ((NSSArena *)NULL == arenaOpt) {
834 /* Heap allocation, no locking required. */
835 h = (struct pointer_header *)PR_Calloc(1, my_size);
836 if ((struct pointer_header *)NULL == h) {
837 nss_SetError(NSS_ERROR_NO_MEMORY);
838 return (void *)NULL;
839 }
840
841 h->arena = (NSSArena *)NULL;
842 h->size = size;
843 /* We used calloc: it's already zeroed */
844
845 return (void *)((char *)h + sizeof(struct pointer_header));
846 } else {
847 void *rv;
848 /* Arena allocation */
849 #ifdef NSSDEBUG
850 if (PR_SUCCESS != nssArena_verifyPointer(arenaOpt)) {
851 return (void *)NULL;
852 }
853 #endif /* NSSDEBUG */
854
855 if ((PRLock *)NULL == arenaOpt->lock) {
856 /* Just got destroyed */
857 nss_SetError(NSS_ERROR_INVALID_ARENA);
858 return (void *)NULL;
859 }
860 PR_Lock(arenaOpt->lock);
861
862 #ifdef ARENA_THREADMARK
863 if ((PRThread *)NULL != arenaOpt->marking_thread) {
864 if (PR_GetCurrentThread() != arenaOpt->marking_thread) {
865 nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
866 PR_Unlock(arenaOpt->lock);
867 return (void *)NULL;
868 }
869 }
870 #endif /* ARENA_THREADMARK */
871
872 rv = nss_zalloc_arena_locked(arenaOpt, size);
873
874 PR_Unlock(arenaOpt->lock);
875 return rv;
876 }
877 /*NOTREACHED*/
878 }
879
880 /*
881 * NSS_ZFreeIf
882 *
883 * If the specified pointer is non-null, then the region of memory
884 * to which it points -- which must have been allocated with
885 * NSS_ZAlloc -- will be zeroed and released. This routine
886 * returns a PRStatus value; if successful, it will return PR_SUCCESS.
887 * If unsuccessful, it will set an error on the error stack and return
888 * PR_FAILURE.
889 *
890 * The error may be one of the following values:
891 * NSS_ERROR_INVALID_POINTER
892 *
893 * Return value:
894 * PR_SUCCESS
895 * PR_FAILURE
896 */
897 NSS_IMPLEMENT PRStatus
898 NSS_ZFreeIf(void *pointer)
899 {
900 return nss_ZFreeIf(pointer);
901 }
902
903 /*
904 * nss_ZFreeIf
905 *
906 * If the specified pointer is non-null, then the region of memory
907 * to which it points -- which must have been allocated with
908 * nss_ZAlloc -- will be zeroed and released. This routine
909 * returns a PRStatus value; if successful, it will return PR_SUCCESS.
910 * If unsuccessful, it will set an error on the error stack and return
911 * PR_FAILURE.
912 *
913 * The error may be one of the following values:
914 * NSS_ERROR_INVALID_POINTER
915 *
916 * Return value:
917 * PR_SUCCESS
918 * PR_FAILURE
919 */
920
921 NSS_IMPLEMENT PRStatus
922 nss_ZFreeIf(void *pointer)
923 {
924 struct pointer_header *h;
925
926 if ((void *)NULL == pointer) {
927 return PR_SUCCESS;
928 }
929
930 h = (struct pointer_header *)((char *)pointer -
931 sizeof(struct pointer_header));
932
933 /* Check any magic here */
934
935 if ((NSSArena *)NULL == h->arena) {
936 /* Heap */
937 (void)nsslibc_memset(pointer, 0, h->size);
938 PR_Free(h);
939 return PR_SUCCESS;
940 } else {
941 /* Arena */
942 #ifdef NSSDEBUG
943 if (PR_SUCCESS != nssArena_verifyPointer(h->arena)) {
944 return PR_FAILURE;
945 }
946 #endif /* NSSDEBUG */
947
948 if ((PRLock *)NULL == h->arena->lock) {
949 /* Just got destroyed.. so this pointer is invalid */
950 nss_SetError(NSS_ERROR_INVALID_POINTER);
951 return PR_FAILURE;
952 }
953 PR_Lock(h->arena->lock);
954
955 (void)nsslibc_memset(pointer, 0, h->size);
956
957 /* No way to "free" it within an NSPR arena. */
958
959 PR_Unlock(h->arena->lock);
960 return PR_SUCCESS;
961 }
962 /*NOTREACHED*/
963 }
964
965 /*
966 * NSS_ZRealloc
967 *
968 * This routine reallocates a block of memory obtained by calling
969 * nss_ZAlloc or nss_ZRealloc. The portion of memory
970 * between the new and old sizes -- which is either being newly
971 * obtained or released -- is in either case zeroed. This routine
972 * may return NULL upon failure, in which case it will have placed
973 * an error on the error stack.
974 *
975 * The error may be one of the following values:
976 * NSS_ERROR_INVALID_POINTER
977 * NSS_ERROR_NO_MEMORY
978 * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
979 *
980 * Return value:
981 * NULL upon error
982 * A pointer to the replacement segment of memory
983 */
984
985 NSS_EXTERN void *
986 NSS_ZRealloc(void *pointer, PRUint32 newSize)
987 {
988 return nss_ZRealloc(pointer, newSize);
989 }
990
991 /*
992 * nss_ZRealloc
993 *
994 * This routine reallocates a block of memory obtained by calling
995 * nss_ZAlloc or nss_ZRealloc. The portion of memory
996 * between the new and old sizes -- which is either being newly
997 * obtained or released -- is in either case zeroed. This routine
998 * may return NULL upon failure, in which case it will have placed
999 * an error on the error stack.
1000 *
1001 * The error may be one of the following values:
1002 * NSS_ERROR_INVALID_POINTER
1003 * NSS_ERROR_NO_MEMORY
1004 * NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD
1005 *
1006 * Return value:
1007 * NULL upon error
1008 * A pointer to the replacement segment of memory
1009 */
1010
1011 NSS_EXTERN void *
1012 nss_ZRealloc(void *pointer, PRUint32 newSize)
1013 {
1014 NSSArena *arena;
1015 struct pointer_header *h, *new_h;
1016 PRUint32 my_newSize = newSize + sizeof(struct pointer_header);
1017 void *rv;
1018
1019 if (my_newSize < sizeof(struct pointer_header)) {
1020 /* Wrapped */
1021 nss_SetError(NSS_ERROR_NO_MEMORY);
1022 return (void *)NULL;
1023 }
1024
1025 if ((void *)NULL == pointer) {
1026 nss_SetError(NSS_ERROR_INVALID_POINTER);
1027 return (void *)NULL;
1028 }
1029
1030 h = (struct pointer_header *)((char *)pointer -
1031 sizeof(struct pointer_header));
1032
1033 /* Check any magic here */
1034
1035 if (newSize == h->size) {
1036 /* saves thrashing */
1037 return pointer;
1038 }
1039
1040 arena = h->arena;
1041 if (!arena) {
1042 /* Heap */
1043 new_h = (struct pointer_header *)PR_Calloc(1, my_newSize);
1044 if ((struct pointer_header *)NULL == new_h) {
1045 nss_SetError(NSS_ERROR_NO_MEMORY);
1046 return (void *)NULL;
1047 }
1048
1049 new_h->arena = (NSSArena *)NULL;
1050 new_h->size = newSize;
1051 rv = (void *)((char *)new_h + sizeof(struct pointer_header));
1052
1053 if (newSize > h->size) {
1054 (void)nsslibc_memcpy(rv, pointer, h->size);
1055 (void)nsslibc_memset(&((char *)rv)[h->size], 0,
1056 (newSize - h->size));
1057 } else {
1058 (void)nsslibc_memcpy(rv, pointer, newSize);
1059 }
1060
1061 (void)nsslibc_memset(pointer, 0, h->size);
1062 h->size = 0;
1063 PR_Free(h);
1064
1065 return rv;
1066 } else {
1067 void *p;
1068 /* Arena */
1069 #ifdef NSSDEBUG
1070 if (PR_SUCCESS != nssArena_verifyPointer(arena)) {
1071 return (void *)NULL;
1072 }
1073 #endif /* NSSDEBUG */
1074
1075 if (!arena->lock) {
1076 /* Just got destroyed.. so this pointer is invalid */
1077 nss_SetError(NSS_ERROR_INVALID_POINTER);
1078 return (void *)NULL;
1079 }
1080 PR_Lock(arena->lock);
1081
1082 #ifdef ARENA_THREADMARK
1083 if (arena->marking_thread) {
1084 if (PR_GetCurrentThread() != arena->marking_thread) {
1085 PR_Unlock(arena->lock);
1086 nss_SetError(NSS_ERROR_ARENA_MARKED_BY_ANOTHER_THREAD);
1087 return (void *)NULL;
1088 }
1089 }
1090 #endif /* ARENA_THREADMARK */
1091
1092 if (newSize < h->size) {
1093 /*
1094 * We have no general way of returning memory to the arena
1095 * (mark/release doesn't work because things may have been
1096 * allocated after this object), so the memory is gone
1097 * anyway. We might as well just return the same pointer to
1098 * the user, saying "yeah, uh-hunh, you can only use less of
1099 * it now." We'll zero the leftover part, of course. And
1100 * in fact we might as well *not* adjust h->size-- this way,
1101 * if the user reallocs back up to something not greater than
1102 * the original size, then voila, there's the memory! This
1103 * way a thrash big/small/big/small doesn't burn up the arena.
1104 */
1105 char *extra = &((char *)pointer)[newSize];
1106 (void)nsslibc_memset(extra, 0, (h->size - newSize));
1107 PR_Unlock(arena->lock);
1108 return pointer;
1109 }
1110
1111 PL_ARENA_ALLOCATE(p, &arena->pool, my_newSize);
1112 if ((void *)NULL == p) {
1113 PR_Unlock(arena->lock);
1114 nss_SetError(NSS_ERROR_NO_MEMORY);
1115 return (void *)NULL;
1116 }
1117
1118 new_h = (struct pointer_header *)p;
1119 new_h->arena = arena;
1120 new_h->size = newSize;
1121 rv = (void *)((char *)new_h + sizeof(struct pointer_header));
1122 if (rv != pointer) {
1123 (void)nsslibc_memcpy(rv, pointer, h->size);
1124 (void)nsslibc_memset(pointer, 0, h->size);
1125 }
1126 (void)nsslibc_memset(&((char *)rv)[h->size], 0, (newSize - h->size));
1127 h->arena = (NSSArena *)NULL;
1128 h->size = 0;
1129 PR_Unlock(arena->lock);
1130 return rv;
1131 }
1132 /*NOTREACHED*/
1133 }
1134
1135 PRStatus
1136 nssArena_Shutdown(void)
1137 {
1138 PRStatus rv = PR_SUCCESS;
1139 #ifdef DEBUG
1140 rv = nssPointerTracker_finalize(&arena_pointer_tracker);
1141 #endif
1142 return rv;
1143 }
OLDNEW
« no previous file with comments | « nss/COPYING ('k') | nss/lib/base/base.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698