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.

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

mercurial