1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/src/malloc/prmem.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,694 @@ 1.4 +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 +** Thread safe versions of malloc, free, realloc, calloc and cfree. 1.11 +*/ 1.12 + 1.13 +#include "primpl.h" 1.14 + 1.15 +#ifdef _PR_ZONE_ALLOCATOR 1.16 + 1.17 +/* 1.18 +** The zone allocator code must use native mutexes and cannot 1.19 +** use PRLocks because PR_NewLock calls PR_Calloc, resulting 1.20 +** in cyclic dependency of initialization. 1.21 +*/ 1.22 + 1.23 +#include <string.h> 1.24 + 1.25 +union memBlkHdrUn; 1.26 + 1.27 +typedef struct MemoryZoneStr { 1.28 + union memBlkHdrUn *head; /* free list */ 1.29 + pthread_mutex_t lock; 1.30 + size_t blockSize; /* size of blocks on this free list */ 1.31 + PRUint32 locked; /* current state of lock */ 1.32 + PRUint32 contention; /* counter: had to wait for lock */ 1.33 + PRUint32 hits; /* allocated from free list */ 1.34 + PRUint32 misses; /* had to call malloc */ 1.35 + PRUint32 elements; /* on free list */ 1.36 +} MemoryZone; 1.37 + 1.38 +typedef union memBlkHdrUn { 1.39 + unsigned char filler[48]; /* fix the size of this beast */ 1.40 + struct memBlkHdrStr { 1.41 + union memBlkHdrUn *next; 1.42 + MemoryZone *zone; 1.43 + size_t blockSize; 1.44 + size_t requestedSize; 1.45 + PRUint32 magic; 1.46 + } s; 1.47 +} MemBlockHdr; 1.48 + 1.49 +#define MEM_ZONES 7 1.50 +#define THREAD_POOLS 11 /* prime number for modulus */ 1.51 +#define ZONE_MAGIC 0x0BADC0DE 1.52 + 1.53 +static MemoryZone zones[MEM_ZONES][THREAD_POOLS]; 1.54 + 1.55 +static PRBool use_zone_allocator = PR_FALSE; 1.56 + 1.57 +static void pr_ZoneFree(void *ptr); 1.58 + 1.59 +void 1.60 +_PR_DestroyZones(void) 1.61 +{ 1.62 + int i, j; 1.63 + 1.64 + if (!use_zone_allocator) 1.65 + return; 1.66 + 1.67 + for (j = 0; j < THREAD_POOLS; j++) { 1.68 + for (i = 0; i < MEM_ZONES; i++) { 1.69 + MemoryZone *mz = &zones[i][j]; 1.70 + pthread_mutex_destroy(&mz->lock); 1.71 + while (mz->head) { 1.72 + MemBlockHdr *hdr = mz->head; 1.73 + mz->head = hdr->s.next; /* unlink it */ 1.74 + free(hdr); 1.75 + mz->elements--; 1.76 + } 1.77 + } 1.78 + } 1.79 + use_zone_allocator = PR_FALSE; 1.80 +} 1.81 + 1.82 +/* 1.83 +** pr_FindSymbolInProg 1.84 +** 1.85 +** Find the specified data symbol in the program and return 1.86 +** its address. 1.87 +*/ 1.88 + 1.89 +#ifdef HAVE_DLL 1.90 + 1.91 +#if defined(USE_DLFCN) && !defined(NO_DLOPEN_NULL) 1.92 + 1.93 +#include <dlfcn.h> 1.94 + 1.95 +static void * 1.96 +pr_FindSymbolInProg(const char *name) 1.97 +{ 1.98 + void *h; 1.99 + void *sym; 1.100 + 1.101 + h = dlopen(0, RTLD_LAZY); 1.102 + if (h == NULL) 1.103 + return NULL; 1.104 + sym = dlsym(h, name); 1.105 + (void)dlclose(h); 1.106 + return sym; 1.107 +} 1.108 + 1.109 +#elif defined(USE_HPSHL) 1.110 + 1.111 +#include <dl.h> 1.112 + 1.113 +static void * 1.114 +pr_FindSymbolInProg(const char *name) 1.115 +{ 1.116 + shl_t h = NULL; 1.117 + void *sym; 1.118 + 1.119 + if (shl_findsym(&h, name, TYPE_DATA, &sym) == -1) 1.120 + return NULL; 1.121 + return sym; 1.122 +} 1.123 + 1.124 +#elif defined(USE_MACH_DYLD) || defined(NO_DLOPEN_NULL) 1.125 + 1.126 +static void * 1.127 +pr_FindSymbolInProg(const char *name) 1.128 +{ 1.129 + /* FIXME: not implemented */ 1.130 + return NULL; 1.131 +} 1.132 + 1.133 +#else 1.134 + 1.135 +#error "The zone allocator is not supported on this platform" 1.136 + 1.137 +#endif 1.138 + 1.139 +#else /* !defined(HAVE_DLL) */ 1.140 + 1.141 +static void * 1.142 +pr_FindSymbolInProg(const char *name) 1.143 +{ 1.144 + /* can't be implemented */ 1.145 + return NULL; 1.146 +} 1.147 + 1.148 +#endif /* HAVE_DLL */ 1.149 + 1.150 +void 1.151 +_PR_InitZones(void) 1.152 +{ 1.153 + int i, j; 1.154 + char *envp; 1.155 + PRBool *sym; 1.156 + 1.157 + if ((sym = (PRBool *)pr_FindSymbolInProg("nspr_use_zone_allocator")) != NULL) { 1.158 + use_zone_allocator = *sym; 1.159 + } else if ((envp = getenv("NSPR_USE_ZONE_ALLOCATOR")) != NULL) { 1.160 + use_zone_allocator = (atoi(envp) == 1); 1.161 + } 1.162 + 1.163 + if (!use_zone_allocator) 1.164 + return; 1.165 + 1.166 + for (j = 0; j < THREAD_POOLS; j++) { 1.167 + for (i = 0; i < MEM_ZONES; i++) { 1.168 + MemoryZone *mz = &zones[i][j]; 1.169 + int rv = pthread_mutex_init(&mz->lock, NULL); 1.170 + PR_ASSERT(0 == rv); 1.171 + if (rv != 0) { 1.172 + goto loser; 1.173 + } 1.174 + mz->blockSize = 16 << ( 2 * i); 1.175 + } 1.176 + } 1.177 + return; 1.178 + 1.179 +loser: 1.180 + _PR_DestroyZones(); 1.181 + return; 1.182 +} 1.183 + 1.184 +PR_IMPLEMENT(void) 1.185 +PR_FPrintZoneStats(PRFileDesc *debug_out) 1.186 +{ 1.187 + int i, j; 1.188 + 1.189 + for (j = 0; j < THREAD_POOLS; j++) { 1.190 + for (i = 0; i < MEM_ZONES; i++) { 1.191 + MemoryZone *mz = &zones[i][j]; 1.192 + MemoryZone zone = *mz; 1.193 + if (zone.elements || zone.misses || zone.hits) { 1.194 + PR_fprintf(debug_out, 1.195 +"pool: %d, zone: %d, size: %d, free: %d, hit: %d, miss: %d, contend: %d\n", 1.196 + j, i, zone.blockSize, zone.elements, 1.197 + zone.hits, zone.misses, zone.contention); 1.198 + } 1.199 + } 1.200 + } 1.201 +} 1.202 + 1.203 +static void * 1.204 +pr_ZoneMalloc(PRUint32 size) 1.205 +{ 1.206 + void *rv; 1.207 + unsigned int zone; 1.208 + size_t blockSize; 1.209 + MemBlockHdr *mb, *mt; 1.210 + MemoryZone *mz; 1.211 + 1.212 + /* Always allocate a non-zero amount of bytes */ 1.213 + if (size < 1) { 1.214 + size = 1; 1.215 + } 1.216 + for (zone = 0, blockSize = 16; zone < MEM_ZONES; ++zone, blockSize <<= 2) { 1.217 + if (size <= blockSize) { 1.218 + break; 1.219 + } 1.220 + } 1.221 + if (zone < MEM_ZONES) { 1.222 + pthread_t me = pthread_self(); 1.223 + unsigned int pool = (PRUptrdiff)me % THREAD_POOLS; 1.224 + PRUint32 wasLocked; 1.225 + mz = &zones[zone][pool]; 1.226 + wasLocked = mz->locked; 1.227 + pthread_mutex_lock(&mz->lock); 1.228 + mz->locked = 1; 1.229 + if (wasLocked) 1.230 + mz->contention++; 1.231 + if (mz->head) { 1.232 + mb = mz->head; 1.233 + PR_ASSERT(mb->s.magic == ZONE_MAGIC); 1.234 + PR_ASSERT(mb->s.zone == mz); 1.235 + PR_ASSERT(mb->s.blockSize == blockSize); 1.236 + PR_ASSERT(mz->blockSize == blockSize); 1.237 + 1.238 + mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); 1.239 + PR_ASSERT(mt->s.magic == ZONE_MAGIC); 1.240 + PR_ASSERT(mt->s.zone == mz); 1.241 + PR_ASSERT(mt->s.blockSize == blockSize); 1.242 + 1.243 + mz->hits++; 1.244 + mz->elements--; 1.245 + mz->head = mb->s.next; /* take off free list */ 1.246 + mz->locked = 0; 1.247 + pthread_mutex_unlock(&mz->lock); 1.248 + 1.249 + mt->s.next = mb->s.next = NULL; 1.250 + mt->s.requestedSize = mb->s.requestedSize = size; 1.251 + 1.252 + rv = (void *)(mb + 1); 1.253 + return rv; 1.254 + } 1.255 + 1.256 + mz->misses++; 1.257 + mz->locked = 0; 1.258 + pthread_mutex_unlock(&mz->lock); 1.259 + 1.260 + mb = (MemBlockHdr *)malloc(blockSize + 2 * (sizeof *mb)); 1.261 + if (!mb) { 1.262 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.263 + return NULL; 1.264 + } 1.265 + mb->s.next = NULL; 1.266 + mb->s.zone = mz; 1.267 + mb->s.magic = ZONE_MAGIC; 1.268 + mb->s.blockSize = blockSize; 1.269 + mb->s.requestedSize = size; 1.270 + 1.271 + mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); 1.272 + memcpy(mt, mb, sizeof *mb); 1.273 + 1.274 + rv = (void *)(mb + 1); 1.275 + return rv; 1.276 + } 1.277 + 1.278 + /* size was too big. Create a block with no zone */ 1.279 + blockSize = (size & 15) ? size + 16 - (size & 15) : size; 1.280 + mb = (MemBlockHdr *)malloc(blockSize + 2 * (sizeof *mb)); 1.281 + if (!mb) { 1.282 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.283 + return NULL; 1.284 + } 1.285 + mb->s.next = NULL; 1.286 + mb->s.zone = NULL; 1.287 + mb->s.magic = ZONE_MAGIC; 1.288 + mb->s.blockSize = blockSize; 1.289 + mb->s.requestedSize = size; 1.290 + 1.291 + mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); 1.292 + memcpy(mt, mb, sizeof *mb); 1.293 + 1.294 + rv = (void *)(mb + 1); 1.295 + return rv; 1.296 +} 1.297 + 1.298 + 1.299 +static void * 1.300 +pr_ZoneCalloc(PRUint32 nelem, PRUint32 elsize) 1.301 +{ 1.302 + PRUint32 size = nelem * elsize; 1.303 + void *p = pr_ZoneMalloc(size); 1.304 + if (p) { 1.305 + memset(p, 0, size); 1.306 + } 1.307 + return p; 1.308 +} 1.309 + 1.310 +static void * 1.311 +pr_ZoneRealloc(void *oldptr, PRUint32 bytes) 1.312 +{ 1.313 + void *rv; 1.314 + MemBlockHdr *mb; 1.315 + int ours; 1.316 + MemBlockHdr phony; 1.317 + 1.318 + if (!oldptr) 1.319 + return pr_ZoneMalloc(bytes); 1.320 + mb = (MemBlockHdr *)((char *)oldptr - (sizeof *mb)); 1.321 + if (mb->s.magic != ZONE_MAGIC) { 1.322 + /* Maybe this just came from ordinary malloc */ 1.323 +#ifdef DEBUG 1.324 + fprintf(stderr, 1.325 + "Warning: reallocing memory block %p from ordinary malloc\n", 1.326 + oldptr); 1.327 +#endif 1.328 + /* 1.329 + * We are going to realloc oldptr. If realloc succeeds, the 1.330 + * original value of oldptr will point to freed memory. So this 1.331 + * function must not fail after a successfull realloc call. We 1.332 + * must perform any operation that may fail before the realloc 1.333 + * call. 1.334 + */ 1.335 + rv = pr_ZoneMalloc(bytes); /* this may fail */ 1.336 + if (!rv) { 1.337 + return rv; 1.338 + } 1.339 + 1.340 + /* We don't know how big it is. But we can fix that. */ 1.341 + oldptr = realloc(oldptr, bytes); 1.342 + /* 1.343 + * If realloc returns NULL, this function loses the original 1.344 + * value of oldptr. This isn't a leak because the caller of 1.345 + * this function still has the original value of oldptr. 1.346 + */ 1.347 + if (!oldptr) { 1.348 + if (bytes) { 1.349 + PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); 1.350 + pr_ZoneFree(rv); 1.351 + return oldptr; 1.352 + } 1.353 + } 1.354 + phony.s.requestedSize = bytes; 1.355 + mb = &phony; 1.356 + ours = 0; 1.357 + } else { 1.358 + size_t blockSize = mb->s.blockSize; 1.359 + MemBlockHdr *mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); 1.360 + 1.361 + PR_ASSERT(mt->s.magic == ZONE_MAGIC); 1.362 + PR_ASSERT(mt->s.zone == mb->s.zone); 1.363 + PR_ASSERT(mt->s.blockSize == blockSize); 1.364 + 1.365 + if (bytes <= blockSize) { 1.366 + /* The block is already big enough. */ 1.367 + mt->s.requestedSize = mb->s.requestedSize = bytes; 1.368 + return oldptr; 1.369 + } 1.370 + ours = 1; 1.371 + rv = pr_ZoneMalloc(bytes); 1.372 + if (!rv) { 1.373 + return rv; 1.374 + } 1.375 + } 1.376 + 1.377 + if (oldptr && mb->s.requestedSize) 1.378 + memcpy(rv, oldptr, mb->s.requestedSize); 1.379 + if (ours) 1.380 + pr_ZoneFree(oldptr); 1.381 + else if (oldptr) 1.382 + free(oldptr); 1.383 + return rv; 1.384 +} 1.385 + 1.386 +static void 1.387 +pr_ZoneFree(void *ptr) 1.388 +{ 1.389 + MemBlockHdr *mb, *mt; 1.390 + MemoryZone *mz; 1.391 + size_t blockSize; 1.392 + PRUint32 wasLocked; 1.393 + 1.394 + if (!ptr) 1.395 + return; 1.396 + 1.397 + mb = (MemBlockHdr *)((char *)ptr - (sizeof *mb)); 1.398 + 1.399 + if (mb->s.magic != ZONE_MAGIC) { 1.400 + /* maybe this came from ordinary malloc */ 1.401 +#ifdef DEBUG 1.402 + fprintf(stderr, 1.403 + "Warning: freeing memory block %p from ordinary malloc\n", ptr); 1.404 +#endif 1.405 + free(ptr); 1.406 + return; 1.407 + } 1.408 + 1.409 + blockSize = mb->s.blockSize; 1.410 + mz = mb->s.zone; 1.411 + mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize); 1.412 + PR_ASSERT(mt->s.magic == ZONE_MAGIC); 1.413 + PR_ASSERT(mt->s.zone == mz); 1.414 + PR_ASSERT(mt->s.blockSize == blockSize); 1.415 + if (!mz) { 1.416 + PR_ASSERT(blockSize > 65536); 1.417 + /* This block was not in any zone. Just free it. */ 1.418 + free(mb); 1.419 + return; 1.420 + } 1.421 + PR_ASSERT(mz->blockSize == blockSize); 1.422 + wasLocked = mz->locked; 1.423 + pthread_mutex_lock(&mz->lock); 1.424 + mz->locked = 1; 1.425 + if (wasLocked) 1.426 + mz->contention++; 1.427 + mt->s.next = mb->s.next = mz->head; /* put on head of list */ 1.428 + mz->head = mb; 1.429 + mz->elements++; 1.430 + mz->locked = 0; 1.431 + pthread_mutex_unlock(&mz->lock); 1.432 +} 1.433 + 1.434 +PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size) 1.435 +{ 1.436 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.437 + 1.438 + return use_zone_allocator ? pr_ZoneMalloc(size) : malloc(size); 1.439 +} 1.440 + 1.441 +PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize) 1.442 +{ 1.443 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.444 + 1.445 + return use_zone_allocator ? 1.446 + pr_ZoneCalloc(nelem, elsize) : calloc(nelem, elsize); 1.447 +} 1.448 + 1.449 +PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size) 1.450 +{ 1.451 + if (!_pr_initialized) _PR_ImplicitInitialization(); 1.452 + 1.453 + return use_zone_allocator ? pr_ZoneRealloc(ptr, size) : realloc(ptr, size); 1.454 +} 1.455 + 1.456 +PR_IMPLEMENT(void) PR_Free(void *ptr) 1.457 +{ 1.458 + if (use_zone_allocator) 1.459 + pr_ZoneFree(ptr); 1.460 + else 1.461 + free(ptr); 1.462 +} 1.463 + 1.464 +#else /* !defined(_PR_ZONE_ALLOCATOR) */ 1.465 + 1.466 +/* 1.467 +** The PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free functions simply 1.468 +** call their libc equivalents now. This may seem redundant, but it 1.469 +** ensures that we are calling into the same runtime library. On 1.470 +** Win32, it is possible to have multiple runtime libraries (e.g., 1.471 +** objects compiled with /MD and /MDd) in the same process, and 1.472 +** they maintain separate heaps, which cannot be mixed. 1.473 +*/ 1.474 +PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size) 1.475 +{ 1.476 +#if defined (WIN16) 1.477 + return PR_MD_malloc( (size_t) size); 1.478 +#else 1.479 + return malloc(size); 1.480 +#endif 1.481 +} 1.482 + 1.483 +PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize) 1.484 +{ 1.485 +#if defined (WIN16) 1.486 + return PR_MD_calloc( (size_t)nelem, (size_t)elsize ); 1.487 + 1.488 +#else 1.489 + return calloc(nelem, elsize); 1.490 +#endif 1.491 +} 1.492 + 1.493 +PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size) 1.494 +{ 1.495 +#if defined (WIN16) 1.496 + return PR_MD_realloc( ptr, (size_t) size); 1.497 +#else 1.498 + return realloc(ptr, size); 1.499 +#endif 1.500 +} 1.501 + 1.502 +PR_IMPLEMENT(void) PR_Free(void *ptr) 1.503 +{ 1.504 +#if defined (WIN16) 1.505 + PR_MD_free( ptr ); 1.506 +#else 1.507 + free(ptr); 1.508 +#endif 1.509 +} 1.510 + 1.511 +#endif /* _PR_ZONE_ALLOCATOR */ 1.512 + 1.513 +/* 1.514 +** Complexity alert! 1.515 +** 1.516 +** If malloc/calloc/free (etc.) were implemented to use pr lock's then 1.517 +** the entry points could block when called if some other thread had the 1.518 +** lock. 1.519 +** 1.520 +** Most of the time this isn't a problem. However, in the case that we 1.521 +** are using the thread safe malloc code after PR_Init but before 1.522 +** PR_AttachThread has been called (on a native thread that nspr has yet 1.523 +** to be told about) we could get royally screwed if the lock was busy 1.524 +** and we tried to context switch the thread away. In this scenario 1.525 +** PR_CURRENT_THREAD() == NULL 1.526 +** 1.527 +** To avoid this unfortunate case, we use the low level locking 1.528 +** facilities for malloc protection instead of the slightly higher level 1.529 +** locking. This makes malloc somewhat faster so maybe it's a good thing 1.530 +** anyway. 1.531 +*/ 1.532 +#ifdef _PR_OVERRIDE_MALLOC 1.533 + 1.534 +/* Imports */ 1.535 +extern void *_PR_UnlockedMalloc(size_t size); 1.536 +extern void *_PR_UnlockedMemalign(size_t alignment, size_t size); 1.537 +extern void _PR_UnlockedFree(void *ptr); 1.538 +extern void *_PR_UnlockedRealloc(void *ptr, size_t size); 1.539 +extern void *_PR_UnlockedCalloc(size_t n, size_t elsize); 1.540 + 1.541 +static PRBool _PR_malloc_initialised = PR_FALSE; 1.542 + 1.543 +#ifdef _PR_PTHREADS 1.544 +static pthread_mutex_t _PR_MD_malloc_crustylock; 1.545 + 1.546 +#define _PR_Lock_Malloc() { \ 1.547 + if(PR_TRUE == _PR_malloc_initialised) { \ 1.548 + PRStatus rv; \ 1.549 + rv = pthread_mutex_lock(&_PR_MD_malloc_crustylock); \ 1.550 + PR_ASSERT(0 == rv); \ 1.551 + } 1.552 + 1.553 +#define _PR_Unlock_Malloc() if(PR_TRUE == _PR_malloc_initialised) { \ 1.554 + PRStatus rv; \ 1.555 + rv = pthread_mutex_unlock(&_PR_MD_malloc_crustylock); \ 1.556 + PR_ASSERT(0 == rv); \ 1.557 + } \ 1.558 + } 1.559 +#else /* _PR_PTHREADS */ 1.560 +static _MDLock _PR_MD_malloc_crustylock; 1.561 + 1.562 +#ifdef IRIX 1.563 +#define _PR_Lock_Malloc() { \ 1.564 + PRIntn _is; \ 1.565 + if(PR_TRUE == _PR_malloc_initialised) { \ 1.566 + if (_PR_MD_GET_ATTACHED_THREAD() && \ 1.567 + !_PR_IS_NATIVE_THREAD( \ 1.568 + _PR_MD_GET_ATTACHED_THREAD())) \ 1.569 + _PR_INTSOFF(_is); \ 1.570 + _PR_MD_LOCK(&_PR_MD_malloc_crustylock); \ 1.571 + } 1.572 + 1.573 +#define _PR_Unlock_Malloc() if(PR_TRUE == _PR_malloc_initialised) { \ 1.574 + _PR_MD_UNLOCK(&_PR_MD_malloc_crustylock); \ 1.575 + if (_PR_MD_GET_ATTACHED_THREAD() && \ 1.576 + !_PR_IS_NATIVE_THREAD( \ 1.577 + _PR_MD_GET_ATTACHED_THREAD())) \ 1.578 + _PR_INTSON(_is); \ 1.579 + } \ 1.580 + } 1.581 +#else /* IRIX */ 1.582 +#define _PR_Lock_Malloc() { \ 1.583 + PRIntn _is; \ 1.584 + if(PR_TRUE == _PR_malloc_initialised) { \ 1.585 + if (_PR_MD_CURRENT_THREAD() && \ 1.586 + !_PR_IS_NATIVE_THREAD( \ 1.587 + _PR_MD_CURRENT_THREAD())) \ 1.588 + _PR_INTSOFF(_is); \ 1.589 + _PR_MD_LOCK(&_PR_MD_malloc_crustylock); \ 1.590 + } 1.591 + 1.592 +#define _PR_Unlock_Malloc() if(PR_TRUE == _PR_malloc_initialised) { \ 1.593 + _PR_MD_UNLOCK(&_PR_MD_malloc_crustylock); \ 1.594 + if (_PR_MD_CURRENT_THREAD() && \ 1.595 + !_PR_IS_NATIVE_THREAD( \ 1.596 + _PR_MD_CURRENT_THREAD())) \ 1.597 + _PR_INTSON(_is); \ 1.598 + } \ 1.599 + } 1.600 +#endif /* IRIX */ 1.601 +#endif /* _PR_PTHREADS */ 1.602 + 1.603 +PR_IMPLEMENT(PRStatus) _PR_MallocInit(void) 1.604 +{ 1.605 + PRStatus rv = PR_SUCCESS; 1.606 + 1.607 + if( PR_TRUE == _PR_malloc_initialised ) return PR_SUCCESS; 1.608 + 1.609 +#ifdef _PR_PTHREADS 1.610 + { 1.611 + int status; 1.612 + pthread_mutexattr_t mattr; 1.613 + 1.614 + status = _PT_PTHREAD_MUTEXATTR_INIT(&mattr); 1.615 + PR_ASSERT(0 == status); 1.616 + status = _PT_PTHREAD_MUTEX_INIT(_PR_MD_malloc_crustylock, mattr); 1.617 + PR_ASSERT(0 == status); 1.618 + status = _PT_PTHREAD_MUTEXATTR_DESTROY(&mattr); 1.619 + PR_ASSERT(0 == status); 1.620 + } 1.621 +#else /* _PR_PTHREADS */ 1.622 + _MD_NEW_LOCK(&_PR_MD_malloc_crustylock); 1.623 +#endif /* _PR_PTHREADS */ 1.624 + 1.625 + if( PR_SUCCESS == rv ) 1.626 + { 1.627 + _PR_malloc_initialised = PR_TRUE; 1.628 + } 1.629 + 1.630 + return rv; 1.631 +} 1.632 + 1.633 +void *malloc(size_t size) 1.634 +{ 1.635 + void *p; 1.636 + _PR_Lock_Malloc(); 1.637 + p = _PR_UnlockedMalloc(size); 1.638 + _PR_Unlock_Malloc(); 1.639 + return p; 1.640 +} 1.641 + 1.642 +#if defined(IRIX) 1.643 +void *memalign(size_t alignment, size_t size) 1.644 +{ 1.645 + void *p; 1.646 + _PR_Lock_Malloc(); 1.647 + p = _PR_UnlockedMemalign(alignment, size); 1.648 + _PR_Unlock_Malloc(); 1.649 + return p; 1.650 +} 1.651 + 1.652 +void *valloc(size_t size) 1.653 +{ 1.654 + return(memalign(sysconf(_SC_PAGESIZE),size)); 1.655 +} 1.656 +#endif /* IRIX */ 1.657 + 1.658 +void free(void *ptr) 1.659 +{ 1.660 + _PR_Lock_Malloc(); 1.661 + _PR_UnlockedFree(ptr); 1.662 + _PR_Unlock_Malloc(); 1.663 +} 1.664 + 1.665 +void *realloc(void *ptr, size_t size) 1.666 +{ 1.667 + void *p; 1.668 + _PR_Lock_Malloc(); 1.669 + p = _PR_UnlockedRealloc(ptr, size); 1.670 + _PR_Unlock_Malloc(); 1.671 + return p; 1.672 +} 1.673 + 1.674 +void *calloc(size_t n, size_t elsize) 1.675 +{ 1.676 + void *p; 1.677 + _PR_Lock_Malloc(); 1.678 + p = _PR_UnlockedCalloc(n, elsize); 1.679 + _PR_Unlock_Malloc(); 1.680 + return p; 1.681 +} 1.682 + 1.683 +void cfree(void *p) 1.684 +{ 1.685 + _PR_Lock_Malloc(); 1.686 + _PR_UnlockedFree(p); 1.687 + _PR_Unlock_Malloc(); 1.688 +} 1.689 + 1.690 +void _PR_InitMem(void) 1.691 +{ 1.692 + PRStatus rv; 1.693 + rv = _PR_MallocInit(); 1.694 + PR_ASSERT(PR_SUCCESS == rv); 1.695 +} 1.696 + 1.697 +#endif /* _PR_OVERRIDE_MALLOC */