nsprpub/pr/src/malloc/prmem.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial