Changeset 101914 in vbox
- Timestamp:
- Nov 7, 2023 8:37:15 AM (13 months ago)
- Location:
- trunk/src/libs/xpcom18a4/xpcom
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/libs/xpcom18a4/xpcom/build/nsXPComInit.cpp
r101861 r101914 117 117 extern nsresult NS_CategoryManagerGetFactory( nsIFactory** ); 118 118 119 #ifdef DEBUG120 extern void _FreeAutoLockStatics();121 #endif122 123 119 static NS_DEFINE_CID(kComponentManagerCID, NS_COMPONENTMANAGER_CID); 124 120 static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); … … 876 872 nsComponentManagerImpl::gComponentManager = nsnull; 877 873 878 #ifdef DEBUG879 _FreeAutoLockStatics();880 #endif881 882 874 ShutdownSpecialSystemDirectory(); 883 875 -
trunk/src/libs/xpcom18a4/xpcom/reflect/xptinfo/src/xptiInterfaceInfo.cpp
r1 r101914 788 788 if(!cnt) 789 789 { 790 nsAutoMonitor lock(xptiInterfaceInfoManager::GetInfoMonitor());790 nsAutoMonitorCanBeNull lock(xptiInterfaceInfoManager::GetInfoMonitor()); 791 791 LOG_INFO_MONITOR_ENTRY; 792 792 -
trunk/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.cpp
r101905 r101914 38 38 #include "nsAutoLock.h" 39 39 40 #ifdef DEBUG41 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_XXX50 # include <stdio.h>51 # include "nsTraceMalloc.h"52 #endif53 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_XXX64 // Callsites for the inner locks/monitors stored in our base nsVoidArray.65 // This array parallels our base nsVoidArray.66 nsVoidArray mInnerSites;67 #endif68 69 nsNamedVector(const char* name = 0, PRUint32 initialSize = 0)70 : nsVoidArray(initialSize),71 mName(name)72 {73 }74 };75 76 static void * PR_CALLBACK77 _hash_alloc_table(void *pool, PRSize size)78 {79 return operator new(size);80 }81 82 static void PR_CALLBACK83 _hash_free_table(void *pool, void *item)84 {85 operator delete(item);86 }87 88 static PLHashEntry * PR_CALLBACK89 _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 in97 * nsAutoMonitor::NewMonitor/DeleteMonitor, we need to provide a freeEntry98 * PLHashTable hook, to avoid leaking nsNamedVectors which are replaced by99 * nsAutoMonitor::NewMonitor.100 *101 * There is still a problem with the OrderTable containing orphaned102 * 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::DestroyMonitor105 * instead of PR_NewMonitor and PR_DestroyMonitor). These lock vectors don't106 * strictly leak, as they are killed on shutdown, but there are unnecessary107 * named vectors in the hash table that outlive their associated locks.108 *109 * XXX so we should have nsLock, nsMonitor, etc. and strongly type their110 * XXX nsAutoXXX counterparts to take only the non-auto types as inputs111 */112 static void PR_CALLBACK113 _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_entry127 };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_XXX245 vec1->mInnerSites.AppendElement((void*) callsite2);246 #endif247 }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 assert266 // if you reenter a PRLock.267 } else if (!addr) {268 // Ignore null addresses: the caller promises not to use the269 // lock at all, and NSPR will assert if you enter it.270 } else {271 const void* node =272 #ifdef NS_TRACE_MALLOC_XXX273 NS_GetStackTrace(1)274 #else275 nsnull276 #endif277 ;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_XXX293 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 #endif300 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 else331 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 else347 prev->mDown = mDown;348 }349 350 #endif /* DEBUG */351 352 40 PRMonitor* nsAutoMonitor::NewMonitor(const char* name) 353 41 { 354 42 PRMonitor* mon = PR_NewMonitor(); 355 #ifdef DEBUG356 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 #endif365 43 return mon; 366 44 } … … 368 46 void nsAutoMonitor::DestroyMonitor(PRMonitor* mon) 369 47 { 370 #ifdef DEBUG371 if (OrderTable)372 OnMonitorRecycle(mon);373 #endif374 48 PR_DestroyMonitor(mon); 375 49 } … … 377 51 void nsAutoMonitor::Enter() 378 52 { 379 #ifdef DEBUG380 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 #endif390 53 PR_EnterMonitor(mMonitor); 391 54 mLockCount += 1; … … 394 57 void nsAutoMonitor::Exit() 395 58 { 396 #ifdef DEBUG397 if (!mAddr) {398 NS_ERROR("It is not legal to exit a null monitor");399 return;400 }401 (void) PR_SetThreadPrivate(LockStackTPI, mDown);402 #endif403 59 PRStatus status = PR_ExitMonitor(mMonitor); 404 NS_ASSERTION(status == PR_SUCCESS, "PR_ExitMonitor failed");60 AssertMsg(status == PR_SUCCESS, ("PR_ExitMonitor failed")); 405 61 mLockCount -= 1; 406 62 } -
trunk/src/libs/xpcom18a4/xpcom/threads/nsAutoLock.h
r101905 r101914 111 111 #include "prlog.h" 112 112 113 #include <iprt/assert.h> 114 #include <iprt/semaphore.h> 115 113 116 /** 114 117 * nsAutoLockBase … … 121 124 enum nsAutoLockType {eAutoLock, eAutoMonitor, eAutoCMonitor}; 122 125 123 #ifdef DEBUG124 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 #else134 126 nsAutoLockBase(void* addr, nsAutoLockType type) {} 135 127 ~nsAutoLockBase() {} 136 137 void Show() {}138 void Hide() {}139 #endif140 128 }; 141 129 … … 147 135 private: 148 136 PRLock* mLock; 137 /** The IPRT fast mutex. */ 138 RTSEMFASTMUTEX m_hMtx; 149 139 PRBool mLocked; 150 140 … … 172 162 : nsAutoLockBase(aLock, eAutoLock), 173 163 mLock(aLock), 164 m_hMtx(NIL_RTSEMFASTMUTEX), 174 165 mLocked(PR_TRUE) { 175 166 PR_ASSERT(mLock); … … 179 170 PR_Lock(mLock); 180 171 } 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 182 183 ~nsAutoLock(void) { 183 184 if (mLocked) 184 PR_Unlock(mLock); 185 { 186 if (m_hMtx != NIL_RTSEMFASTMUTEX) 187 RTSemFastMutexRelease(m_hMtx); 188 else 189 PR_Unlock(mLock); 190 } 185 191 } 186 192 … … 191 197 **/ 192 198 void lock() { 193 Show();194 199 PR_ASSERT(!mLocked); 195 PR_Lock(mLock); 200 if (m_hMtx != NIL_RTSEMFASTMUTEX) 201 RTSemFastMutexRequest(m_hMtx); 202 else 203 PR_Lock(mLock); 196 204 mLocked = PR_TRUE; 197 205 } … … 205 213 void unlock() { 206 214 PR_ASSERT(mLocked); 207 PR_Unlock(mLock); 215 if (m_hMtx != NIL_RTSEMFASTMUTEX) 216 RTSemFastMutexRelease(m_hMtx); 217 else 218 PR_Unlock(mLock); 208 219 mLocked = PR_FALSE; 209 Hide();210 220 } 211 221 }; … … 213 223 #include "prmon.h" 214 224 #include "nsError.h" 215 #include "nsDebug.h"216 225 217 226 class NS_COM nsAutoMonitor : public nsAutoLockBase { … … 242 251 mMonitor(mon), mLockCount(0) 243 252 { 244 NS_ASSERTION(mMonitor, "null monitor");253 AssertMsg(mMonitor, ("null monitor")); 245 254 if (mMonitor) { 246 255 PR_EnterMonitor(mMonitor); … … 250 259 251 260 ~nsAutoMonitor() { 252 NS_ASSERTION(mMonitor, "null monitor");261 AssertMsg(mMonitor, ("null monitor")); 253 262 if (mMonitor && mLockCount) { 254 #ifdef DEBUG255 PRStatus status =256 #endif257 263 PR_ExitMonitor(mMonitor); 258 NS_ASSERTION(status == PR_SUCCESS, "PR_ExitMonitor failed");259 264 } 260 265 } … … 317 322 }; 318 323 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 */ 331 class NS_COM nsAutoMonitorCanBeNull : public nsAutoLockBase { 332 public: 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 359 private: 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 319 375 #endif // nsAutoLock_h__ 320 376
Note:
See TracChangeset
for help on using the changeset viewer.