VirtualBox

Changeset 20932 in vbox for trunk


Ignore:
Timestamp:
Jun 25, 2009 12:27:02 PM (16 years ago)
Author:
vboxsync
Message:

Main/AutoLock: eliminate not entirely working custom windows implementation. IPRT based one works.

Location:
trunk/src/VBox/Main
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/AutoLock.cpp

    r16310 r20932  
    2020 */
    2121
    22 #ifdef VBOX_MAIN_AUTOLOCK_TRAP
    23 // workaround for compile problems on gcc 4.1
    24 # ifdef __GNUC__
    25 #  pragma GCC visibility push(default)
    26 # endif
    27 #endif
    28 
    2922#include "AutoLock.h"
    3023
     
    3326#include <iprt/string.h>
    3427
    35 #ifdef VBOX_MAIN_AUTOLOCK_TRAP
    36 # if defined (RT_OS_LINUX)
    37 #  include <signal.h>
    38 #  include <execinfo.h>
    39 /* get REG_EIP from ucontext.h */
    40 #  ifndef __USE_GNU
    41 #  define __USE_GNU
    42 #  endif
    43 #  include <ucontext.h>
    44 #  ifdef RT_ARCH_AMD64
    45 #   define REG_PC REG_RIP
    46 #  else
    47 #   define REG_PC REG_EIP
    48 #  endif
    49 # endif
    50 #endif /* VBOX_MAIN_AUTOLOCK_TRAP */
    5128
    5229namespace util
    5330{
    5431
    55 #ifdef VBOX_MAIN_AUTOLOCK_TRAP
    56 
    57 namespace internal
    58 {
    59 
    60 struct TLS
    61 {
    62     struct Uint32_t
    63     {
    64         Uint32_t() : raw (0) {}
    65         operator uint32_t &() { return raw; }
    66         uint32_t raw;
    67     };
    68 
    69     typedef std::map <RWLockHandle *, Uint32_t> HandleMap;
    70     HandleMap handles; /*< handle reference counter on the current thread */
    71 };
    72 
    73 /**
    74  * Global module initialization structure.
    75  *
    76  * The constructor and destructor of this structure are used to perform global
    77  * module initiaizaton and cleanup. Thee must be only one global variable of
    78  * this structure.
    79  */
    80 static
    81 class Global
    82 {
    83 public:
    84 
    85     Global() : tlsID (NIL_RTTLS)
    86     {
    87 #if defined (RT_OS_LINUX) /** @todo r=bird: Why only linux? All but windows supports destructors... */
    88         int vrc = RTTlsAllocEx (&tlsID, TLSDestructor);
    89         AssertRC (vrc);
    90 #else
    91         tlsID = RTTlsAlloc();
    92         Assert (tlsID != NIL_RTTLS);
    93 #endif
    94     }
    95 
    96     ~Global()
    97     {
    98         RTTlsFree (tlsID);
    99     }
    100 
    101     TLS *tls() const
    102     {
    103         TLS *tls = NULL;
    104         if (tlsID != NIL_RTTLS)
    105         {
    106             tls = static_cast <TLS *> (RTTlsGet (tlsID));
    107             if (tls == NULL)
    108             {
    109                 tls = new TLS();
    110                 RTTlsSet (tlsID, tls);
    111             }
    112         }
    113 
    114         return tls;
    115     }
    116 
    117     RTTLS tlsID;
    118 }
    119 gGlobal;
    120 
    121 DECLCALLBACK(void) TLSDestructor (void *aValue)
    122 {
    123     if (aValue != NULL)
    124     {
    125         TLS *tls = static_cast <TLS *> (aValue);
    126         RWLockHandle::TLSDestructor (tls);
    127         delete tls;
    128     }
    129 }
    130 
    131 } /* namespace internal */
    132 
    133 #endif /* VBOX_MAIN_AUTOLOCK_TRAP */
    134 
    135 
    13632RWLockHandle::RWLockHandle()
    13733{
    138 #ifdef VBOX_MAIN_USE_SEMRW
    139 
    14034    int vrc = RTSemRWCreate (&mSemRW);
    14135    AssertRC (vrc);
    142 
    143 #else /* !VBOX_MAIN_USE_SEMRW */
    144 
    145     int vrc = RTCritSectInit (&mCritSect);
    146     AssertRC (vrc);
    147     vrc = RTSemEventCreate (&mGoWriteSem);
    148     AssertRC (vrc);
    149     vrc = RTSemEventMultiCreate (&mGoReadSem);
    150     AssertRC (vrc);
    151 
    152     mWriteLockThread = NIL_RTNATIVETHREAD;
    153 
    154     mReadLockCount = 0;
    155     mSelfReadLockCount = 0;
    156 
    157     mWriteLockLevel = 0;
    158     mWriteLockPending = 0;
    159 
    160 #endif /* !VBOX_MAIN_USE_SEMRW */
    16136}
    16237
     
    16439RWLockHandle::~RWLockHandle()
    16540{
    166 #ifdef VBOX_MAIN_USE_SEMRW
    167 
    16841    RTSemRWDestroy (mSemRW);
    169 
    170 #else /* !VBOX_MAIN_USE_SEMRW */
    171 
    172     RTSemEventMultiDestroy (mGoReadSem);
    173     RTSemEventDestroy (mGoWriteSem);
    174     RTCritSectDelete (&mCritSect);
    175 
    176 #endif /* !VBOX_MAIN_USE_SEMRW */
    17742}
    17843
     
    18045bool RWLockHandle::isWriteLockOnCurrentThread() const
    18146{
    182 #ifdef VBOX_MAIN_USE_SEMRW
    183 
    18447    return RTSemRWIsWriteOwner (mSemRW);
    185 
    186 #else /* !VBOX_MAIN_USE_SEMRW */
    187 
    188     RTCritSectEnter (&mCritSect);
    189     bool locked = mWriteLockThread == RTThreadNativeSelf();
    190     RTCritSectLeave (&mCritSect);
    191     return locked;
    192 
    193 #endif /* !VBOX_MAIN_USE_SEMRW */
    19448}
    19549
     
    19751void RWLockHandle::lockWrite()
    19852{
    199 #ifdef VBOX_MAIN_USE_SEMRW
    200 
    20153    int vrc = RTSemRWRequestWrite (mSemRW, RT_INDEFINITE_WAIT);
    20254    AssertRC (vrc);
    203 
    204 #else /* !VBOX_MAIN_USE_SEMRW */
    205 
    206     RTCritSectEnter (&mCritSect);
    207 
    208     RTNATIVETHREAD threadSelf = RTThreadNativeSelf();
    209 
    210     if (mWriteLockThread != threadSelf)
    211     {
    212 # ifdef VBOX_MAIN_AUTOLOCK_TRAP
    213         if (mReadLockCount != 0)
    214         {
    215             using namespace internal;
    216             TLS *tls = gGlobal.tls();
    217             if (tls != NULL)
    218             {
    219                 TLS::HandleMap::const_iterator it = tls->handles.find (this);
    220                 if (it != tls->handles.end() && it->second.raw != 0)
    221                 {
    222                     /* if there is a writer then the handle reference counter equals
    223                      * to the number of readers on the current thread plus 1 */
    224 
    225                     uint32_t readers = it->second.raw;
    226                     if (mWriteLockThread != NIL_RTNATIVETHREAD)
    227                         -- readers;
    228 
    229                     std::string info;
    230                     gatherInfo (info);
    231 
    232                     AssertReleaseMsgFailedReturnVoid ((
    233                         "DETECTED SELF DEADLOCK on Thread %08x: lockWrite() after "
    234                         "lockRead(): reader count = %d!\n%s\n",
    235                         threadSelf, readers, info.c_str()));
    236                 }
    237             }
    238         }
    239 # endif /* VBOX_MAIN_AUTOLOCK_TRAP */
    240 
    241         if (mReadLockCount != 0 || mWriteLockThread != NIL_RTNATIVETHREAD ||
    242             mWriteLockPending != 0 /* respect other pending writers */)
    243         {
    244             /* wait until all read locks or another write lock is released */
    245             ++ mWriteLockPending;
    246             Assert (mWriteLockPending != 0 /* pending writer overflow? */);
    247             RTCritSectLeave (&mCritSect);
    248             RTSemEventWait (mGoWriteSem, RT_INDEFINITE_WAIT);
    249             RTCritSectEnter (&mCritSect);
    250             -- mWriteLockPending;
    251         }
    252 
    253         Assert (mWriteLockLevel == 0);
    254         Assert (mWriteLockThread == NIL_RTNATIVETHREAD);
    255         Assert (mSelfReadLockCount == 0 /* missing unlockRead()? */);
    256 
    257         mWriteLockThread = threadSelf;
    258     }
    259 
    260     ++ mWriteLockLevel;
    261     Assert (mWriteLockLevel != 0 /* overflow */);
    262 
    263 # ifdef VBOX_MAIN_AUTOLOCK_TRAP
    264     logOp (LockWrite);
    265 # endif
    266 
    267     RTCritSectLeave (&mCritSect);
    268 
    269 # ifdef DEBUG
    270     if (mWriteLockLevel == 1)
    271     {
    272         RTTHREAD iprtThreadSelf = RTThreadSelf();
    273         if (iprtThreadSelf != NIL_RTTHREAD)
    274             RTThreadWriteLockInc (iprtThreadSelf);
    275     }
    276 # endif
    277 
    278 #endif /* !VBOX_MAIN_USE_SEMRW */
    27955}
    28056
     
    28258void RWLockHandle::unlockWrite()
    28359{
    284 #ifdef VBOX_MAIN_USE_SEMRW
    285 
    28660    int vrc = RTSemRWReleaseWrite (mSemRW);
    28761    AssertRC (vrc);
    288 
    289 #else /* !VBOX_MAIN_USE_SEMRW */
    290 
    291     RTCritSectEnter (&mCritSect);
    292 
    293     RTNATIVETHREAD threadSelf = RTThreadNativeSelf();
    294 
    295     Assert (mWriteLockLevel != 0 /* unlockWrite() w/o preceding lockWrite()? */);
    296     if (mWriteLockLevel != 0)
    297     {
    298         Assert (mWriteLockThread == threadSelf
    299                 /* unlockWrite() w/o preceding lockWrite()? */);
    300         if (mWriteLockThread == threadSelf)
    301         {
    302             -- mWriteLockLevel;
    303             if (mWriteLockLevel == 0)
    304             {
    305                 Assert (mSelfReadLockCount == 0
    306                         /* mixed unlockWrite()/unlockRead() order? */);
    307 
    308                 mWriteLockThread = NIL_RTNATIVETHREAD;
    309 
    310                 /* no write locks, let writers go if there are any (top priority),
    311                  * otherwise let readers go if there are any */
    312                 if (mWriteLockPending != 0)
    313                     RTSemEventSignal (mGoWriteSem);
    314                 else if (mReadLockCount != 0)
    315                     RTSemEventMultiSignal (mGoReadSem);
    316 
    317 # ifdef DEBUG
    318                 RTTHREAD iprtThreadSelf = RTThreadSelf();
    319                 if (iprtThreadSelf != NIL_RTTHREAD)
    320                     RTThreadWriteLockDec (iprtThreadSelf);
    321 # endif
    322             }
    323         }
    324     }
    325 
    326 # ifdef VBOX_MAIN_AUTOLOCK_TRAP
    327     logOp (UnlockWrite);
    328 # endif
    329 
    330     RTCritSectLeave (&mCritSect);
    331 
    332 #endif /* !VBOX_MAIN_USE_SEMRW */
    33362}
    33463
     
    33665void RWLockHandle::lockRead()
    33766{
    338 #ifdef VBOX_MAIN_USE_SEMRW
    339 
    34067    int vrc = RTSemRWRequestRead (mSemRW, RT_INDEFINITE_WAIT);
    34168    AssertRC (vrc);
    342 
    343 #else /* !VBOX_MAIN_USE_SEMRW */
    344 
    345     RTCritSectEnter (&mCritSect);
    346 
    347     RTNATIVETHREAD threadSelf = RTThreadNativeSelf();
    348 
    349 # ifdef VBOX_MAIN_AUTOLOCK_TRAP
    350     logOp (LockRead);
    351 # endif /* VBOX_MAIN_AUTOLOCK_TRAP */
    352 
    353     bool isWriteLock = mWriteLockLevel != 0;
    354     bool isFirstReadLock = mReadLockCount == 0;
    355 
    356     if (isWriteLock && mWriteLockThread == threadSelf)
    357     {
    358         /* read lock nested into the write lock */
    359         ++ mSelfReadLockCount;
    360         Assert (mSelfReadLockCount != 0 /* self read lock overflow? */);
    361 
    362         /* cause to return immediately */
    363         isWriteLock = false;
    364     }
    365     else
    366     {
    367         ++ mReadLockCount;
    368         Assert (mReadLockCount != 0 /* read lock overflow? */);
    369 
    370         if (!isWriteLock)
    371         {
    372             Assert (mSelfReadLockCount == 0 /* missing unlockRead()? */);
    373 
    374             /* write locks are top priority, so let them go if they are
    375              * pending and we're the only reader so far */
    376             if (mWriteLockPending != 0 && isFirstReadLock)
    377             {
    378                 isWriteLock = true;
    379                 /* note that we must not signal mGoWriteSem here because it
    380                  * has been already signaled by unlockWrite() or by
    381                  * unlockRead() */
    382             }
    383         }
    384 
    385         /* the first waiting reader resets the semaphore before letting it be
    386          * posted (i.e. before leaving the critical section) */
    387         if (isWriteLock && isFirstReadLock)
    388             RTSemEventMultiReset (mGoReadSem);
    389     }
    390 
    391     RTCritSectLeave (&mCritSect);
    392 
    393     /* wait until the write lock is released */
    394     if (isWriteLock)
    395         RTSemEventMultiWait (mGoReadSem, RT_INDEFINITE_WAIT);
    396 
    397 # ifdef DEBUG
    398     RTTHREAD iprtThreadSelf = RTThreadSelf();
    399     if (iprtThreadSelf != NIL_RTTHREAD)
    400         RTThreadReadLockInc (iprtThreadSelf);
    401 # endif
    402 
    403 #endif /* !VBOX_MAIN_USE_SEMRW */
    40469}
    40570
     
    40772void RWLockHandle::unlockRead()
    40873{
    409 #ifdef VBOX_MAIN_USE_SEMRW
    410 
    41174    int vrc = RTSemRWReleaseRead (mSemRW);
    41275    AssertRC (vrc);
    413 
    414 #else /* !VBOX_MAIN_USE_SEMRW */
    415 
    416     RTCritSectEnter (&mCritSect);
    417 
    418     RTNATIVETHREAD threadSelf = RTThreadNativeSelf();
    419 
    420     if (mWriteLockLevel != 0)
    421     {
    422         /* read unlock nested into the write lock */
    423         Assert (mWriteLockThread == threadSelf
    424                 /* unlockRead() after lockWrite()? */);
    425         if (mWriteLockThread == threadSelf)
    426         {
    427             Assert (mSelfReadLockCount != 0
    428                     /* unlockRead() w/o preceding lockRead()? */);
    429             if (mSelfReadLockCount != 0)
    430             {
    431                 -- mSelfReadLockCount;
    432 
    433 # ifdef VBOX_MAIN_AUTOLOCK_TRAP
    434                 logOp (UnlockRead);
    435 # endif /* VBOX_MAIN_AUTOLOCK_TRAP */
    436             }
    437         }
    438     }
    439     else
    440     {
    441         Assert (mReadLockCount != 0
    442                 /* unlockRead() w/o preceding lockRead()? */);
    443         if (mReadLockCount != 0)
    444         {
    445             -- mReadLockCount;
    446             if (mReadLockCount == 0)
    447             {
    448                 /* no read locks, let writers go if there are any */
    449                 if (mWriteLockPending != 0)
    450                     RTSemEventSignal (mGoWriteSem);
    451             }
    452 
    453 # ifdef VBOX_MAIN_AUTOLOCK_TRAP
    454             logOp (UnlockRead);
    455 # endif /* VBOX_MAIN_AUTOLOCK_TRAP */
    456         }
    457     }
    458 
    459     RTCritSectLeave (&mCritSect);
    460 
    461 # ifdef DEBUG
    462     RTTHREAD iprtThreadSelf = RTThreadSelf();
    463     if (iprtThreadSelf != NIL_RTTHREAD)
    464         RTThreadReadLockDec (iprtThreadSelf);
    465 # endif
    466 
    467 #endif /* !VBOX_MAIN_USE_SEMRW */
    46876}
    46977
     
    47179uint32_t RWLockHandle::writeLockLevel() const
    47280{
    473 #ifdef VBOX_MAIN_USE_SEMRW
    474 
    47581    return RTSemRWGetWriteRecursion (mSemRW);
    476 
    477 #else /* !VBOX_MAIN_USE_SEMRW */
    478 
    479     Assert (mWriteLockLevel != 0);
    480 
    481     return mWriteLockLevel;
    482 
    483 #endif /* !VBOX_MAIN_USE_SEMRW */
    48482}
    485 
    486 
    487 #ifdef VBOX_MAIN_AUTOLOCK_TRAP
    488 
    489 void RWLockHandle::logOp (Operation aOp)
    490 {
    491     std::string info;
    492 
    493     char buf [256];
    494     RTStrPrintf (buf, sizeof (buf), "[%c] Thread %08x (%s)\n",
    495                  aOp == LockRead ? 'r' : aOp == LockWrite ? 'w' : '?',
    496                  RTThreadNativeSelf(), RTThreadGetName (RTThreadSelf()));
    497     info += buf;
    498 
    499 # if defined (RT_OS_LINUX)
    500 
    501     void *trace [16];
    502     char **messages = (char **) NULL;
    503     int i, trace_size = 0;
    504     trace_size = backtrace (trace, 16);
    505 
    506     messages = backtrace_symbols (trace, trace_size);
    507     /* skip first stack frame (points here) and the second stack frame (points
    508      * to lockRead()/lockWrite() */
    509     for (i = 2; i < trace_size; ++i)
    510         (info += messages[i]) += "\n";
    511 
    512     free (messages);
    513 
    514 # endif /* defined (RT_OS_LINUX) */
    515 
    516     internal::TLS *tls = internal::gGlobal.tls();
    517     if (tls != NULL)
    518     {
    519 
    520         switch (aOp)
    521         {
    522             case LockRead:
    523             {
    524                 mReaderInfo.push_back (info);
    525                 ++ tls->handles [this];
    526                 break;
    527             }
    528             case UnlockRead:
    529             {
    530                 mReaderInfo.pop_back();
    531                 -- tls->handles [this];
    532                 break;
    533             }
    534             case LockWrite:
    535             {
    536                 mWriterInfo = info;
    537                 ++ tls->handles [this];
    538                 break;
    539             }
    540             case UnlockWrite:
    541             {
    542                 mWriterInfo.clear();;
    543                 -- tls->handles [this];
    544                 break;
    545             }
    546         }
    547     }
    548 }
    549 
    550 void RWLockHandle::gatherInfo (std::string &aInfo)
    551 {
    552     char buf [256];
    553     RTStrPrintf (buf, sizeof (buf),
    554                  "[*] RWLockHandle %x:\n", this,
    555                  RTThreadNativeSelf(), RTThreadGetName (RTThreadSelf()));
    556     aInfo += buf;
    557 
    558     /* add reader info */
    559     for (ReaderInfo::const_iterator it = mReaderInfo.begin();
    560          it != mReaderInfo.end(); ++ it)
    561     {
    562         aInfo += *it;
    563     }
    564     /* add writer info */
    565     if (!mWriterInfo.empty())
    566         aInfo += mWriterInfo;
    567 }
    568 
    569 /* static */
    570 void RWLockHandle::TLSDestructor (internal::TLS *aTLS)
    571 {
    572     using namespace internal;
    573 
    574     if (aTLS != NULL && aTLS->handles.size())
    575     {
    576         std::string info;
    577         size_t cnt = 0;
    578 
    579         for (TLS::HandleMap::const_iterator it = aTLS->handles.begin();
    580              it != aTLS->handles.end(); ++ it)
    581         {
    582             if (it->second.raw != 0)
    583             {
    584                 it->first->gatherInfo (info);
    585                 ++ cnt;
    586             }
    587         }
    588 
    589         if (cnt != 0)
    590         {
    591             AssertReleaseMsgFailed ((
    592                 "DETECTED %d HELD RWLockHandle's on Thread %08x!\n%s\n",
    593                 cnt, RTThreadNativeSelf(), info.c_str()));
    594         }
    595     }
    596 }
    597 
    598 #endif /* ifdef VBOX_MAIN_AUTOLOCK_TRAP */
    599 
    60083
    60184} /* namespace util */
  • trunk/src/VBox/Main/Makefile.kmk

    r20928 r20932  
    6464        $(if $(VBOX_WITH_GUEST_PROPS),VBOX_WITH_GUEST_PROPS,) \
    6565        $(if $(VBOX_WITH_HOSTNETIF_API),VBOX_WITH_HOSTNETIF_API,)
    66 
    67 # Unconditionally use the RW semaphores from IPRT in AutoLock
    68 VBOX_MAIN_DEFS += VBOX_MAIN_USE_SEMRW
    6966
    7067# Unconditionally enable the new semaphore key generation code
  • trunk/src/VBox/Main/include/AutoLock.h

    r14949 r20932  
    3636#endif
    3737
    38 #ifdef VBOX_MAIN_USE_SEMRW
    39 # include <iprt/semaphore.h>
    40 #else
    41 # ifdef VBOX_MAIN_AUTOLOCK_TRAP
    42 #  include <map>
    43 #  include <list>
    44 #  include <string>
    45 # endif
    46 #endif
     38#include <iprt/semaphore.h>
    4739
    4840namespace util
    4941{
    50 
    51 #ifdef VBOX_MAIN_AUTOLOCK_TRAP
    52 namespace internal
    53 {
    54     struct TLS;
    55     DECLCALLBACK(void) TLSDestructor (void *aValue);
    56 }
    57 #endif /* VBOX_MAIN_AUTOLOCK_TRAP */
    5842
    5943/**
     
    195179    uint32_t writeLockLevel() const;
    196180
    197 #ifdef VBOX_MAIN_USE_SEMRW
    198 
    199181    RTSEMRW mSemRW;
    200 
    201 #else /* VBOX_MAIN_USE_SEMRW */
    202 
    203     mutable RTCRITSECT mCritSect;
    204     RTSEMEVENT mGoWriteSem;
    205     RTSEMEVENTMULTI mGoReadSem;
    206 
    207     RTNATIVETHREAD mWriteLockThread;
    208 
    209     uint32_t mReadLockCount;     /*< Number of read locks */
    210     uint32_t mSelfReadLockCount; /*< Number of read locks nested in write lock */
    211 
    212     uint32_t mWriteLockLevel;
    213     uint32_t mWriteLockPending;
    214 
    215 # ifdef VBOX_MAIN_AUTOLOCK_TRAP
    216 
    217     enum Operation { LockRead, UnlockRead, LockWrite, UnlockWrite };
    218     void logOp (Operation aOp);
    219     void gatherInfo (std::string &aInfo);
    220 
    221     friend DECLCALLBACK(void) internal::TLSDestructor (void *aValue);
    222     static void TLSDestructor (internal::TLS *aTLS);
    223 
    224     typedef std::list <std::string> ReaderInfo;
    225     ReaderInfo mReaderInfo;
    226     std::string mWriterInfo;
    227 
    228 # endif /* VBOX_MAIN_AUTOLOCK_TRAP */
    229 
    230 #endif /* VBOX_MAIN_USE_SEMRW */
    231182};
    232183
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