IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 31569


Ignore:
Timestamp:
May 26, 2011, 10:47:40 AM (15 years ago)
Author:
eugene
Message:

allow softlocks for improved psRealloc behavoir (disabled)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/eam_branches/ipp-20110505/psLib/src/sys/psMemory.c

    r31568 r31569  
    3535#include "psError.h"    // for psErrorStackPrint() only
    3636#include "psMemory.h"
     37#include "psAbort.h"
    3738
    3839// Magic number in psMemBlock header
     
    325326}
    326327
     328/** BLOCK_LOCK, BLOCK_UNLOCK, BLOCKSET_LOCK, BLOCKSET_UNLOCK are used to set per-memBlock locks
     329 **     to allow psRealloc to release the global lock before performing the expensive system
     330 **     call 'realloc'
     331 **/
     332
     333// if HARDLOCKS is set, revert to global locking for realloc
     334# define HARDLOCKS 1
     335
     336// memBlock->inFlight is a 'soft' lock.  if true, the lock is set
     337void BLOCK_LOCK (psMemBlock *memBlock, bool keepMutex) {
     338
     339# if (HARDLOCKS)
     340    MUTEX_LOCK(&memBlockListMutex);
     341# else
     342
     343    psAssert (memBlock || keepMutex, "trying to set a soft lock on a non-existent memBlock");
     344
     345    // if memBlock is not defined, we are just asking for a m
     346    if (!memBlock) {
     347        MUTEX_LOCK(&memBlockListMutex);
     348        return;
     349    }
     350       
     351    while (true) {
     352        // we cannot set the lock on the marker while the lock is held
     353        while (memBlock->inFlight) { usleep (10000); }
     354
     355        // set a lock, then lock this memblock and its neighbors
     356        MUTEX_LOCK(&memBlockListMutex);
     357   
     358        // did we beat the race condition?  is the lock still clear?
     359        if (memBlock->inFlight) {
     360            // nope, we need to try again
     361            MUTEX_UNLOCK(&memBlockListMutex);
     362            continue;
     363        }
     364
     365        // the marker is ours!
     366        memBlock->inFlight = true;
     367        if (keepMutex) return;
     368
     369        MUTEX_UNLOCK(&memBlockListMutex);
     370        return;
     371    }
     372# endif
     373}
     374
     375void BLOCK_UNLOCK (psMemBlock *memBlock, bool haveMutex) {
     376   
     377# if (HARDLOCKS)
     378    MUTEX_UNLOCK(&memBlockListMutex);
     379# else
     380
     381    psAssert (memBlock || haveMutex, "trying to clear a soft lock on a non-existent memBlock");
     382
     383    // if memBlock is not defined, we are just asking for a regular lock
     384    if (!memBlock) {
     385        MUTEX_UNLOCK(&memBlockListMutex);
     386        return;
     387    }
     388
     389    // need to lock before clearing the marker
     390    if (!haveMutex) {
     391        MUTEX_LOCK(&memBlockListMutex);
     392    }
     393    memBlock->inFlight = false;
     394    MUTEX_UNLOCK(&memBlockListMutex);
     395    return;
     396# endif   
     397}
     398
     399// attempt to grab the markers on the given memBlock and its two neighbors.  the only times the
     400// two neighbors do not exist is if we are at the beginning or end of the list (or the list is
     401// new).
     402void BLOCKSET_LOCK (psMemBlock *memBlock, bool keepMutex) {
     403
     404# if (HARDLOCKS)
     405    MUTEX_LOCK(&memBlockListMutex);
     406# else
     407
     408    psAssert (memBlock, "trying to set a soft lock on a non-existent memBlock");
     409
     410    while (true) {
     411        // we cannot set the lock on the marker while the lock is held
     412        // wait until all three markers are clear:
     413        while (memBlock->inFlight) { usleep (10000); }
     414        if (memBlock->nextBlock) {
     415            while (memBlock->nextBlock->inFlight) { usleep (10000); }
     416        }
     417        if (memBlock->previousBlock) {
     418            while (memBlock->previousBlock->inFlight) { usleep (10000); }
     419        }
     420
     421        // set a lock, then lock this memblock and its neighbors
     422        MUTEX_LOCK(&memBlockListMutex);
     423   
     424        // did we beat the race condition?  are all three locks still clear?
     425        if (memBlock->inFlight) {
     426            // nope, we need to try again
     427            MUTEX_UNLOCK(&memBlockListMutex);
     428            continue;
     429        }
     430        if (memBlock->nextBlock && memBlock->nextBlock->inFlight) {
     431            // nope, we need to try again
     432            MUTEX_UNLOCK(&memBlockListMutex);
     433            continue;
     434        }
     435        if (memBlock->previousBlock && memBlock->previousBlock->inFlight) {
     436            // nope, we need to try again
     437            MUTEX_UNLOCK(&memBlockListMutex);
     438            continue;
     439        }
     440
     441        // the markers are ours!
     442        memBlock->inFlight = true;
     443        if (memBlock->nextBlock) {
     444            memBlock->nextBlock->inFlight = true;
     445        }
     446        if (memBlock->previousBlock) {
     447            memBlock->previousBlock->inFlight = true;
     448        }
     449        if (keepMutex) return;
     450
     451        MUTEX_UNLOCK(&memBlockListMutex);
     452        return;
     453    }
     454# endif
     455}
     456
     457void BLOCKSET_UNLOCK (psMemBlock *memBlock, bool haveMutex) {
     458   
     459# if (HARDLOCKS)
     460    MUTEX_UNLOCK(&memBlockListMutex);
     461# else
     462
     463    // need to lock before clearing the marker
     464    if (!haveMutex) {
     465        MUTEX_LOCK(&memBlockListMutex);
     466    }
     467    memBlock->inFlight = false;
     468    if (memBlock->nextBlock) {
     469        memBlock->nextBlock->inFlight = false;
     470    }
     471    if (memBlock->previousBlock) {
     472        memBlock->previousBlock->inFlight = false;
     473    }
     474    MUTEX_UNLOCK(&memBlockListMutex);
     475    return;
     476# endif
     477}
     478
    327479// pointer to the last mem block that was allocated.
    328480// This is the root of the entire memory list
    329481static psMemBlock *lastMemBlockAllocated = NULL;
    330 static bool lastMemBlockInFlight = false;
    331482
    332483/* Actually allocate memory
     
    366517    // function
    367518    memBlock->func = func;
     519
     520    // per-block lock (off by default)
     521    memBlock->inFlight = false;
    368522
    369523    #if defined(PS_MEM_BACKTRACE) && defined(HAVE_BACKTRACE)
     
    397551    // need exclusive access of the memory block list now...
    398552    // this lock is very frequently called in a given program
    399     MUTEX_LOCK(&memBlockListMutex);
    400 
    401     // increment the memory id only after we've grabbed the memBlockListMutex
     553    // lastMemBlockAllocated is always true except the first allocation
     554    BLOCK_LOCK (lastMemBlockAllocated, true);
     555
     556    // increment the memory id only after we've grabbed the memBlockListMutex this value is
     557    // returned by psMemGetID and psMemGetLastID, but only ever modified here
    402558    *(psMemId* )&memBlock->id = ++memid;
    403559
     
    416572    }
    417573
    418     MUTEX_UNLOCK(&memBlockListMutex);
     574    BLOCK_UNLOCK (memBlock->nextBlock, true);
    419575
    420576    // And return the user the memory that they allocated
     
    562718    */
    563719
    564     // set a lock, then lock this memblock and its neighbors
    565     MUTEX_LOCK(&memBlockListMutex);
     720    // set a lock, then lock this memblock and its neighbors.  at the end of this call,
     721    // the global mutex is released, but the memBlock and its neighbors are protected
     722    BLOCKSET_LOCK (memBlock, false);
    566723
    567724    psMemBlock *nextBlock = memBlock->nextBlock;
     
    573730    bool isBlockLast = (memBlock == lastMemBlockAllocated);
    574731
    575     memBlock->inFlight = true;
    576     nextBlock->inFlight = true;
    577     previousBlock->inFlight = true;
    578     if (isBlockLast) lastMemBlockInFlight = true;
    579 
    580     MUTEX_UNLOCK(&memBlockListMutex);
    581 
    582     // now that the per-memBlock locks are set, we can unlock the threads and realloc the data
    583 
     732    // do the expensive system call.  other threads can continue to modify other memBlocks
     733    // except this one and its two neighbors
    584734    memBlock = (psMemBlock *)realloc(memBlock, sizeof(psMemBlock) + size + sizeof(void *));
    585735    if (memBlock == NULL) {
     
    616766
    617767    // all of the list modifications are done; set the lock and clear the per-memBlock locks
    618     MUTEX_LOCK(&memBlockListMutex);
    619     memBlock->inFlight = false;
    620     nextBlock->inFlight = false;
    621     previousBlock->inFlight = false;
    622     if (isBlockLast) lastMemBlockInFlight = false;
    623 
    624     MUTEX_UNLOCK(&memBlockListMutex);
     768    BLOCKSET_UNLOCK(memBlock, false);
     769
     770    psAssert (!memBlock->inFlight, "unreleased lock?");
     771    psAssert (!nextBlock || !nextBlock->inFlight, "unreleased lock?");
     772    psAssert (!previousBlock || !previousBlock->inFlight, "unreleased lock?");
    625773
    626774    return memBlock + 1;                    // usr memory
     
    848996    // if we have multiple references, just decrement the count and return.
    849997    // we need a MUTEX_LOCK here: otherwise, two functions can race on refCounter--;
    850     MUTEX_LOCK(&memBlockListMutex);
     998    BLOCK_LOCK (memBlock, true);
    851999    if (memBlock->refCounter > 1) {
    8521000        memBlock->refCounter--;
     
    8561004            memFreeID += memFreeCallback(memBlock);
    8571005        }
    858         MUTEX_UNLOCK(&memBlockListMutex);
     1006        BLOCK_UNLOCK(memBlock, true);
    8591007        return ptr;
    8601008    }
    861     MUTEX_UNLOCK(&memBlockListMutex);
     1009    BLOCK_UNLOCK(memBlock, true);
    8621010
    8631011    // we can't invoke freeFunc() while we're holding memBlockListMutex as it
     
    8681016
    8691017    // this lock is frequently set in a given program
    870     MUTEX_LOCK(&memBlockListMutex);
     1018    BLOCKSET_LOCK (memBlock, true);
    8711019
    8721020    // Did the user ask to be informed about this deallocation?
     
    8811029    if (nextBlock != NULL) {
    8821030        nextBlock->previousBlock = previousBlock;
     1031        nextBlock->inFlight = false;
    8831032    }
    8841033    if (previousBlock != NULL) {
    8851034        previousBlock->nextBlock = nextBlock;
     1035        previousBlock->inFlight = false;
    8861036    }
    8871037    if (lastMemBlockAllocated == memBlock) {
     
    8931043    memBlock->previousBlock = NULL;
    8941044
    895     MUTEX_UNLOCK(&memBlockListMutex);
     1045    BLOCKSET_UNLOCK (memBlock, true);
     1046
     1047    // XXX these are slightly dangerous : someone else may grab the lock in the meanwhile...
     1048    psAssert (!memBlock->inFlight, "unreleased lock?");
     1049    psAssert (!nextBlock || !nextBlock->inFlight, "unreleased lock?");
     1050    psAssert (!previousBlock || !previousBlock->inFlight, "unreleased lock?");
    8961051
    8971052    // invoke free only after we've released the block list lock as free()
Note: See TracChangeset for help on using the changeset viewer.