Changeset 121098 in webkit for trunk/Source/JavaScriptCore/runtime/JSLock.cpp
- Timestamp:
- Jun 23, 2012, 6:41:40 AM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/runtime/JSLock.cpp
r121058 r121098 24 24 #include "Heap.h" 25 25 #include "CallFrame.h" 26 #include "JSGlobalObject.h"27 26 #include "JSObject.h" 28 27 #include "ScopeChain.h" … … 40 39 41 40 // Acquire this mutex before accessing lock-related data. 42 static pthread_mutex_t giantGlobalJSLock = PTHREAD_MUTEX_INITIALIZER; 43 44 GlobalJSLock::GlobalJSLock() 45 { 46 pthread_mutex_lock(&giantGlobalJSLock); 47 } 48 49 GlobalJSLock::~GlobalJSLock() 50 { 51 pthread_mutex_unlock(&giantGlobalJSLock); 52 } 53 54 JSLockHolder::JSLockHolder(ExecState* exec) 55 : m_globalData(&exec->globalData()) 56 { 57 m_globalData->apiLock().lock(); 58 } 59 60 JSLockHolder::JSLockHolder(JSGlobalData* globalData) 61 : m_globalData(globalData) 62 { 63 m_globalData->apiLock().lock(); 64 } 65 66 JSLockHolder::JSLockHolder(JSGlobalData& globalData) 67 : m_globalData(&globalData) 68 { 69 m_globalData->apiLock().lock(); 70 } 71 72 JSLockHolder::~JSLockHolder() 73 { 74 m_globalData->apiLock().unlock(); 75 } 76 77 JSLock::JSLock() 78 : m_lockCount(0) 79 { 80 m_spinLock.Init(); 81 } 82 83 JSLock::~JSLock() 84 { 85 } 86 87 void JSLock::lock() 88 { 89 ThreadIdentifier currentThread = WTF::currentThread(); 90 { 91 SpinLockHolder holder(&m_spinLock); 92 if (m_ownerThread == currentThread && m_lockCount) { 93 m_lockCount++; 94 return; 95 } 96 } 97 98 m_lock.lock(); 99 100 SpinLockHolder holder(&m_spinLock); 101 m_ownerThread = currentThread; 102 ASSERT(!m_lockCount); 103 m_lockCount = 1; 104 } 105 106 void JSLock::unlock() 107 { 108 ASSERT(currentThreadIsHoldingLock()); 109 110 SpinLockHolder holder(&m_spinLock); 111 m_lockCount--; 112 113 if (!m_lockCount) 114 m_lock.unlock(); 41 static pthread_mutex_t JSMutex = PTHREAD_MUTEX_INITIALIZER; 42 43 // Thread-specific key that tells whether a thread holds the JSMutex, and how many times it was taken recursively. 44 pthread_key_t JSLockCount; 45 46 static void createJSLockCount() 47 { 48 pthread_key_create(&JSLockCount, 0); 49 } 50 51 pthread_once_t createJSLockCountOnce = PTHREAD_ONCE_INIT; 52 53 // Lock nesting count. 54 intptr_t JSLock::lockCount() 55 { 56 pthread_once(&createJSLockCountOnce, createJSLockCount); 57 58 return reinterpret_cast<intptr_t>(pthread_getspecific(JSLockCount)); 59 } 60 61 static void setLockCount(intptr_t count) 62 { 63 ASSERT(count >= 0); 64 pthread_setspecific(JSLockCount, reinterpret_cast<void*>(count)); 65 } 66 67 JSLock::JSLock(ExecState* exec) 68 : m_lockBehavior(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly) 69 { 70 lock(m_lockBehavior); 71 } 72 73 JSLock::JSLock(JSGlobalData* globalData) 74 : m_lockBehavior(globalData->isSharedInstance() ? LockForReal : SilenceAssertionsOnly) 75 { 76 lock(m_lockBehavior); 77 } 78 79 void JSLock::lock(JSLockBehavior lockBehavior) 80 { 81 #ifdef NDEBUG 82 // Locking "not for real" is a debug-only feature. 83 if (lockBehavior == SilenceAssertionsOnly) 84 return; 85 #endif 86 87 pthread_once(&createJSLockCountOnce, createJSLockCount); 88 89 intptr_t currentLockCount = lockCount(); 90 if (!currentLockCount && lockBehavior == LockForReal) { 91 int result = pthread_mutex_lock(&JSMutex); 92 ASSERT_UNUSED(result, !result); 93 } 94 setLockCount(currentLockCount + 1); 95 } 96 97 void JSLock::unlock(JSLockBehavior lockBehavior) 98 { 99 ASSERT(lockCount()); 100 101 #ifdef NDEBUG 102 // Locking "not for real" is a debug-only feature. 103 if (lockBehavior == SilenceAssertionsOnly) 104 return; 105 #endif 106 107 intptr_t newLockCount = lockCount() - 1; 108 setLockCount(newLockCount); 109 if (!newLockCount && lockBehavior == LockForReal) { 110 int result = pthread_mutex_unlock(&JSMutex); 111 ASSERT_UNUSED(result, !result); 112 } 115 113 } 116 114 117 115 void JSLock::lock(ExecState* exec) 118 116 { 119 exec->globalData().apiLock().lock();117 lock(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly); 120 118 } 121 119 122 120 void JSLock::unlock(ExecState* exec) 123 121 { 124 exec->globalData().apiLock().unlock();122 unlock(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly); 125 123 } 126 124 127 125 bool JSLock::currentThreadIsHoldingLock() 128 126 { 129 return m_lockCount && m_ownerThread == WTF::currentThread(); 127 pthread_once(&createJSLockCountOnce, createJSLockCount); 128 return !!pthread_getspecific(JSLockCount); 130 129 } 131 130 … … 151 150 // write over the second thread's call frames. 152 151 // 153 // Toavoid JS stack corruption we enforce a policy of only ever allowing two152 // In avoid JS stack corruption we enforce a policy of only ever allowing two 154 153 // threads to use a JS context concurrently, and only allowing the second of 155 154 // these threads to execute until it has completed and fully returned from its … … 160 159 // again through a callback, then the locks will not be dropped when DropAllLocks 161 160 // is called (since lockDropDepth is non-zero). Since this thread is still holding 162 // the locks, only it will be able to re-enter JSC (either be returning from the161 // the locks, only it will re able to re-enter JSC (either be returning from the 163 162 // callback, or by re-entering through another call to evaulate script or call 164 163 // function). … … 170 169 // would likely increase complexity and overhead. 171 170 // 172 173 // This function returns the number of locks that were dropped. 174 unsigned JSLock::dropAllLocks() 175 { 176 if (m_lockDropDepth++) 177 return 0; 178 179 return dropAllLocksUnconditionally(); 180 } 181 182 unsigned JSLock::dropAllLocksUnconditionally() 183 { 184 unsigned lockCount = m_lockCount; 185 for (unsigned i = 0; i < lockCount; i++) 186 unlock(); 187 188 return lockCount; 189 } 190 191 void JSLock::grabAllLocks(unsigned lockCount) 192 { 193 for (unsigned i = 0; i < lockCount; i++) 194 lock(); 195 196 m_lockDropDepth--; 197 } 171 static unsigned lockDropDepth = 0; 198 172 199 173 JSLock::DropAllLocks::DropAllLocks(ExecState* exec) 200 : m_lockCount(0) 201 , m_globalData(&exec->globalData()) 202 { 203 m_lockCount = m_globalData->apiLock().dropAllLocks(); 204 } 205 206 JSLock::DropAllLocks::DropAllLocks(JSGlobalData* globalData) 207 : m_lockCount(0) 208 , m_globalData(globalData) 209 { 210 m_lockCount = m_globalData->apiLock().dropAllLocks(); 174 : m_lockBehavior(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly) 175 { 176 pthread_once(&createJSLockCountOnce, createJSLockCount); 177 178 if (lockDropDepth++) { 179 m_lockCount = 0; 180 return; 181 } 182 183 m_lockCount = JSLock::lockCount(); 184 for (intptr_t i = 0; i < m_lockCount; i++) 185 JSLock::unlock(m_lockBehavior); 186 } 187 188 JSLock::DropAllLocks::DropAllLocks(JSLockBehavior JSLockBehavior) 189 : m_lockBehavior(JSLockBehavior) 190 { 191 pthread_once(&createJSLockCountOnce, createJSLockCount); 192 193 if (lockDropDepth++) { 194 m_lockCount = 0; 195 return; 196 } 197 198 // It is necessary to drop even "unreal" locks, because having a non-zero lock count 199 // will prevent a real lock from being taken. 200 201 m_lockCount = JSLock::lockCount(); 202 for (intptr_t i = 0; i < m_lockCount; i++) 203 JSLock::unlock(m_lockBehavior); 211 204 } 212 205 213 206 JSLock::DropAllLocks::~DropAllLocks() 214 207 { 215 m_globalData->apiLock().grabAllLocks(m_lockCount); 208 for (intptr_t i = 0; i < m_lockCount; i++) 209 JSLock::lock(m_lockBehavior); 210 211 --lockDropDepth; 216 212 } 217 213 218 214 #else // (OS(DARWIN) || USE(PTHREADS)) 219 215 220 GlobalJSLock::GlobalJSLock() 221 { 222 } 223 224 GlobalJSLock::~GlobalJSLock() 225 { 226 } 227 228 JSLockHolder::JSLockHolder(JSGlobalData*) 229 { 230 } 231 232 JSLockHolder::JSLockHolder(JSGlobalData&) 233 { 234 } 235 236 JSLockHolder::JSLockHolder(ExecState*) 237 { 238 } 239 240 JSLockHolder::~JSLockHolder() 241 { 242 } 243 244 JSLock::JSLock() 245 { 246 } 247 248 JSLock::~JSLock() 249 { 216 JSLock::JSLock(ExecState*) 217 : m_lockBehavior(SilenceAssertionsOnly) 218 { 219 } 220 221 // If threading support is off, set the lock count to a constant value of 1 so ssertions 222 // that the lock is held don't fail 223 intptr_t JSLock::lockCount() 224 { 225 return 1; 250 226 } 251 227 … … 255 231 } 256 232 257 void JSLock::lock( )258 { 259 } 260 261 void JSLock::unlock( )233 void JSLock::lock(JSLockBehavior) 234 { 235 } 236 237 void JSLock::unlock(JSLockBehavior) 262 238 { 263 239 } … … 271 247 } 272 248 273 void JSLock::lock(JSGlobalData&)274 {275 }276 277 void JSLock::unlock(JSGlobalData&)278 {279 }280 281 unsigned JSLock::dropAllLocks()282 {283 return 0;284 }285 286 unsigned JSLock::dropAllLocksUnconditionally()287 {288 return 0;289 }290 291 void JSLock::grabAllLocks(unsigned)292 {293 }294 295 249 JSLock::DropAllLocks::DropAllLocks(ExecState*) 296 250 { 297 251 } 298 252 299 JSLock::DropAllLocks::DropAllLocks(JS GlobalData*)253 JSLock::DropAllLocks::DropAllLocks(JSLockBehavior) 300 254 { 301 255 }
Note:
See TracChangeset
for help on using the changeset viewer.