📄 natobject.cc
字号:
count = he -> light_count; } if (address & LOCKED) { wait_unlocked(he); goto retry; } // Now the unlikely cases. // We do know that: // - Address is set, and doesn't contain the LOCKED bit. // - If address refers to the same object as addr, then he -> light_thr_id // refers to this thread, and count is valid. // - The case in which we held the lightweight lock has been // completely handled, except for the REQUEST_CONVERSION case. // if ((address & ~FLAGS) == addr) { // The lightweight lock is assigned to this object. // Thus we must be in the REQUEST_CONVERSION case. if (0 != count) { // Defer conversion until we exit completely. he -> light_count = count - 1; return; } JvAssert(he -> light_thr_id == self); JvAssert(address & REQUEST_CONVERSION); // Conversion requested // Convert now. if (!compare_and_swap(&(he -> address), address, address | LOCKED)) goto retry; heavy_lock *hl = find_heavy(addr, he); JvAssert (0 != hl); // Requestor created it. he -> light_count = 0; JvAssert(he -> heavy_count > 0); // was incremented by requestor. _Jv_MutexLock(&(hl->si.mutex)); // Release the he lock after acquiring the mutex. // Otherwise we can accidentally // notify a thread that has already seen a heavyweight // lock. he -> light_thr_id = INVALID_THREAD_ID; release_set(&(he -> address), HEAVY); LOG(PROMOTE, address, self); // lightweight lock now unused. _Jv_CondNotifyAll(&(hl->si.condition), &(hl->si.mutex)); _Jv_MutexUnlock(&(hl->si.mutex)); // heavy_count was already incremented by original requestor. keep_live(addr); return; } // lightweight lock not for this object. JvAssert(!(address & LOCKED)); JvAssert((address & ~FLAGS) != addr); if (!compare_and_swap(&(he -> address), address, address | LOCKED)) goto retry; heavy_lock *hl = find_heavy(addr, he); if (NULL == hl) {# ifdef LOCK_DEBUG fprintf(stderr, "Failed to find heavyweight lock for addr 0x%lx" " pid = %d\n", addr, getpid()); print_he(he); for(;;) {}# endif release_set(&(he -> address), address); throw new java::lang::IllegalMonitorStateException( JvNewStringLatin1("current thread not owner")); } JvAssert(address & HEAVY); count = he -> heavy_count; JvAssert(count > 0); --count; he -> heavy_count = count; if (0 == count) { const unsigned test_freq = 16; // Power of 2 static volatile unsigned counter = 0; unsigned my_counter = counter; counter = my_counter + 1; if (my_counter%test_freq == 0) { // Randomize the interval length a bit. counter = my_counter + (my_counter >> 4) % (test_freq/2); // Unlock mutex first, to avoid self-deadlock, or worse. _Jv_MutexUnlock(&(hl->si.mutex)); maybe_remove_all_heavy(he, address &~HEAVY); // release lock bit, preserving // REQUEST_CONVERSION // and object address. } else { release_set(&(he -> address), address &~HEAVY); _Jv_MutexUnlock(&(hl->si.mutex)); // Unlock after releasing the lock bit, so that // we don't switch to another thread prematurely. } } else { release_set(&(he -> address), address); _Jv_MutexUnlock(&(hl->si.mutex)); } LOG(REL_HEAVY, addr, self); keep_live(addr);} // Return false if obj's monitor is held by the current threadbool_Jv_ObjectCheckMonitor (jobject obj){#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS obj_addr_t addr = (obj_addr_t)obj & ~((obj_addr_t)FLAGS);#else obj_addr_t addr = (obj_addr_t)obj;#endif obj_addr_t address; unsigned hash = JV_SYNC_HASH(addr); hash_entry * he = light_locks + hash; JvAssert(!(addr & FLAGS)); address = he -> address; // Try it the easy way first: if (address == 0) return true; _Jv_ThreadId_t self = _Jv_ThreadSelf(); if ((address & ~(HEAVY | REQUEST_CONVERSION)) == addr) // Fails if entry is LOCKED. // I can't asynchronously become or stop being the holder. return he -> light_thr_id != self;retry: // Acquire the hash table entry lock address &= ~LOCKED; if (!compare_and_swap(&(he -> address), address, address | LOCKED)) { wait_unlocked(he); goto retry; } bool not_mine; if ((address & ~FLAGS) == addr) not_mine = (he -> light_thr_id != self); else { heavy_lock* hl = find_heavy(addr, he); not_mine = hl ? _Jv_MutexCheckMonitor(&hl->si.mutex) : true; } release_set(&(he -> address), address); // unlock hash entry return not_mine;}// The rest of these are moderately thin veneers on _Jv_Cond ops.// The current version of Notify might be able to make the pthread// call AFTER releasing the lock, thus saving some context switches??voidjava::lang::Object::wait (jlong timeout, jint nanos){#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS obj_addr_t addr = (obj_addr_t)this & ~((obj_addr_t)FLAGS);#else obj_addr_t addr = (obj_addr_t)this;#endif _Jv_ThreadId_t self = _Jv_ThreadSelf(); unsigned hash = JV_SYNC_HASH(addr); hash_entry * he = light_locks + hash; unsigned count; obj_addr_t address; heavy_lock *hl; if (__builtin_expect (timeout < 0 || nanos < 0 || nanos > 999999, false)) throw new IllegalArgumentException;retry: address = he -> address; address &= ~LOCKED; if (!compare_and_swap(&(he -> address), address, address | LOCKED)) { wait_unlocked(he); goto retry; } // address did not have the lock bit set. We now hold the lock on he. if ((address & ~FLAGS) == addr) { // Convert to heavyweight. if (he -> light_thr_id != self) {# ifdef LOCK_DEBUG fprintf(stderr, "Found wrong lightweight lock owner in wait " "address = 0x%lx pid = %d\n", address, getpid()); print_he(he); for(;;) {}# endif release_set(&(he -> address), address); throw new IllegalMonitorStateException (JvNewStringLatin1 ("current thread not owner")); } count = he -> light_count; hl = get_heavy(addr, he); he -> light_count = 0; he -> heavy_count += count + 1; for (unsigned i = 0; i <= count; ++i) _Jv_MutexLock(&(hl->si.mutex)); // Again release the he lock after acquiring the mutex. he -> light_thr_id = INVALID_THREAD_ID; release_set(&(he -> address), HEAVY); // lightweight lock now unused. LOG(PROMOTE2, addr, self); if (address & REQUEST_CONVERSION) _Jv_CondNotifyAll (&(hl->si.condition), &(hl->si.mutex)); // Since we do this before we do a CondWait, we guarantee that // threads waiting on requested conversion are awoken before // a real wait on the same condition variable. // No other notification can occur in the interim, since // we hold the heavy lock, and notifications are made // without acquiring it. } else /* We should hold the heavyweight lock. */ { hl = find_heavy(addr, he); release_set(&(he -> address), address); if (0 == hl) {# ifdef LOCK_DEBUG fprintf(stderr, "Couldn't find heavy lock in wait " "addr = 0x%lx pid = %d\n", addr, getpid()); print_he(he); for(;;) {}# endif throw new IllegalMonitorStateException (JvNewStringLatin1 ("current thread not owner")); } JvAssert(address & HEAVY); } LOG(WAIT_START, addr, self); switch (_Jv_CondWait (&(hl->si.condition), &(hl->si.mutex), timeout, nanos)) { case _JV_NOT_OWNER: throw new IllegalMonitorStateException (JvNewStringLatin1 ("current thread not owner")); case _JV_INTERRUPTED: if (Thread::interrupted ()) throw new InterruptedException; } LOG(WAIT_END, addr, self);}voidjava::lang::Object::notify (void){#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS obj_addr_t addr = (obj_addr_t)this & ~((obj_addr_t)FLAGS);#else obj_addr_t addr = (obj_addr_t)this;#endif _Jv_ThreadId_t self = _Jv_ThreadSelf(); unsigned hash = JV_SYNC_HASH(addr); hash_entry * he = light_locks + hash; heavy_lock *hl; obj_addr_t address; int result;retry: address = ((he -> address) & ~LOCKED); if (!compare_and_swap(&(he -> address), address, address | LOCKED)) { wait_unlocked(he); goto retry; } if ((address & ~FLAGS) == addr && he -> light_thr_id == self) { // We hold lightweight lock. Since it has not // been inflated, there are no waiters. release_set(&(he -> address), address); // unlock return; } hl = find_heavy(addr, he); // Hl can't disappear since we point to the underlying object. // It's important that we release the lock bit before the notify, since // otherwise we will try to wake up the target while we still hold the // bit. This results in lock bit contention, which we don't handle // terribly well. release_set(&(he -> address), address); // unlock if (0 == hl) { throw new IllegalMonitorStateException(JvNewStringLatin1 ("current thread not owner")); return; } // We know that we hold the heavyweight lock at this point, // and the lightweight lock is not in use. result = _Jv_CondNotify(&(hl->si.condition), &(hl->si.mutex)); LOG(NOTIFY, addr, self); keep_live(addr); if (__builtin_expect (result, 0)) throw new IllegalMonitorStateException(JvNewStringLatin1 ("current thread not owner"));}voidjava::lang::Object::notifyAll (void){#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS obj_addr_t addr = (obj_addr_t)this & ~((obj_addr_t)FLAGS);#else obj_addr_t addr = (obj_addr_t)this;#endif _Jv_ThreadId_t self = _Jv_ThreadSelf(); unsigned hash = JV_SYNC_HASH(addr); hash_entry * he = light_locks + hash; heavy_lock *hl; obj_addr_t address; int result;retry: address = (he -> address) & ~LOCKED; if (!compare_and_swap(&(he -> address), address, address | LOCKED)) { wait_unlocked(he); goto retry; } hl = find_heavy(addr, he); if ((address & ~FLAGS) == addr && he -> light_thr_id == self) { // We hold lightweight lock. Since it has not // been inflated, there are no waiters. release_set(&(he -> address), address); // unlock return; } release_set(&(he -> address), address); // unlock if (0 == hl) { throw new IllegalMonitorStateException(JvNewStringLatin1 ("current thread not owner")); } result = _Jv_CondNotifyAll(&(hl->si.condition), &(hl->si.mutex)); LOG(NOTIFY_ALL, addr, self); if (__builtin_expect (result, 0)) throw new IllegalMonitorStateException(JvNewStringLatin1 ("current thread not owner"));}// This is declared in Java code and in Object.h.// It should never be called with JV_HASH_SYNCHRONIZATIONvoidjava::lang::Object::sync_init (void){ throw new IllegalMonitorStateException(JvNewStringLatin1 ("internal error: sync_init"));}// This is called on startup and declared in Object.h.// For now we just make it a no-op.void_Jv_InitializeSyncMutex (void){}#endif /* JV_HASH_SYNCHRONIZATION */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -