VirtualBox

Changeset 101914 in vbox


Ignore:
Timestamp:
Nov 7, 2023 8:37:15 AM (13 months ago)
Author:
vboxsync
Message:

libs/xpcom: Add the possibility to use IPRT RTSEMFASTMUTEX semaphores in nsAutoLock so we can convert code to IPRT, remove some debug only code which would make it more complicated, bugref:10545

Location:
trunk/src/libs/xpcom18a4/xpcom
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/libs/xpcom18a4/xpcom/build/nsXPComInit.cpp

    r101861 r101914  
    117117extern nsresult NS_CategoryManagerGetFactory( nsIFactory** );
    118118
    119 #ifdef DEBUG
    120 extern void _FreeAutoLockStatics();
    121 #endif
    122 
    123119static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID);
    124120static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID);
     
    876872    nsComponentManagerImpl::gComponentManager = nsnull;
    877873
    878 #ifdef DEBUG
    879     _FreeAutoLockStatics();
    880 #endif
    881 
    882874    ShutdownSpecialSystemDirectory();
    883875
  • trunk/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp

    r1 r101914  
    788788    if(!cnt)
    789789    {
    790         nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor());
     790        nsAutoMonitorCanBeNull lock(xptiInterfaceInfoManager::GetInfoMonitor());
    791791        LOG_INFO_MONITOR_ENTRY;
    792792       
  • trunk/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp

    r101905 r101914  
    3838#include "nsAutoLock.h"
    3939
    40 #ifdef DEBUG
    41 
    42 #include "plhash.h"
    43 #include "prprf.h"
    44 #include "prlock.h"
    45 #include "prthread.h"
    46 #include "nsDebug.h"
    47 #include "nsVoidArray.h"
    48 
    49 #ifdef NS_TRACE_MALLOC_XXX
    50 # include <stdio.h>
    51 # include "nsTraceMalloc.h"
    52 #endif
    53 
    54 static PRUintn      LockStackTPI = (PRUintn)-1;
    55 static PLHashTable* OrderTable = 0;
    56 static PRLock*      OrderTableLock = 0;
    57 
    58 static const char* const LockTypeNames[] = {"Lock", "Monitor", "CMonitor"};
    59 
    60 struct nsNamedVector : public nsVoidArray {
    61     const char* mName;
    62 
    63 #ifdef NS_TRACE_MALLOC_XXX
    64     // Callsites for the inner locks/monitors stored in our base nsVoidArray.
    65     // This array parallels our base nsVoidArray.
    66     nsVoidArray mInnerSites;
    67 #endif
    68 
    69     nsNamedVector(const char* name = 0, PRUint32 initialSize = 0)
    70         : nsVoidArray(initialSize),
    71           mName(name)
    72     {
    73     }
    74 };
    75 
    76 static void * PR_CALLBACK
    77 _hash_alloc_table(void *pool, PRSize size)
    78 {
    79     return operator new(size);
    80 }
    81 
    82 static void  PR_CALLBACK
    83 _hash_free_table(void *pool, void *item)
    84 {
    85     operator delete(item);
    86 }
    87 
    88 static PLHashEntry * PR_CALLBACK
    89 _hash_alloc_entry(void *pool, const void *key)
    90 {
    91     return new PLHashEntry;
    92 }
    93 
    94 /*
    95  * Because monitors and locks may be associated with an nsAutoLockBase,
    96  * without having had their associated nsNamedVector created explicitly in
    97  * nsAutoMonitor::NewMonitor/DeleteMonitor, we need to provide a freeEntry
    98  * PLHashTable hook, to avoid leaking nsNamedVectors which are replaced by
    99  * nsAutoMonitor::NewMonitor.
    100  *
    101  * There is still a problem with the OrderTable containing orphaned
    102  * nsNamedVector entries, for manually created locks wrapped by nsAutoLocks.
    103  * (there should be no manually created monitors wrapped by nsAutoMonitors:
    104  * you should use nsAutoMonitor::NewMonitor and nsAutoMonitor::DestroyMonitor
    105  * instead of PR_NewMonitor and PR_DestroyMonitor).  These lock vectors don't
    106  * strictly leak, as they are killed on shutdown, but there are unnecessary
    107  * named vectors in the hash table that outlive their associated locks.
    108  *
    109  * XXX so we should have nsLock, nsMonitor, etc. and strongly type their
    110  * XXX nsAutoXXX counterparts to take only the non-auto types as inputs
    111  */
    112 static void  PR_CALLBACK
    113 _hash_free_entry(void *pool, PLHashEntry *entry, PRUintn flag)
    114 {
    115     nsNamedVector* vec = (nsNamedVector*) entry->value;
    116     if (vec) {
    117         entry->value = 0;
    118         delete vec;
    119     }
    120     if (flag == HT_FREE_ENTRY)
    121         delete entry;
    122 }
    123 
    124 static const PLHashAllocOps _hash_alloc_ops = {
    125     _hash_alloc_table, _hash_free_table,
    126     _hash_alloc_entry, _hash_free_entry
    127 };
    128 
    129 PR_STATIC_CALLBACK(PRIntn)
    130 _purge_one(PLHashEntry* he, PRIntn cnt, void* arg)
    131 {
    132     nsNamedVector* vec = (nsNamedVector*) he->value;
    133 
    134     if (he->key == arg)
    135         return HT_ENUMERATE_REMOVE;
    136     vec->RemoveElement(arg);
    137     return HT_ENUMERATE_NEXT;
    138 }
    139 
    140 PR_STATIC_CALLBACK(void)
    141 OnMonitorRecycle(void* addr)
    142 {
    143     PR_Lock(OrderTableLock);
    144     PL_HashTableEnumerateEntries(OrderTable, _purge_one, addr);
    145     PR_Unlock(OrderTableLock);
    146 }
    147 
    148 PR_STATIC_CALLBACK(PLHashNumber)
    149 _hash_pointer(const void* key)
    150 {
    151     return PLHashNumber(NS_PTR_TO_INT32(key)) >> 2;
    152 }
    153 
    154 // Must be single-threaded here, early in primordial thread.
    155 static void InitAutoLockStatics()
    156 {
    157     (void) PR_NewThreadPrivateIndex(&LockStackTPI, 0);
    158     OrderTable = PL_NewHashTable(64, _hash_pointer,
    159                                  PL_CompareValues, PL_CompareValues,
    160                                  &_hash_alloc_ops, 0);
    161     if (OrderTable && !(OrderTableLock = PR_NewLock())) {
    162         PL_HashTableDestroy(OrderTable);
    163         OrderTable = 0;
    164     }
    165 }
    166 
    167 void _FreeAutoLockStatics()
    168 {
    169     PLHashTable* table = OrderTable;
    170     if (!table) return;
    171 
    172     // Called at shutdown, so we don't need to lock.
    173     PR_DestroyLock(OrderTableLock);
    174     OrderTableLock = 0;
    175     PL_HashTableDestroy(table);
    176     OrderTable = 0;
    177 }
    178 
    179 static nsNamedVector* GetVector(PLHashTable* table, const void* key)
    180 {
    181     PLHashNumber hash = _hash_pointer(key);
    182     PLHashEntry** hep = PL_HashTableRawLookup(table, hash, key);
    183     PLHashEntry* he = *hep;
    184     if (he)
    185         return (nsNamedVector*) he->value;
    186     nsNamedVector* vec = new nsNamedVector();
    187     if (vec)
    188         PL_HashTableRawAdd(table, hep, hash, key, vec);
    189     return vec;
    190 }
    191 
    192 // We maintain an acyclic graph in OrderTable, so recursion can't diverge.
    193 static PRBool Reachable(PLHashTable* table, const void* goal, const void* start)
    194 {
    195     PR_ASSERT(goal);
    196     PR_ASSERT(start);
    197     nsNamedVector* vec = GetVector(table, start);
    198     for (PRUint32 i = 0, n = vec->Count(); i < n; i++) {
    199         void* addr = vec->ElementAt(i);
    200         if (addr == goal || Reachable(table, goal, addr))
    201             return PR_TRUE;
    202     }
    203     return PR_FALSE;
    204 }
    205 
    206 static PRBool WellOrdered(const void* addr1, const void* addr2,
    207                           const void *callsite2, PRUint32* index2p,
    208                           nsNamedVector** vec1p, nsNamedVector** vec2p)
    209 {
    210     PRBool rv = PR_TRUE;
    211     PLHashTable* table = OrderTable;
    212     if (!table) return rv;
    213     PR_Lock(OrderTableLock);
    214 
    215     // Check whether we've already asserted (addr1 < addr2).
    216     nsNamedVector* vec1 = GetVector(table, addr1);
    217     if (vec1) {
    218         PRUint32 i, n;
    219 
    220         for (i = 0, n = vec1->Count(); i < n; i++)
    221             if (vec1->ElementAt(i) == addr2)
    222                 break;
    223 
    224         if (i == n) {
    225             // Now check for (addr2 < addr1) and return false if so.
    226             nsNamedVector* vec2 = GetVector(table, addr2);
    227             if (vec2) {
    228                 for (i = 0, n = vec2->Count(); i < n; i++) {
    229                     void* addri = vec2->ElementAt(i);
    230                     PR_ASSERT(addri);
    231                     if (addri == addr1 || Reachable(table, addr1, addri)) {
    232                         *index2p = i;
    233                         *vec1p = vec1;
    234                         *vec2p = vec2;
    235                         rv = PR_FALSE;
    236                         break;
    237                     }
    238                 }
    239 
    240                 if (rv) {
    241                     // Assert (addr1 < addr2) into the order table.
    242                     // XXX fix plvector/nsVector to use const void*
    243                     vec1->AppendElement((void*) addr2);
    244 #ifdef NS_TRACE_MALLOC_XXX
    245                     vec1->mInnerSites.AppendElement((void*) callsite2);
    246 #endif
    247                 }
    248             }
    249         }
    250     }
    251 
    252     PR_Unlock(OrderTableLock);
    253     return rv;
    254 }
    255 
    256 nsAutoLockBase::nsAutoLockBase(void* addr, nsAutoLockType type)
    257 {
    258     if (LockStackTPI == PRUintn(-1))
    259         InitAutoLockStatics();
    260 
    261     nsAutoLockBase* stackTop =
    262         (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI);
    263     if (stackTop) {
    264         if (stackTop->mAddr == addr) {
    265             // Ignore reentry: it's legal for monitors, and NSPR will assert
    266             // if you reenter a PRLock.
    267         } else if (!addr) {
    268             // Ignore null addresses: the caller promises not to use the
    269             // lock at all, and NSPR will assert if you enter it.
    270         } else {
    271             const void* node =
    272 #ifdef NS_TRACE_MALLOC_XXX
    273                 NS_GetStackTrace(1)
    274 #else
    275                 nsnull
    276 #endif
    277                 ;
    278             nsNamedVector* vec1;
    279             nsNamedVector* vec2;
    280             PRUint32 i2;
    281 
    282             if (!WellOrdered(stackTop->mAddr, addr, node, &i2, &vec1, &vec2)) {
    283                 char buf[128];
    284                 PR_snprintf(buf, sizeof buf,
    285                             "Potential deadlock between %s%s@%p and %s%s@%p",
    286                             vec1->mName ? vec1->mName : "",
    287                             LockTypeNames[stackTop->mType],
    288                             stackTop->mAddr,
    289                             vec2->mName ? vec2->mName : "",
    290                             LockTypeNames[type],
    291                             addr);
    292 #ifdef NS_TRACE_MALLOC_XXX
    293                 fprintf(stderr, "\n*** %s\n\nCurrent stack:\n", buf);
    294                 NS_DumpStackTrace(node, stderr);
    295 
    296                 fputs("\nPrevious stack:\n", stderr);
    297                 NS_DumpStackTrace(vec2->mInnerSites.ElementAt(i2), stderr);
    298                 putc('\n', stderr);
    299 #endif
    300                 NS_ERROR(buf);
    301             }
    302         }
    303     }
    304 
    305     mAddr = addr;
    306     mDown = stackTop;
    307     mType = type;
    308     if (mAddr)
    309         (void) PR_SetThreadPrivate(LockStackTPI, this);
    310 }
    311 
    312 nsAutoLockBase::~nsAutoLockBase()
    313 {
    314     if (mAddr)
    315         (void) PR_SetThreadPrivate(LockStackTPI, mDown);
    316 }
    317 
    318 void nsAutoLockBase::Show()
    319 {
    320     if (!mAddr)
    321         return;
    322     nsAutoLockBase* curr = (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI);
    323     nsAutoLockBase* prev = nsnull;
    324     while (curr != mDown) {
    325         prev = curr;
    326         curr = prev->mDown;
    327     }
    328     if (!prev)
    329         PR_SetThreadPrivate(LockStackTPI, this);
    330     else
    331         prev->mDown = this;
    332 }
    333 
    334 void nsAutoLockBase::Hide()
    335 {
    336     if (!mAddr)
    337         return;
    338     nsAutoLockBase* curr = (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI);
    339     nsAutoLockBase* prev = nsnull;
    340     while (curr != this) {
    341         prev = curr;
    342         curr = prev->mDown;
    343     }
    344     if (!prev)
    345         PR_SetThreadPrivate(LockStackTPI, mDown);
    346     else
    347         prev->mDown = mDown;
    348 }
    349 
    350 #endif /* DEBUG */
    351 
    35240PRMonitor* nsAutoMonitor::NewMonitor(const char* name)
    35341{
    35442    PRMonitor* mon = PR_NewMonitor();
    355 #ifdef DEBUG
    356     if (mon && OrderTable) {
    357         nsNamedVector* value = new nsNamedVector(name);
    358         if (value) {
    359             PR_Lock(OrderTableLock);
    360             PL_HashTableAdd(OrderTable, mon, value);
    361             PR_Unlock(OrderTableLock);
    362         }
    363     }
    364 #endif
    36543    return mon;
    36644}
     
    36846void nsAutoMonitor::DestroyMonitor(PRMonitor* mon)
    36947{
    370 #ifdef DEBUG
    371     if (OrderTable)
    372         OnMonitorRecycle(mon);
    373 #endif
    37448    PR_DestroyMonitor(mon);
    37549}
     
    37751void nsAutoMonitor::Enter()
    37852{
    379 #ifdef DEBUG
    380     if (!mAddr) {
    381         NS_ERROR("It is not legal to enter a null monitor");
    382         return;
    383     }
    384     nsAutoLockBase* stackTop =
    385         (nsAutoLockBase*) PR_GetThreadPrivate(LockStackTPI);
    386     NS_ASSERTION(stackTop == mDown, "non-LIFO nsAutoMonitor::Enter");
    387     mDown = stackTop;
    388     (void) PR_SetThreadPrivate(LockStackTPI, this);
    389 #endif
    39053    PR_EnterMonitor(mMonitor);
    39154    mLockCount += 1;
     
    39457void nsAutoMonitor::Exit()
    39558{
    396 #ifdef DEBUG
    397     if (!mAddr) {
    398         NS_ERROR("It is not legal to exit a null monitor");
    399         return;
    400     }
    401     (void) PR_SetThreadPrivate(LockStackTPI, mDown);
    402 #endif
    40359    PRStatus status = PR_ExitMonitor(mMonitor);
    404     NS_ASSERTION(status == PR_SUCCESS, "PR_ExitMonitor failed");
     60    AssertMsg(status == PR_SUCCESS, ("PR_ExitMonitor failed"));
    40561    mLockCount -= 1;
    40662}
  • trunk/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h

    r101905 r101914  
    111111#include "prlog.h"
    112112
     113#include <iprt/assert.h>
     114#include <iprt/semaphore.h>
     115
    113116/**
    114117 * nsAutoLockBase
     
    121124    enum nsAutoLockType {eAutoLock, eAutoMonitor, eAutoCMonitor};
    122125
    123 #ifdef DEBUG
    124     nsAutoLockBase(void* addr, nsAutoLockType type);
    125     ~nsAutoLockBase();
    126 
    127     void            Show();
    128     void            Hide();
    129 
    130     void*           mAddr;
    131     nsAutoLockBase* mDown;
    132     nsAutoLockType  mType;
    133 #else
    134126    nsAutoLockBase(void* addr, nsAutoLockType type) {}
    135127    ~nsAutoLockBase() {}
    136 
    137     void            Show() {}
    138     void            Hide() {}
    139 #endif
    140128};
    141129
     
    147135private:
    148136    PRLock* mLock;
     137    /** The IPRT fast mutex. */
     138    RTSEMFASTMUTEX m_hMtx;
    149139    PRBool mLocked;
    150140
     
    172162        : nsAutoLockBase(aLock, eAutoLock),
    173163          mLock(aLock),
     164          m_hMtx(NIL_RTSEMFASTMUTEX),
    174165          mLocked(PR_TRUE) {
    175166        PR_ASSERT(mLock);
     
    179170        PR_Lock(mLock);
    180171    }
    181    
     172
     173    nsAutoLock(RTSEMFASTMUTEX hMtx)
     174        : nsAutoLockBase(hMtx, eAutoLock),
     175          mLock(NULL),
     176          m_hMtx(hMtx),
     177          mLocked(PR_TRUE) {
     178        PR_ASSERT(mLock);
     179
     180        RTSemFastMutexRequest(m_hMtx);
     181    }
     182
    182183    ~nsAutoLock(void) {
    183184        if (mLocked)
    184             PR_Unlock(mLock);
     185        {
     186            if (m_hMtx != NIL_RTSEMFASTMUTEX)
     187                RTSemFastMutexRelease(m_hMtx);
     188            else
     189                PR_Unlock(mLock);
     190        }
    185191    }
    186192
     
    191197     **/ 
    192198    void lock() {
    193         Show();
    194199        PR_ASSERT(!mLocked);
    195         PR_Lock(mLock);
     200        if (m_hMtx != NIL_RTSEMFASTMUTEX)
     201            RTSemFastMutexRequest(m_hMtx);
     202        else
     203            PR_Lock(mLock);
    196204        mLocked = PR_TRUE;
    197205    }
     
    205213     void unlock() {
    206214        PR_ASSERT(mLocked);
    207         PR_Unlock(mLock);
     215        if (m_hMtx != NIL_RTSEMFASTMUTEX)
     216            RTSemFastMutexRelease(m_hMtx);
     217        else
     218            PR_Unlock(mLock);
    208219        mLocked = PR_FALSE;
    209         Hide();
    210220    }
    211221};
     
    213223#include "prmon.h"
    214224#include "nsError.h"
    215 #include "nsDebug.h"
    216225
    217226class NS_COM nsAutoMonitor : public nsAutoLockBase {
     
    242251          mMonitor(mon), mLockCount(0)
    243252    {
    244         NS_ASSERTION(mMonitor, "null monitor");
     253        AssertMsg(mMonitor, ("null monitor"));
    245254        if (mMonitor) {
    246255            PR_EnterMonitor(mMonitor);
     
    250259
    251260    ~nsAutoMonitor() {
    252         NS_ASSERTION(mMonitor, "null monitor");
     261        AssertMsg(mMonitor, ("null monitor"));
    253262        if (mMonitor && mLockCount) {
    254 #ifdef DEBUG
    255             PRStatus status =
    256 #endif
    257263            PR_ExitMonitor(mMonitor);
    258             NS_ASSERTION(status == PR_SUCCESS, "PR_ExitMonitor failed");
    259264        }
    260265    }
     
    317322};
    318323
     324
     325/**
     326 * Cut down version of the nsAutoMonitor where the passed monitor can be NULL.
     327 * Used in exactly one place because the regular nsAutoMonitor would assert in that place
     328 * during shutdown (see nsComponentManager::NS_GetServiceManager for an explanation while
     329 * the assertion is nothing to orry about actually).
     330 */
     331class NS_COM nsAutoMonitorCanBeNull : public nsAutoLockBase {
     332public:
     333
     334   
     335    /**
     336     * Constructor
     337     * The constructor locks the given monitor.  During destruction
     338     * the monitor will be unlocked.
     339     *
     340     * @param mon A valid PRMonitor* returned from
     341     *        nsAutoMonitor::NewMonitor().
     342     **/
     343    nsAutoMonitorCanBeNull(PRMonitor* mon)
     344        : nsAutoLockBase((void*)mon, eAutoMonitor),
     345          mMonitor(mon), mLockCount(0)
     346    {
     347        if (mMonitor) {
     348            PR_EnterMonitor(mMonitor);
     349            mLockCount = 1;
     350        }
     351    }
     352
     353    ~nsAutoMonitorCanBeNull() {
     354        if (mMonitor && mLockCount) {
     355            PR_ExitMonitor(mMonitor);
     356        }
     357    }
     358
     359private:
     360    PRMonitor*  mMonitor;
     361    PRInt32     mLockCount;
     362
     363    // Not meant to be implemented. This makes it a compiler error to
     364    // construct or assign an nsAutoLock object incorrectly.
     365    nsAutoMonitorCanBeNull(void);
     366    nsAutoMonitorCanBeNull(const nsAutoMonitorCanBeNull& /*aMon*/);
     367    nsAutoMonitorCanBeNull& operator =(const nsAutoMonitorCanBeNull& /*aMon*/);
     368
     369    // Not meant to be implemented. This makes it a compiler error to
     370    // attempt to create an nsAutoLock object on the heap.
     371    static void* operator new(size_t /*size*/) CPP_THROW_NEW;
     372    static void operator delete(void* /*memory*/);
     373};
     374
    319375#endif // nsAutoLock_h__
    320376
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette