📄 natobject.cc
字号:
address &= ~LOCKED; if (!compare_and_swap(&(he -> address), address, (address | LOCKED ))) { wait_unlocked(he); goto retry; } if ((address & ~(HEAVY | REQUEST_CONVERSION)) == 0) { // Either was_heavy is true, or something changed out from under us, // since the initial test for 0 failed. assert(!(address & REQUEST_CONVERSION)); // Can't convert a nonexistent lightweight lock. heavy_lock *hl; hl = (was_heavy? find_heavy(addr, he) : 0); if (0 == hl) { // It is OK to use the lighweight lock, since either the // heavyweight lock does not exist, or none of the // heavyweight locks currently exist. Future threads // trying to acquire the lock will see the lightweight // one first and use that. he -> light_thr_id = self; // OK, since nobody else can hold // light lock or do this at the same time. assert(he -> light_count == 0); assert(was_heavy == (he -> address & HEAVY)); release_set(&(he -> address), (addr | was_heavy)); } else { // Must use heavy lock. ++ (he -> heavy_count); assert(0 == (address & ~HEAVY)); release_set(&(he -> address), HEAVY); _Jv_MutexLock(&(hl->si.mutex)); keep_live(addr); } return; } // Lightweight lock is held, but does not correspond to this object. // We hold the lock on the hash entry, and he -> address can't // change from under us. Neither can the chain of heavy locks. { assert(0 == he -> heavy_count || (address & HEAVY)); heavy_lock *hl = get_heavy(addr, he); ++ (he -> heavy_count); release_set(&(he -> address), address | HEAVY); _Jv_MutexLock(&(hl->si.mutex)); keep_live(addr); }}void_Jv_MonitorExit (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 _Jv_ThreadId_t self = _Jv_ThreadSelf(); unsigned hash = JV_SYNC_HASH(addr); hash_entry * he = light_locks + hash; _Jv_ThreadId_t light_thr_id; unsigned count; obj_addr_t address;retry: light_thr_id = he -> light_thr_id; // Unfortunately, it turns out we always need to read the address // first. Even if we are going to update it with compare_and_swap, // we need to reset light_thr_id, and that's not safe unless we know // that we hold the lock. address = he -> address; // First the (relatively) fast cases: if (__builtin_expect(light_thr_id == self, true)) // Above must fail if addr == 0 . { count = he -> light_count; if (__builtin_expect((address & ~HEAVY) == addr, true)) { if (count != 0) { // We held the lightweight lock all along. Thus the values // we saw for light_thr_id and light_count must have been valid. he -> light_count = count - 1; return; } else { // We hold the lightweight lock once. he -> light_thr_id = INVALID_THREAD_ID; if (compare_and_swap_release(&(he -> address), address, address & HEAVY)) return; else { he -> light_thr_id = light_thr_id; // Undo prior damage. goto retry; } } } // else lock is not for this address, conversion is requested, // or the lock bit in the address field is set. } else { if (__builtin_expect(!addr, false)) throw new java::lang::NullPointerException; if ((address & ~(HEAVY | REQUEST_CONVERSION)) == addr) {# ifdef LOCK_DEBUG fprintf(stderr, "Lightweight lock held by other thread\n\t" "light_thr_id = 0x%lx, self = 0x%lx, " "address = 0x%lx, pid = %d\n", light_thr_id, self, address, getpid()); print_he(he); for(;;) {}# endif // Someone holds the lightweight lock for this object, and // it can't be us. throw new java::lang::IllegalMonitorStateException( JvNewStringLatin1("current thread not owner")); } else 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; } assert(he -> light_thr_id == self); assert(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); assert (0 != hl); // Requestor created it. he -> light_count = 0; assert(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); // 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. assert(!(address & LOCKED)); assert((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 throw new java::lang::IllegalMonitorStateException( JvNewStringLatin1("current thread not owner")); } assert(address & HEAVY); count = he -> heavy_count; assert(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)); } keep_live(addr);} // 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 does not have the lock bit set. We 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. if (address & REQUEST_CONVERSION) _Jv_CondNotify (&(hl->si.condition), &(hl->si.mutex)); } 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")); } assert(address & HEAVY); } 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; }}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 thee 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; } result = _Jv_CondNotify(&(hl->si.condition), &(hl->si.mutex)); 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)); 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 + -