1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Netscape Portable Runtime (NSPR).
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998-2000
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /*
39 : ** Thread safe versions of malloc, free, realloc, calloc and cfree.
40 : */
41 :
42 : #include "primpl.h"
43 :
44 : #ifdef _PR_ZONE_ALLOCATOR
45 :
46 : /*
47 : ** The zone allocator code must use native mutexes and cannot
48 : ** use PRLocks because PR_NewLock calls PR_Calloc, resulting
49 : ** in cyclic dependency of initialization.
50 : */
51 :
52 : #include <string.h>
53 :
54 : union memBlkHdrUn;
55 :
56 : typedef struct MemoryZoneStr {
57 : union memBlkHdrUn *head; /* free list */
58 : pthread_mutex_t lock;
59 : size_t blockSize; /* size of blocks on this free list */
60 : PRUint32 locked; /* current state of lock */
61 : PRUint32 contention; /* counter: had to wait for lock */
62 : PRUint32 hits; /* allocated from free list */
63 : PRUint32 misses; /* had to call malloc */
64 : PRUint32 elements; /* on free list */
65 : } MemoryZone;
66 :
67 : typedef union memBlkHdrUn {
68 : unsigned char filler[48]; /* fix the size of this beast */
69 : struct memBlkHdrStr {
70 : union memBlkHdrUn *next;
71 : MemoryZone *zone;
72 : size_t blockSize;
73 : size_t requestedSize;
74 : PRUint32 magic;
75 : } s;
76 : } MemBlockHdr;
77 :
78 : #define MEM_ZONES 7
79 : #define THREAD_POOLS 11 /* prime number for modulus */
80 : #define ZONE_MAGIC 0x0BADC0DE
81 :
82 : static MemoryZone zones[MEM_ZONES][THREAD_POOLS];
83 :
84 : static PRBool use_zone_allocator = PR_FALSE;
85 :
86 : static void pr_ZoneFree(void *ptr);
87 :
88 : void
89 140 : _PR_DestroyZones(void)
90 : {
91 : int i, j;
92 :
93 140 : if (!use_zone_allocator)
94 140 : return;
95 :
96 0 : for (j = 0; j < THREAD_POOLS; j++) {
97 0 : for (i = 0; i < MEM_ZONES; i++) {
98 0 : MemoryZone *mz = &zones[i][j];
99 0 : pthread_mutex_destroy(&mz->lock);
100 0 : while (mz->head) {
101 0 : MemBlockHdr *hdr = mz->head;
102 0 : mz->head = hdr->s.next; /* unlink it */
103 0 : free(hdr);
104 0 : mz->elements--;
105 : }
106 : }
107 : }
108 0 : use_zone_allocator = PR_FALSE;
109 : }
110 :
111 : /*
112 : ** pr_FindSymbolInProg
113 : **
114 : ** Find the specified data symbol in the program and return
115 : ** its address.
116 : */
117 :
118 : #ifdef HAVE_DLL
119 :
120 : #if defined(USE_DLFCN) && !defined(NO_DLOPEN_NULL)
121 :
122 : #include <dlfcn.h>
123 :
124 : static void *
125 20034 : pr_FindSymbolInProg(const char *name)
126 : {
127 : void *h;
128 : void *sym;
129 :
130 20034 : h = dlopen(0, RTLD_LAZY);
131 20034 : if (h == NULL)
132 0 : return NULL;
133 20034 : sym = dlsym(h, name);
134 20034 : (void)dlclose(h);
135 20034 : return sym;
136 : }
137 :
138 : #elif defined(USE_HPSHL)
139 :
140 : #include <dl.h>
141 :
142 : static void *
143 : pr_FindSymbolInProg(const char *name)
144 : {
145 : shl_t h = NULL;
146 : void *sym;
147 :
148 : if (shl_findsym(&h, name, TYPE_DATA, &sym) == -1)
149 : return NULL;
150 : return sym;
151 : }
152 :
153 : #elif defined(USE_MACH_DYLD) || defined(NO_DLOPEN_NULL)
154 :
155 : static void *
156 : pr_FindSymbolInProg(const char *name)
157 : {
158 : /* FIXME: not implemented */
159 : return NULL;
160 : }
161 :
162 : #else
163 :
164 : #error "The zone allocator is not supported on this platform"
165 :
166 : #endif
167 :
168 : #else /* !defined(HAVE_DLL) */
169 :
170 : static void *
171 : pr_FindSymbolInProg(const char *name)
172 : {
173 : /* can't be implemented */
174 : return NULL;
175 : }
176 :
177 : #endif /* HAVE_DLL */
178 :
179 : void
180 20034 : _PR_InitZones(void)
181 : {
182 : int i, j;
183 : char *envp;
184 : PRBool *sym;
185 :
186 20034 : if ((sym = (PRBool *)pr_FindSymbolInProg("nspr_use_zone_allocator")) != NULL) {
187 1441 : use_zone_allocator = *sym;
188 18593 : } else if ((envp = getenv("NSPR_USE_ZONE_ALLOCATOR")) != NULL) {
189 0 : use_zone_allocator = (atoi(envp) == 1);
190 : }
191 :
192 20034 : if (!use_zone_allocator)
193 20034 : return;
194 :
195 0 : for (j = 0; j < THREAD_POOLS; j++) {
196 0 : for (i = 0; i < MEM_ZONES; i++) {
197 0 : MemoryZone *mz = &zones[i][j];
198 0 : int rv = pthread_mutex_init(&mz->lock, NULL);
199 0 : PR_ASSERT(0 == rv);
200 0 : if (rv != 0) {
201 0 : goto loser;
202 : }
203 0 : mz->blockSize = 16 << ( 2 * i);
204 : }
205 : }
206 0 : return;
207 :
208 : loser:
209 0 : _PR_DestroyZones();
210 0 : return;
211 : }
212 :
213 : PR_IMPLEMENT(void)
214 0 : PR_FPrintZoneStats(PRFileDesc *debug_out)
215 : {
216 : int i, j;
217 :
218 0 : for (j = 0; j < THREAD_POOLS; j++) {
219 0 : for (i = 0; i < MEM_ZONES; i++) {
220 0 : MemoryZone *mz = &zones[i][j];
221 0 : MemoryZone zone = *mz;
222 0 : if (zone.elements || zone.misses || zone.hits) {
223 0 : PR_fprintf(debug_out,
224 : "pool: %d, zone: %d, size: %d, free: %d, hit: %d, miss: %d, contend: %d\n",
225 : j, i, zone.blockSize, zone.elements,
226 : zone.hits, zone.misses, zone.contention);
227 : }
228 : }
229 : }
230 0 : }
231 :
232 : static void *
233 0 : pr_ZoneMalloc(PRUint32 size)
234 : {
235 : void *rv;
236 : unsigned int zone;
237 : size_t blockSize;
238 : MemBlockHdr *mb, *mt;
239 : MemoryZone *mz;
240 :
241 : /* Always allocate a non-zero amount of bytes */
242 0 : if (size < 1) {
243 0 : size = 1;
244 : }
245 0 : for (zone = 0, blockSize = 16; zone < MEM_ZONES; ++zone, blockSize <<= 2) {
246 0 : if (size <= blockSize) {
247 0 : break;
248 : }
249 : }
250 0 : if (zone < MEM_ZONES) {
251 0 : pthread_t me = pthread_self();
252 0 : unsigned int pool = (PRUptrdiff)me % THREAD_POOLS;
253 : PRUint32 wasLocked;
254 0 : mz = &zones[zone][pool];
255 0 : wasLocked = mz->locked;
256 0 : pthread_mutex_lock(&mz->lock);
257 0 : mz->locked = 1;
258 0 : if (wasLocked)
259 0 : mz->contention++;
260 0 : if (mz->head) {
261 0 : mb = mz->head;
262 0 : PR_ASSERT(mb->s.magic == ZONE_MAGIC);
263 0 : PR_ASSERT(mb->s.zone == mz);
264 0 : PR_ASSERT(mb->s.blockSize == blockSize);
265 0 : PR_ASSERT(mz->blockSize == blockSize);
266 :
267 0 : mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
268 0 : PR_ASSERT(mt->s.magic == ZONE_MAGIC);
269 0 : PR_ASSERT(mt->s.zone == mz);
270 0 : PR_ASSERT(mt->s.blockSize == blockSize);
271 :
272 0 : mz->hits++;
273 0 : mz->elements--;
274 0 : mz->head = mb->s.next; /* take off free list */
275 0 : mz->locked = 0;
276 0 : pthread_mutex_unlock(&mz->lock);
277 :
278 0 : mt->s.next = mb->s.next = NULL;
279 0 : mt->s.requestedSize = mb->s.requestedSize = size;
280 :
281 0 : rv = (void *)(mb + 1);
282 0 : return rv;
283 : }
284 :
285 0 : mz->misses++;
286 0 : mz->locked = 0;
287 0 : pthread_mutex_unlock(&mz->lock);
288 :
289 0 : mb = (MemBlockHdr *)malloc(blockSize + 2 * (sizeof *mb));
290 0 : if (!mb) {
291 0 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
292 0 : return NULL;
293 : }
294 0 : mb->s.next = NULL;
295 0 : mb->s.zone = mz;
296 0 : mb->s.magic = ZONE_MAGIC;
297 0 : mb->s.blockSize = blockSize;
298 0 : mb->s.requestedSize = size;
299 :
300 0 : mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
301 0 : memcpy(mt, mb, sizeof *mb);
302 :
303 0 : rv = (void *)(mb + 1);
304 0 : return rv;
305 : }
306 :
307 : /* size was too big. Create a block with no zone */
308 0 : blockSize = (size & 15) ? size + 16 - (size & 15) : size;
309 0 : mb = (MemBlockHdr *)malloc(blockSize + 2 * (sizeof *mb));
310 0 : if (!mb) {
311 0 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
312 0 : return NULL;
313 : }
314 0 : mb->s.next = NULL;
315 0 : mb->s.zone = NULL;
316 0 : mb->s.magic = ZONE_MAGIC;
317 0 : mb->s.blockSize = blockSize;
318 0 : mb->s.requestedSize = size;
319 :
320 0 : mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
321 0 : memcpy(mt, mb, sizeof *mb);
322 :
323 0 : rv = (void *)(mb + 1);
324 0 : return rv;
325 : }
326 :
327 :
328 : static void *
329 0 : pr_ZoneCalloc(PRUint32 nelem, PRUint32 elsize)
330 : {
331 0 : PRUint32 size = nelem * elsize;
332 0 : void *p = pr_ZoneMalloc(size);
333 0 : if (p) {
334 0 : memset(p, 0, size);
335 : }
336 0 : return p;
337 : }
338 :
339 : static void *
340 0 : pr_ZoneRealloc(void *oldptr, PRUint32 bytes)
341 : {
342 : void *rv;
343 : MemBlockHdr *mb;
344 : int ours;
345 : MemBlockHdr phony;
346 :
347 0 : if (!oldptr)
348 0 : return pr_ZoneMalloc(bytes);
349 0 : mb = (MemBlockHdr *)((char *)oldptr - (sizeof *mb));
350 0 : if (mb->s.magic != ZONE_MAGIC) {
351 : /* Maybe this just came from ordinary malloc */
352 : #ifdef DEBUG
353 0 : fprintf(stderr,
354 : "Warning: reallocing memory block %p from ordinary malloc\n",
355 : oldptr);
356 : #endif
357 : /*
358 : * We are going to realloc oldptr. If realloc succeeds, the
359 : * original value of oldptr will point to freed memory. So this
360 : * function must not fail after a successfull realloc call. We
361 : * must perform any operation that may fail before the realloc
362 : * call.
363 : */
364 0 : rv = pr_ZoneMalloc(bytes); /* this may fail */
365 0 : if (!rv) {
366 0 : return rv;
367 : }
368 :
369 : /* We don't know how big it is. But we can fix that. */
370 0 : oldptr = realloc(oldptr, bytes);
371 : /*
372 : * If realloc returns NULL, this function loses the original
373 : * value of oldptr. This isn't a leak because the caller of
374 : * this function still has the original value of oldptr.
375 : */
376 0 : if (!oldptr) {
377 0 : if (bytes) {
378 0 : PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
379 0 : pr_ZoneFree(rv);
380 0 : return oldptr;
381 : }
382 : }
383 0 : phony.s.requestedSize = bytes;
384 0 : mb = &phony;
385 0 : ours = 0;
386 : } else {
387 0 : size_t blockSize = mb->s.blockSize;
388 0 : MemBlockHdr *mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
389 :
390 0 : PR_ASSERT(mt->s.magic == ZONE_MAGIC);
391 0 : PR_ASSERT(mt->s.zone == mb->s.zone);
392 0 : PR_ASSERT(mt->s.blockSize == blockSize);
393 :
394 0 : if (bytes <= blockSize) {
395 : /* The block is already big enough. */
396 0 : mt->s.requestedSize = mb->s.requestedSize = bytes;
397 0 : return oldptr;
398 : }
399 0 : ours = 1;
400 0 : rv = pr_ZoneMalloc(bytes);
401 0 : if (!rv) {
402 0 : return rv;
403 : }
404 : }
405 :
406 0 : if (oldptr && mb->s.requestedSize)
407 0 : memcpy(rv, oldptr, mb->s.requestedSize);
408 0 : if (ours)
409 0 : pr_ZoneFree(oldptr);
410 0 : else if (oldptr)
411 0 : free(oldptr);
412 0 : return rv;
413 : }
414 :
415 : static void
416 0 : pr_ZoneFree(void *ptr)
417 : {
418 : MemBlockHdr *mb, *mt;
419 : MemoryZone *mz;
420 : size_t blockSize;
421 : PRUint32 wasLocked;
422 :
423 0 : if (!ptr)
424 0 : return;
425 :
426 0 : mb = (MemBlockHdr *)((char *)ptr - (sizeof *mb));
427 :
428 0 : if (mb->s.magic != ZONE_MAGIC) {
429 : /* maybe this came from ordinary malloc */
430 : #ifdef DEBUG
431 0 : fprintf(stderr,
432 : "Warning: freeing memory block %p from ordinary malloc\n", ptr);
433 : #endif
434 0 : free(ptr);
435 0 : return;
436 : }
437 :
438 0 : blockSize = mb->s.blockSize;
439 0 : mz = mb->s.zone;
440 0 : mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
441 0 : PR_ASSERT(mt->s.magic == ZONE_MAGIC);
442 0 : PR_ASSERT(mt->s.zone == mz);
443 0 : PR_ASSERT(mt->s.blockSize == blockSize);
444 0 : if (!mz) {
445 0 : PR_ASSERT(blockSize > 65536);
446 : /* This block was not in any zone. Just free it. */
447 0 : free(mb);
448 0 : return;
449 : }
450 0 : PR_ASSERT(mz->blockSize == blockSize);
451 0 : wasLocked = mz->locked;
452 0 : pthread_mutex_lock(&mz->lock);
453 0 : mz->locked = 1;
454 0 : if (wasLocked)
455 0 : mz->contention++;
456 0 : mt->s.next = mb->s.next = mz->head; /* put on head of list */
457 0 : mz->head = mb;
458 0 : mz->elements++;
459 0 : mz->locked = 0;
460 0 : pthread_mutex_unlock(&mz->lock);
461 : }
462 :
463 1751741 : PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size)
464 : {
465 1751741 : if (!_pr_initialized) _PR_ImplicitInitialization();
466 :
467 1751741 : return use_zone_allocator ? pr_ZoneMalloc(size) : malloc(size);
468 : }
469 :
470 2704668 : PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize)
471 : {
472 2704668 : if (!_pr_initialized) _PR_ImplicitInitialization();
473 :
474 5409336 : return use_zone_allocator ?
475 2704668 : pr_ZoneCalloc(nelem, elsize) : calloc(nelem, elsize);
476 : }
477 :
478 88394 : PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size)
479 : {
480 88394 : if (!_pr_initialized) _PR_ImplicitInitialization();
481 :
482 88394 : return use_zone_allocator ? pr_ZoneRealloc(ptr, size) : realloc(ptr, size);
483 : }
484 :
485 3667948 : PR_IMPLEMENT(void) PR_Free(void *ptr)
486 : {
487 3667948 : if (use_zone_allocator)
488 0 : pr_ZoneFree(ptr);
489 : else
490 3667948 : free(ptr);
491 3667948 : }
492 :
493 : #else /* !defined(_PR_ZONE_ALLOCATOR) */
494 :
495 : /*
496 : ** The PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free functions simply
497 : ** call their libc equivalents now. This may seem redundant, but it
498 : ** ensures that we are calling into the same runtime library. On
499 : ** Win32, it is possible to have multiple runtime libraries (e.g.,
500 : ** objects compiled with /MD and /MDd) in the same process, and
501 : ** they maintain separate heaps, which cannot be mixed.
502 : */
503 : PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size)
504 : {
505 : #if defined (WIN16)
506 : return PR_MD_malloc( (size_t) size);
507 : #else
508 : return malloc(size);
509 : #endif
510 : }
511 :
512 : PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize)
513 : {
514 : #if defined (WIN16)
515 : return PR_MD_calloc( (size_t)nelem, (size_t)elsize );
516 :
517 : #else
518 : return calloc(nelem, elsize);
519 : #endif
520 : }
521 :
522 : PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size)
523 : {
524 : #if defined (WIN16)
525 : return PR_MD_realloc( ptr, (size_t) size);
526 : #else
527 : return realloc(ptr, size);
528 : #endif
529 : }
530 :
531 : PR_IMPLEMENT(void) PR_Free(void *ptr)
532 : {
533 : #if defined (WIN16)
534 : PR_MD_free( ptr );
535 : #else
536 : free(ptr);
537 : #endif
538 : }
539 :
540 : #endif /* _PR_ZONE_ALLOCATOR */
541 :
542 : /*
543 : ** Complexity alert!
544 : **
545 : ** If malloc/calloc/free (etc.) were implemented to use pr lock's then
546 : ** the entry points could block when called if some other thread had the
547 : ** lock.
548 : **
549 : ** Most of the time this isn't a problem. However, in the case that we
550 : ** are using the thread safe malloc code after PR_Init but before
551 : ** PR_AttachThread has been called (on a native thread that nspr has yet
552 : ** to be told about) we could get royally screwed if the lock was busy
553 : ** and we tried to context switch the thread away. In this scenario
554 : ** PR_CURRENT_THREAD() == NULL
555 : **
556 : ** To avoid this unfortunate case, we use the low level locking
557 : ** facilities for malloc protection instead of the slightly higher level
558 : ** locking. This makes malloc somewhat faster so maybe it's a good thing
559 : ** anyway.
560 : */
561 : #ifdef _PR_OVERRIDE_MALLOC
562 :
563 : /* Imports */
564 : extern void *_PR_UnlockedMalloc(size_t size);
565 : extern void *_PR_UnlockedMemalign(size_t alignment, size_t size);
566 : extern void _PR_UnlockedFree(void *ptr);
567 : extern void *_PR_UnlockedRealloc(void *ptr, size_t size);
568 : extern void *_PR_UnlockedCalloc(size_t n, size_t elsize);
569 :
570 : static PRBool _PR_malloc_initialised = PR_FALSE;
571 :
572 : #ifdef _PR_PTHREADS
573 : static pthread_mutex_t _PR_MD_malloc_crustylock;
574 :
575 : #define _PR_Lock_Malloc() { \
576 : if(PR_TRUE == _PR_malloc_initialised) { \
577 : PRStatus rv; \
578 : rv = pthread_mutex_lock(&_PR_MD_malloc_crustylock); \
579 : PR_ASSERT(0 == rv); \
580 : }
581 :
582 : #define _PR_Unlock_Malloc() if(PR_TRUE == _PR_malloc_initialised) { \
583 : PRStatus rv; \
584 : rv = pthread_mutex_unlock(&_PR_MD_malloc_crustylock); \
585 : PR_ASSERT(0 == rv); \
586 : } \
587 : }
588 : #else /* _PR_PTHREADS */
589 : static _MDLock _PR_MD_malloc_crustylock;
590 :
591 : #ifdef IRIX
592 : #define _PR_Lock_Malloc() { \
593 : PRIntn _is; \
594 : if(PR_TRUE == _PR_malloc_initialised) { \
595 : if (_PR_MD_GET_ATTACHED_THREAD() && \
596 : !_PR_IS_NATIVE_THREAD( \
597 : _PR_MD_GET_ATTACHED_THREAD())) \
598 : _PR_INTSOFF(_is); \
599 : _PR_MD_LOCK(&_PR_MD_malloc_crustylock); \
600 : }
601 :
602 : #define _PR_Unlock_Malloc() if(PR_TRUE == _PR_malloc_initialised) { \
603 : _PR_MD_UNLOCK(&_PR_MD_malloc_crustylock); \
604 : if (_PR_MD_GET_ATTACHED_THREAD() && \
605 : !_PR_IS_NATIVE_THREAD( \
606 : _PR_MD_GET_ATTACHED_THREAD())) \
607 : _PR_INTSON(_is); \
608 : } \
609 : }
610 : #else /* IRIX */
611 : #define _PR_Lock_Malloc() { \
612 : PRIntn _is; \
613 : if(PR_TRUE == _PR_malloc_initialised) { \
614 : if (_PR_MD_CURRENT_THREAD() && \
615 : !_PR_IS_NATIVE_THREAD( \
616 : _PR_MD_CURRENT_THREAD())) \
617 : _PR_INTSOFF(_is); \
618 : _PR_MD_LOCK(&_PR_MD_malloc_crustylock); \
619 : }
620 :
621 : #define _PR_Unlock_Malloc() if(PR_TRUE == _PR_malloc_initialised) { \
622 : _PR_MD_UNLOCK(&_PR_MD_malloc_crustylock); \
623 : if (_PR_MD_CURRENT_THREAD() && \
624 : !_PR_IS_NATIVE_THREAD( \
625 : _PR_MD_CURRENT_THREAD())) \
626 : _PR_INTSON(_is); \
627 : } \
628 : }
629 : #endif /* IRIX */
630 : #endif /* _PR_PTHREADS */
631 :
632 : PR_IMPLEMENT(PRStatus) _PR_MallocInit(void)
633 : {
634 : PRStatus rv = PR_SUCCESS;
635 :
636 : if( PR_TRUE == _PR_malloc_initialised ) return PR_SUCCESS;
637 :
638 : #ifdef _PR_PTHREADS
639 : {
640 : int status;
641 : pthread_mutexattr_t mattr;
642 :
643 : status = _PT_PTHREAD_MUTEXATTR_INIT(&mattr);
644 : PR_ASSERT(0 == status);
645 : status = _PT_PTHREAD_MUTEX_INIT(_PR_MD_malloc_crustylock, mattr);
646 : PR_ASSERT(0 == status);
647 : status = _PT_PTHREAD_MUTEXATTR_DESTROY(&mattr);
648 : PR_ASSERT(0 == status);
649 : }
650 : #else /* _PR_PTHREADS */
651 : _MD_NEW_LOCK(&_PR_MD_malloc_crustylock);
652 : #endif /* _PR_PTHREADS */
653 :
654 : if( PR_SUCCESS == rv )
655 : {
656 : _PR_malloc_initialised = PR_TRUE;
657 : }
658 :
659 : return rv;
660 : }
661 :
662 : void *malloc(size_t size)
663 : {
664 : void *p;
665 : _PR_Lock_Malloc();
666 : p = _PR_UnlockedMalloc(size);
667 : _PR_Unlock_Malloc();
668 : return p;
669 : }
670 :
671 : #if defined(IRIX)
672 : void *memalign(size_t alignment, size_t size)
673 : {
674 : void *p;
675 : _PR_Lock_Malloc();
676 : p = _PR_UnlockedMemalign(alignment, size);
677 : _PR_Unlock_Malloc();
678 : return p;
679 : }
680 :
681 : void *valloc(size_t size)
682 : {
683 : return(memalign(sysconf(_SC_PAGESIZE),size));
684 : }
685 : #endif /* IRIX */
686 :
687 : void free(void *ptr)
688 : {
689 : _PR_Lock_Malloc();
690 : _PR_UnlockedFree(ptr);
691 : _PR_Unlock_Malloc();
692 : }
693 :
694 : void *realloc(void *ptr, size_t size)
695 : {
696 : void *p;
697 : _PR_Lock_Malloc();
698 : p = _PR_UnlockedRealloc(ptr, size);
699 : _PR_Unlock_Malloc();
700 : return p;
701 : }
702 :
703 : void *calloc(size_t n, size_t elsize)
704 : {
705 : void *p;
706 : _PR_Lock_Malloc();
707 : p = _PR_UnlockedCalloc(n, elsize);
708 : _PR_Unlock_Malloc();
709 : return p;
710 : }
711 :
712 : void cfree(void *p)
713 : {
714 : _PR_Lock_Malloc();
715 : _PR_UnlockedFree(p);
716 : _PR_Unlock_Malloc();
717 : }
718 :
719 : void _PR_InitMem(void)
720 : {
721 : PRStatus rv;
722 : rv = _PR_MallocInit();
723 : PR_ASSERT(PR_SUCCESS == rv);
724 : }
725 :
726 : #endif /* _PR_OVERRIDE_MALLOC */
|