LCOV - code coverage report
Current view: directory - nsprpub/pr/src/malloc - prmem.c (source / functions) Found Hit Coverage
Test: app.info Lines: 197 29 14.7 %
Date: 2012-06-02 Functions: 12 7 58.3 %

       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 */

Generated by: LCOV version 1.7