Back to index

lightning-sunbird  0.9+nobinonly
prmem.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /*
00039 ** Thread safe versions of malloc, free, realloc, calloc and cfree.
00040 */
00041 
00042 #include "primpl.h"
00043 
00044 #ifdef _PR_ZONE_ALLOCATOR
00045 
00046 /*
00047 ** The zone allocator code must use native mutexes and cannot
00048 ** use PRLocks because PR_NewLock calls PR_Calloc, resulting
00049 ** in cyclic dependency of initialization.
00050 */
00051 
00052 #include <string.h>  
00053 
00054 union memBlkHdrUn;
00055 
00056 typedef struct MemoryZoneStr {
00057     union memBlkHdrUn    *head;         /* free list */
00058     pthread_mutex_t       lock;
00059     size_t                blockSize;    /* size of blocks on this free list */
00060     PRUint32              locked;       /* current state of lock */
00061     PRUint32              contention;   /* counter: had to wait for lock */
00062     PRUint32              hits;         /* allocated from free list */
00063     PRUint32              misses;       /* had to call malloc */
00064     PRUint32              elements;     /* on free list */
00065 } MemoryZone;
00066 
00067 typedef union memBlkHdrUn {
00068     unsigned char filler[48];  /* fix the size of this beast */
00069     struct memBlkHdrStr {
00070         union memBlkHdrUn    *next;
00071         MemoryZone           *zone;
00072         size_t                blockSize;
00073         size_t                requestedSize;
00074         PRUint32              magic;
00075     } s;
00076 } MemBlockHdr;
00077 
00078 #define MEM_ZONES     7
00079 #define THREAD_POOLS 11  /* prime number for modulus */
00080 #define ZONE_MAGIC  0x0BADC0DE
00081 
00082 static MemoryZone zones[MEM_ZONES][THREAD_POOLS];
00083 
00084 static PRBool use_zone_allocator = PR_FALSE;
00085 
00086 static void pr_ZoneFree(void *ptr);
00087 
00088 void
00089 _PR_DestroyZones(void)
00090 {   
00091     int i, j;
00092 
00093     if (!use_zone_allocator)
00094         return;
00095     
00096     for (j = 0; j < THREAD_POOLS; j++) {
00097         for (i = 0; i < MEM_ZONES; i++) {
00098             MemoryZone *mz = &zones[i][j];
00099             pthread_mutex_destroy(&mz->lock);
00100             while (mz->head) {
00101                 MemBlockHdr *hdr = mz->head;
00102                 mz->head = hdr->s.next;  /* unlink it */
00103                 free(hdr);
00104                 mz->elements--;
00105             }
00106         }
00107     } 
00108     use_zone_allocator = PR_FALSE;
00109 } 
00110 
00111 /*
00112 ** pr_FindSymbolInProg
00113 **
00114 ** Find the specified data symbol in the program and return
00115 ** its address.
00116 */
00117 
00118 #ifdef HAVE_DLL
00119 
00120 #ifdef USE_DLFCN
00121 
00122 #include <dlfcn.h>
00123 
00124 static void *
00125 pr_FindSymbolInProg(const char *name)
00126 {
00127     void *h;
00128     void *sym;
00129 
00130     h = dlopen(0, RTLD_LAZY);
00131     if (h == NULL)
00132         return NULL;
00133     sym = dlsym(h, name);
00134     (void)dlclose(h);
00135     return sym;
00136 }
00137 
00138 #elif defined(USE_HPSHL)
00139 
00140 #include <dl.h>
00141 
00142 static void *
00143 pr_FindSymbolInProg(const char *name)
00144 {
00145     shl_t h = NULL;
00146     void *sym;
00147 
00148     if (shl_findsym(&h, name, TYPE_DATA, &sym) == -1)
00149         return NULL;
00150     return sym;
00151 }
00152 
00153 #elif defined(USE_MACH_DYLD)
00154 
00155 static void *
00156 pr_FindSymbolInProg(const char *name)
00157 {
00158     /* FIXME: not implemented */
00159     return NULL;
00160 }
00161 
00162 #else
00163 
00164 #error "The zone allocator is not supported on this platform"
00165 
00166 #endif
00167 
00168 #else /* !defined(HAVE_DLL) */
00169 
00170 static void *
00171 pr_FindSymbolInProg(const char *name)
00172 {
00173     /* can't be implemented */
00174     return NULL;
00175 }
00176 
00177 #endif /* HAVE_DLL */
00178 
00179 void
00180 _PR_InitZones(void)
00181 {
00182     int i, j;
00183     char *envp;
00184     PRBool *sym;
00185 
00186     if ((sym = (PRBool *)pr_FindSymbolInProg("nspr_use_zone_allocator")) != NULL) {
00187         use_zone_allocator = *sym;
00188     } else if ((envp = getenv("NSPR_USE_ZONE_ALLOCATOR")) != NULL) {
00189         use_zone_allocator = (atoi(envp) == 1);
00190     }
00191 
00192     if (!use_zone_allocator)
00193         return;
00194 
00195     for (j = 0; j < THREAD_POOLS; j++) { 
00196         for (i = 0; i < MEM_ZONES; i++) {
00197             MemoryZone *mz = &zones[i][j];
00198             int rv = pthread_mutex_init(&mz->lock, NULL);
00199             PR_ASSERT(0 == rv);
00200             if (rv != 0) {
00201                 goto loser;
00202             } 
00203             mz->blockSize = 16 << ( 2 * i);
00204         }
00205     }
00206     return;
00207 
00208 loser:
00209     _PR_DestroyZones();
00210     return;
00211 }
00212 
00213 PR_IMPLEMENT(void)
00214 PR_FPrintZoneStats(PRFileDesc *debug_out)
00215 {
00216     int i, j;
00217 
00218     for (j = 0; j < THREAD_POOLS; j++) {
00219         for (i = 0; i < MEM_ZONES; i++) {
00220             MemoryZone   *mz   = &zones[i][j];
00221             MemoryZone    zone = *mz;
00222             if (zone.elements || zone.misses || zone.hits) {
00223                 PR_fprintf(debug_out,
00224 "pool: %d, zone: %d, size: %d, free: %d, hit: %d, miss: %d, contend: %d\n",
00225                     j, i, zone.blockSize, zone.elements,
00226                     zone.hits, zone.misses, zone.contention);
00227             }
00228        }
00229     }
00230 }
00231 
00232 static void *
00233 pr_ZoneMalloc(PRUint32 size)
00234 {
00235     void         *rv;
00236     unsigned int  zone;
00237     size_t        blockSize;
00238     MemBlockHdr  *mb, *mt;
00239     MemoryZone   *mz;
00240 
00241     /* Always allocate a non-zero amount of bytes */
00242     if (size < 1) {
00243         size = 1;
00244     }
00245     for (zone = 0, blockSize = 16; zone < MEM_ZONES; ++zone, blockSize <<= 2) {
00246         if (size <= blockSize) {
00247             break;
00248         }
00249     }
00250     if (zone < MEM_ZONES) {
00251         pthread_t me = pthread_self();
00252         unsigned int pool = (PRUptrdiff)me % THREAD_POOLS;
00253         PRUint32     wasLocked;
00254         mz = &zones[zone][pool];
00255         wasLocked = mz->locked;
00256         pthread_mutex_lock(&mz->lock);
00257         mz->locked = 1;
00258         if (wasLocked)
00259             mz->contention++;
00260         if (mz->head) {
00261             mb = mz->head;
00262             PR_ASSERT(mb->s.magic == ZONE_MAGIC);
00263             PR_ASSERT(mb->s.zone  == mz);
00264             PR_ASSERT(mb->s.blockSize == blockSize);
00265             PR_ASSERT(mz->blockSize == blockSize);
00266 
00267             mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
00268             PR_ASSERT(mt->s.magic == ZONE_MAGIC);
00269             PR_ASSERT(mt->s.zone  == mz);
00270             PR_ASSERT(mt->s.blockSize == blockSize);
00271 
00272             mz->hits++;
00273             mz->elements--;
00274             mz->head = mb->s.next;    /* take off free list */
00275             mz->locked = 0;
00276             pthread_mutex_unlock(&mz->lock);
00277 
00278             mt->s.next          = mb->s.next          = NULL;
00279             mt->s.requestedSize = mb->s.requestedSize = size;
00280 
00281             rv = (void *)(mb + 1);
00282             return rv;
00283         }
00284 
00285         mz->misses++;
00286         mz->locked = 0;
00287         pthread_mutex_unlock(&mz->lock);
00288 
00289         mb = (MemBlockHdr *)malloc(blockSize + 2 * (sizeof *mb));
00290         if (!mb) {
00291             PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00292             return NULL;
00293         }
00294         mb->s.next          = NULL;
00295         mb->s.zone          = mz;
00296         mb->s.magic         = ZONE_MAGIC;
00297         mb->s.blockSize     = blockSize;
00298         mb->s.requestedSize = size;
00299 
00300         mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
00301         memcpy(mt, mb, sizeof *mb);
00302 
00303         rv = (void *)(mb + 1);
00304         return rv;
00305     }
00306 
00307     /* size was too big.  Create a block with no zone */
00308     blockSize = (size & 15) ? size + 16 - (size & 15) : size;
00309     mb = (MemBlockHdr *)malloc(blockSize + 2 * (sizeof *mb));
00310     if (!mb) {
00311         PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00312         return NULL;
00313     }
00314     mb->s.next          = NULL;
00315     mb->s.zone          = NULL;
00316     mb->s.magic         = ZONE_MAGIC;
00317     mb->s.blockSize     = blockSize;
00318     mb->s.requestedSize = size;
00319 
00320     mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
00321     memcpy(mt, mb, sizeof *mb);
00322 
00323     rv = (void *)(mb + 1);
00324     return rv;
00325 }
00326 
00327 
00328 static void *
00329 pr_ZoneCalloc(PRUint32 nelem, PRUint32 elsize)
00330 {
00331     PRUint32 size = nelem * elsize;
00332     void *p = pr_ZoneMalloc(size);
00333     if (p) {
00334         memset(p, 0, size);
00335     }
00336     return p;
00337 }
00338 
00339 static void *
00340 pr_ZoneRealloc(void *oldptr, PRUint32 bytes)
00341 {
00342     void         *rv;
00343     MemBlockHdr  *mb;
00344     int           ours;
00345     MemBlockHdr   phony;
00346 
00347     if (!oldptr)
00348         return pr_ZoneMalloc(bytes);
00349     mb = (MemBlockHdr *)((char *)oldptr - (sizeof *mb));
00350     if (mb->s.magic != ZONE_MAGIC) {
00351         /* Maybe this just came from ordinary malloc */
00352 #ifdef DEBUG
00353         fprintf(stderr,
00354             "Warning: reallocing memory block %p from ordinary malloc\n",
00355             oldptr);
00356 #endif
00357         /*
00358          * We are going to realloc oldptr.  If realloc succeeds, the
00359          * original value of oldptr will point to freed memory.  So this
00360          * function must not fail after a successfull realloc call.  We
00361          * must perform any operation that may fail before the realloc
00362          * call.
00363          */
00364         rv = pr_ZoneMalloc(bytes);  /* this may fail */
00365         if (!rv) {
00366             return rv;
00367         }
00368 
00369         /* We don't know how big it is.  But we can fix that. */
00370         oldptr = realloc(oldptr, bytes);
00371         /*
00372          * If realloc returns NULL, this function loses the original
00373          * value of oldptr.  This isn't a leak because the caller of
00374          * this function still has the original value of oldptr.
00375          */
00376         if (!oldptr) {
00377             if (bytes) {
00378                 PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0);
00379                 pr_ZoneFree(rv);
00380                 return oldptr;
00381             }
00382         }
00383         phony.s.requestedSize = bytes;
00384         mb = &phony;
00385         ours = 0;
00386     } else {
00387         size_t blockSize = mb->s.blockSize;
00388         MemBlockHdr *mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
00389 
00390         PR_ASSERT(mt->s.magic == ZONE_MAGIC);
00391         PR_ASSERT(mt->s.zone  == mb->s.zone);
00392         PR_ASSERT(mt->s.blockSize == blockSize);
00393        
00394         if (bytes <= blockSize) {
00395             /* The block is already big enough. */
00396             mt->s.requestedSize = mb->s.requestedSize = bytes;
00397             return oldptr;
00398         }
00399         ours = 1;
00400         rv = pr_ZoneMalloc(bytes);
00401         if (!rv) {
00402             return rv;
00403         }
00404     }
00405     
00406     if (oldptr && mb->s.requestedSize)
00407         memcpy(rv, oldptr, mb->s.requestedSize);
00408     if (ours)
00409         pr_ZoneFree(oldptr);
00410     else if (oldptr)
00411         free(oldptr);
00412     return rv;
00413 }
00414 
00415 static void
00416 pr_ZoneFree(void *ptr)
00417 {
00418     MemBlockHdr  *mb, *mt;
00419     MemoryZone   *mz;
00420     size_t        blockSize;
00421     PRUint32      wasLocked;
00422 
00423     if (!ptr)
00424         return;
00425 
00426     mb = (MemBlockHdr *)((char *)ptr - (sizeof *mb));
00427 
00428     if (mb->s.magic != ZONE_MAGIC) {
00429         /* maybe this came from ordinary malloc */
00430 #ifdef DEBUG
00431         fprintf(stderr,
00432             "Warning: freeing memory block %p from ordinary malloc\n", ptr);
00433 #endif
00434         free(ptr);
00435         return;
00436     }
00437 
00438     blockSize = mb->s.blockSize;
00439     mz        = mb->s.zone;
00440     mt = (MemBlockHdr *)(((char *)(mb + 1)) + blockSize);
00441     PR_ASSERT(mt->s.magic == ZONE_MAGIC);
00442     PR_ASSERT(mt->s.zone  == mz);
00443     PR_ASSERT(mt->s.blockSize == blockSize);
00444     if (!mz) {
00445         PR_ASSERT(blockSize > 65536);
00446         /* This block was not in any zone.  Just free it. */
00447         free(mb);
00448         return;
00449     }
00450     PR_ASSERT(mz->blockSize == blockSize);
00451     wasLocked = mz->locked;
00452     pthread_mutex_lock(&mz->lock);
00453     mz->locked = 1;
00454     if (wasLocked)
00455         mz->contention++;
00456     mt->s.next = mb->s.next = mz->head;        /* put on head of list */
00457     mz->head = mb;
00458     mz->elements++;
00459     mz->locked = 0;
00460     pthread_mutex_unlock(&mz->lock);
00461 }
00462 
00463 PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size)
00464 {
00465     if (!_pr_initialized) _PR_ImplicitInitialization();
00466 
00467     return use_zone_allocator ? pr_ZoneMalloc(size) : malloc(size);
00468 }
00469 
00470 PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize)
00471 {
00472     if (!_pr_initialized) _PR_ImplicitInitialization();
00473 
00474     return use_zone_allocator ?
00475         pr_ZoneCalloc(nelem, elsize) : calloc(nelem, elsize);
00476 }
00477 
00478 PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size)
00479 {
00480     if (!_pr_initialized) _PR_ImplicitInitialization();
00481 
00482     return use_zone_allocator ? pr_ZoneRealloc(ptr, size) : realloc(ptr, size);
00483 }
00484 
00485 PR_IMPLEMENT(void) PR_Free(void *ptr)
00486 {
00487     if (use_zone_allocator)
00488         pr_ZoneFree(ptr);
00489     else
00490         free(ptr);
00491 }
00492 
00493 #else /* !defined(_PR_ZONE_ALLOCATOR) */
00494 
00495 /*
00496 ** The PR_Malloc, PR_Calloc, PR_Realloc, and PR_Free functions simply
00497 ** call their libc equivalents now.  This may seem redundant, but it
00498 ** ensures that we are calling into the same runtime library.  On
00499 ** Win32, it is possible to have multiple runtime libraries (e.g.,
00500 ** objects compiled with /MD and /MDd) in the same process, and
00501 ** they maintain separate heaps, which cannot be mixed.
00502 */
00503 PR_IMPLEMENT(void *) PR_Malloc(PRUint32 size)
00504 {
00505 #if defined (WIN16)
00506     return PR_MD_malloc( (size_t) size);
00507 #else
00508     return malloc(size);
00509 #endif
00510 }
00511 
00512 PR_IMPLEMENT(void *) PR_Calloc(PRUint32 nelem, PRUint32 elsize)
00513 {
00514 #if defined (WIN16)
00515     return PR_MD_calloc( (size_t)nelem, (size_t)elsize );
00516     
00517 #else
00518     return calloc(nelem, elsize);
00519 #endif
00520 }
00521 
00522 PR_IMPLEMENT(void *) PR_Realloc(void *ptr, PRUint32 size)
00523 {
00524 #if defined (WIN16)
00525     return PR_MD_realloc( ptr, (size_t) size);
00526 #else
00527     return realloc(ptr, size);
00528 #endif
00529 }
00530 
00531 PR_IMPLEMENT(void) PR_Free(void *ptr)
00532 {
00533 #if defined (WIN16)
00534     PR_MD_free( ptr );
00535 #else
00536     free(ptr);
00537 #endif
00538 }
00539 
00540 #endif /* _PR_ZONE_ALLOCATOR */
00541 
00542 /*
00543 ** Complexity alert!
00544 **
00545 ** If malloc/calloc/free (etc.) were implemented to use pr lock's then
00546 ** the entry points could block when called if some other thread had the
00547 ** lock.
00548 **
00549 ** Most of the time this isn't a problem. However, in the case that we
00550 ** are using the thread safe malloc code after PR_Init but before
00551 ** PR_AttachThread has been called (on a native thread that nspr has yet
00552 ** to be told about) we could get royally screwed if the lock was busy
00553 ** and we tried to context switch the thread away. In this scenario
00554 **     PR_CURRENT_THREAD() == NULL
00555 **
00556 ** To avoid this unfortunate case, we use the low level locking
00557 ** facilities for malloc protection instead of the slightly higher level
00558 ** locking. This makes malloc somewhat faster so maybe it's a good thing
00559 ** anyway.
00560 */
00561 #ifdef _PR_OVERRIDE_MALLOC
00562 
00563 /* Imports */
00564 extern void *_PR_UnlockedMalloc(size_t size);
00565 extern void *_PR_UnlockedMemalign(size_t alignment, size_t size);
00566 extern void _PR_UnlockedFree(void *ptr);
00567 extern void *_PR_UnlockedRealloc(void *ptr, size_t size);
00568 extern void *_PR_UnlockedCalloc(size_t n, size_t elsize);
00569 
00570 static PRBool _PR_malloc_initialised = PR_FALSE;
00571 
00572 #ifdef _PR_PTHREADS
00573 static pthread_mutex_t _PR_MD_malloc_crustylock;
00574 
00575 #define _PR_Lock_Malloc() {                                    \
00576                             if(PR_TRUE == _PR_malloc_initialised) { \
00577                                    PRStatus rv;                \
00578                                    rv = pthread_mutex_lock(&_PR_MD_malloc_crustylock); \
00579                                    PR_ASSERT(0 == rv);         \
00580                             }
00581 
00582 #define _PR_Unlock_Malloc()        if(PR_TRUE == _PR_malloc_initialised) { \
00583                                    PRStatus rv;                \
00584                                    rv = pthread_mutex_unlock(&_PR_MD_malloc_crustylock); \
00585                                    PR_ASSERT(0 == rv);         \
00586                             }                                  \
00587                        }
00588 #else /* _PR_PTHREADS */
00589 static _MDLock _PR_MD_malloc_crustylock;
00590 
00591 #ifdef IRIX
00592 #define _PR_Lock_Malloc() {                                    \
00593                         PRIntn _is;                                   \
00594                             if(PR_TRUE == _PR_malloc_initialised) { \
00595                             if (_PR_MD_GET_ATTACHED_THREAD() &&              \
00596                                    !_PR_IS_NATIVE_THREAD(             \
00597                                    _PR_MD_GET_ATTACHED_THREAD()))     \
00598                                           _PR_INTSOFF(_is);    \
00599                                    _PR_MD_LOCK(&_PR_MD_malloc_crustylock); \
00600                             }
00601 
00602 #define _PR_Unlock_Malloc()        if(PR_TRUE == _PR_malloc_initialised) { \
00603                                    _PR_MD_UNLOCK(&_PR_MD_malloc_crustylock); \
00604                             if (_PR_MD_GET_ATTACHED_THREAD() &&              \
00605                                    !_PR_IS_NATIVE_THREAD(             \
00606                                    _PR_MD_GET_ATTACHED_THREAD()))     \
00607                                           _PR_INTSON(_is);     \
00608                             }                                  \
00609                        }
00610 #else  /* IRIX */
00611 #define _PR_Lock_Malloc() {                                    \
00612                         PRIntn _is;                                   \
00613                             if(PR_TRUE == _PR_malloc_initialised) { \
00614                             if (_PR_MD_CURRENT_THREAD() &&            \
00615                                    !_PR_IS_NATIVE_THREAD(             \
00616                                    _PR_MD_CURRENT_THREAD()))   \
00617                                           _PR_INTSOFF(_is);    \
00618                                    _PR_MD_LOCK(&_PR_MD_malloc_crustylock); \
00619                             }
00620 
00621 #define _PR_Unlock_Malloc()        if(PR_TRUE == _PR_malloc_initialised) { \
00622                                    _PR_MD_UNLOCK(&_PR_MD_malloc_crustylock); \
00623                             if (_PR_MD_CURRENT_THREAD() &&            \
00624                                    !_PR_IS_NATIVE_THREAD(             \
00625                                    _PR_MD_CURRENT_THREAD()))   \
00626                                           _PR_INTSON(_is);     \
00627                             }                                  \
00628                        }
00629 #endif /* IRIX       */
00630 #endif /* _PR_PTHREADS */
00631 
00632 PR_IMPLEMENT(PRStatus) _PR_MallocInit(void)
00633 {
00634     PRStatus rv = PR_SUCCESS;
00635 
00636     if( PR_TRUE == _PR_malloc_initialised ) return PR_SUCCESS;
00637 
00638 #ifdef _PR_PTHREADS
00639     {
00640        int status;
00641        pthread_mutexattr_t mattr;
00642 
00643        status = _PT_PTHREAD_MUTEXATTR_INIT(&mattr);
00644        PR_ASSERT(0 == status);
00645        status = _PT_PTHREAD_MUTEX_INIT(_PR_MD_malloc_crustylock, mattr);
00646        PR_ASSERT(0 == status);
00647        status = _PT_PTHREAD_MUTEXATTR_DESTROY(&mattr);
00648        PR_ASSERT(0 == status);
00649     }
00650 #else /* _PR_PTHREADS */
00651     _MD_NEW_LOCK(&_PR_MD_malloc_crustylock);
00652 #endif /* _PR_PTHREADS */
00653 
00654     if( PR_SUCCESS == rv )
00655     {
00656         _PR_malloc_initialised = PR_TRUE;
00657     }
00658 
00659     return rv;
00660 }
00661 
00662 void *malloc(size_t size)
00663 {
00664     void *p;
00665     _PR_Lock_Malloc();
00666     p = _PR_UnlockedMalloc(size);
00667     _PR_Unlock_Malloc();
00668     return p;
00669 }
00670 
00671 #if defined(IRIX)
00672 void *memalign(size_t alignment, size_t size)
00673 {
00674     void *p;
00675     _PR_Lock_Malloc();
00676     p = _PR_UnlockedMemalign(alignment, size);
00677     _PR_Unlock_Malloc();
00678     return p;
00679 }
00680 
00681 void *valloc(size_t size)
00682 {
00683     return(memalign(sysconf(_SC_PAGESIZE),size));
00684 }
00685 #endif /* IRIX */
00686 
00687 void free(void *ptr)
00688 {
00689     _PR_Lock_Malloc();
00690     _PR_UnlockedFree(ptr);
00691     _PR_Unlock_Malloc();
00692 }
00693 
00694 void *realloc(void *ptr, size_t size)
00695 {
00696     void *p;
00697     _PR_Lock_Malloc();
00698     p = _PR_UnlockedRealloc(ptr, size);
00699     _PR_Unlock_Malloc();
00700     return p;
00701 }
00702 
00703 void *calloc(size_t n, size_t elsize)
00704 {
00705     void *p;
00706     _PR_Lock_Malloc();
00707     p = _PR_UnlockedCalloc(n, elsize);
00708     _PR_Unlock_Malloc();
00709     return p;
00710 }
00711 
00712 void cfree(void *p)
00713 {
00714     _PR_Lock_Malloc();
00715     _PR_UnlockedFree(p);
00716     _PR_Unlock_Malloc();
00717 }
00718 
00719 void _PR_InitMem(void)
00720 {
00721     PRStatus rv;
00722     rv = _PR_MallocInit();
00723     PR_ASSERT(PR_SUCCESS == rv);
00724 }
00725 
00726 #endif /* _PR_OVERRIDE_MALLOC */