/* A method's quick prepare info list holds prepare information for all blocks within the method that end with a quickened instruction. If the quickened instruction being executed is in the list we must have reached the end of a block and we need to inline it */ void checkInliningQuickenedInstruction(Instruction *pc, MethodBlock *mb) { /* As there could be multiple threads executing this method, the list must be protected with a lock. However, the fast case of an empty list doesn't need locking. */ if(mb->quick_prepare_info) { QuickPrepareInfo *info, *last = NULL; Thread *self = threadSelf(); rewriteLock(self); /* Search list */ info = mb->quick_prepare_info; for(; info && info->quickened != pc; last = info, info = info->next); /* If prepare info found, remove it from the list */ if(info) { if(last) last->next = info->next; else mb->quick_prepare_info = info->next; } rewriteUnlock(self); /* If prepare info found, inline block (no need to hold lock) */ if(info) { inlineBlock(mb, &info->block); sysFree(info); } } }
void inlineBlockWrappedOpcode(MethodBlock *mb, Instruction *pc) { PrepareInfo *prepare_info = pc->operand.pntr; OpcodeInfo *info; int i; Thread *self = threadSelf(); rewriteLock(self); for(i = 0; i < HANDLERS; i++) if(pc->handler == handler_entry_points[i][OPC_INLINE_REWRITER]) break; if(i == HANDLERS) { rewriteUnlock(self); return; } pc->handler = handler_entry_points[0][GOTO_START]; rewriteUnlock(self); /* Unwrap the original handler's operand */ pc->operand = prepare_info->operand; MBARRIER(); /* Unwrap the original handler */ info = &prepare_info->block.opcodes[prepare_info->block.length-1]; pc->handler = handler_entry_points[info->cache_depth][info->opcode]; inlineBlock(mb, &prepare_info->block); sysFree(prepare_info); }
void objectUnlock(Object *obj) { Thread *self = threadSelf(); uintptr_t lockword = LOCKWORD_READ(&obj->lock); uintptr_t thin_locked = self->id<<TID_SHIFT; TRACE("Thread %p unlock on obj %p...\n", self, obj); if(lockword == thin_locked) { /* This barrier is not needed for the thin-locking implementation; it's a requirement of the Java memory model. */ JMM_UNLOCK_MBARRIER(); LOCKWORD_WRITE(&obj->lock, 0); /* Required by thin-locking mechanism. */ MBARRIER(); retry: if(testFlcBit(obj)) { Monitor *mon = findMonitor(obj); if(!monitorTryLock(mon, self)) { threadYield(self); goto retry; } if(testFlcBit(obj) && (mon->obj == obj)) monitorNotify(mon, self); monitorUnlock(mon, self); } } else { if((lockword & (TID_MASK|SHAPE_BIT)) == thin_locked) LOCKWORD_WRITE(&obj->lock, lockword - (1<<COUNT_SHIFT)); else if((lockword & SHAPE_BIT) != 0) { Monitor *mon = (Monitor*) (lockword & ~SHAPE_BIT); if((mon->count == 0) && (LOCKWORD_READ(&mon->entering) == 0) && (mon->in_wait == 0)) { TRACE("Thread %p is deflating obj %p...\n", self, obj); /* This barrier is not needed for the thin-locking implementation; it's a requirement of the Java memory model. */ JMM_UNLOCK_MBARRIER(); LOCKWORD_WRITE(&obj->lock, 0); LOCKWORD_COMPARE_AND_SWAP(&mon->entering, 0, UN_USED); } monitorUnlock(mon, self); } } }
void resetPeakThreadsCount() { Thread *self = threadSelf(); /* Grab the thread lock to protect against concurrent update by threads starting/dying */ disableSuspend(self); pthread_mutex_lock(&lock); peak_threads_count = threads_count; pthread_mutex_unlock(&lock); enableSuspend(self); }
void createJavaThread(Object *jThread, long long stack_size) { //ExecEnv *ee; Thread *thread; Thread *self = threadSelf(); Object *vmthread = allocObject(vmthread_class); if(vmthread == NULL) return; disableSuspend(self); pthread_mutex_lock(&lock); if(INST_DATA(jThread)[vmthread_offset]) { pthread_mutex_unlock(&lock); enableSuspend(self); signalException(java_lang_IllegalThreadStateException, "thread already started"); return; } //ee = (ExecEnv*)sysMalloc(sizeof(ExecEnv)); thread = new Thread; //memset(ee, 0, sizeof(ExecEnv)); // thread->ee = ee; // ee->thread = jThread; thread->thread = jThread; // ee->stack_size = stack_size; INST_DATA(vmthread)[vmData_offset] = (uintptr_t)thread; INST_DATA(vmthread)[thread_offset] = (uintptr_t)jThread; INST_DATA(jThread)[vmthread_offset] = (uintptr_t)vmthread; pthread_mutex_unlock(&lock); if(pthread_create(&thread->tid, &attributes, threadStart, thread)) { INST_DATA(jThread)[vmthread_offset] = 0; //sysFree(ee); enableSuspend(self); signalException(java_lang_OutOfMemoryError, "can't create thread"); return; } pthread_mutex_lock(&lock); /* Wait for thread to start */ while(thread->state == 0) pthread_cond_wait(&cv, &lock); pthread_mutex_unlock(&lock); enableSuspend(self); }
bool Thread::checkHardRealtime() { #ifdef _SYSTEM_LXRT_ if (threadSelf() && os::isThisHRT() && !isHardRealtime() && m_priority < 0) { return setHardRealtime(true); } else #endif { return false; } }
void mainThreadWaitToExitVM() { Thread *self = threadSelf(); TRACE("Waiting for %d non-daemon threads to exit\n", non_daemon_thrds); disableSuspend(self); pthread_mutex_lock(&exit_lock); self->state = WAITING; while(non_daemon_thrds) pthread_cond_wait(&exit_cv, &exit_lock); pthread_mutex_unlock(&exit_lock); enableSuspend(self); }
void objectWait0(Object *obj, long long ms, int ns, int interruptible) { uintptr_t lockword = LOCKWORD_READ(&obj->lock); Thread *self = threadSelf(); Monitor *mon; TRACE("Thread %p Wait on obj %p...\n", self, obj); if((lockword & SHAPE_BIT) == 0) { int tid = (lockword&TID_MASK)>>TID_SHIFT; if(tid == self->id) { mon = findMonitor(obj); monitorLock(mon, self); inflate(obj, mon, self); mon->count = (lockword&COUNT_MASK)>>COUNT_SHIFT; } else
void threadInterrupt(Thread *thread) { Thread *self = threadSelf(); Monitor *mon; /* MonitorWait sets wait_mon _before_ checking interrupted status. Therefore, if wait_mon is null, interrupted status will be noticed. This guards against a race-condition leading to an interrupt being missed. The memory barrier ensures correct ordering on SMP systems. */ thread->interrupted = TRUE; MBARRIER(); if((mon = thread->wait_mon) != NULL && thread->wait_next != NULL) { int locked; thread->interrupting = TRUE; /* The thread is waiting on a monitor, but it may not have entered the wait (in which case the signal will be lost). Loop until we can get ownership (i.e. the thread has released it on waiting) */ while(!(locked = !pthread_mutex_trylock(&mon->lock)) && mon->owner == NULL) sched_yield(); pthread_cond_signal(&thread->wait_cv); if(locked) pthread_mutex_unlock(&mon->lock); } /* Thread may still be parked */ threadUnpark(thread); /* Handle the case where the thread is blocked in a system call. This will knock it out with an EINTR. The suspend signal handler will just return (as in the user doing a kill), and do nothing otherwise. */ /* Note, under Linuxthreads pthread_kill obtains a lock on the thread being signalled. If another thread is suspending all threads, and the interrupting thread is earlier in the thread list than the thread being interrupted, it can be suspended holding the lock. When the suspending thread tries to signal the interrupted thread it will deadlock. To prevent this, disable suspension. */ fastDisableSuspend(self); pthread_kill(thread->tid, SIGUSR1); fastEnableSuspend(self); }
void objectLock(Object *obj) { Thread *self = threadSelf(); uintptr_t thin_locked = self->id<<TID_SHIFT; uintptr_t entering, lockword; Monitor *mon; TRACE("Thread %p lock on obj %p...\n", self, obj); if(LOCKWORD_COMPARE_AND_SWAP(&obj->lock, 0, thin_locked)) { /* This barrier is not needed for the thin-locking implementation; it's a requirement of the Java memory model. */ JMM_LOCK_MBARRIER(); return; } lockword = LOCKWORD_READ(&obj->lock); if((lockword & (TID_MASK|SHAPE_BIT)) == thin_locked) { int count = lockword & COUNT_MASK; if(count < (((1<<COUNT_SIZE)-1)<<COUNT_SHIFT)) LOCKWORD_WRITE(&obj->lock, lockword + (1<<COUNT_SHIFT)); else { mon = findMonitor(obj); monitorLock(mon, self); inflate(obj, mon, self); mon->count = 1<<COUNT_SIZE; } return; } try_again: mon = findMonitor(obj); try_again2: if((entering = LOCKWORD_READ(&mon->entering)) == UN_USED) goto try_again; if(!(LOCKWORD_COMPARE_AND_SWAP(&mon->entering, entering, entering+1))) goto try_again2; if(mon->obj != obj) { while(entering = LOCKWORD_READ(&mon->entering), !(LOCKWORD_COMPARE_AND_SWAP(&mon->entering, entering, entering-1))); goto try_again; } monitorLock(mon, self); while(entering = LOCKWORD_READ(&mon->entering), !(LOCKWORD_COMPARE_AND_SWAP(&mon->entering, entering, entering-1))); while((LOCKWORD_READ(&obj->lock) & SHAPE_BIT) == 0) { setFlcBit(obj); if(LOCKWORD_COMPARE_AND_SWAP(&obj->lock, 0, thin_locked)) inflate(obj, mon, self); else monitorWait0(mon, self, 0, 0, TRUE, FALSE); } }
//The following function is converted from the macro with the same name,since it may lead compiling error under //Microsoft Visual Studio. static void _findHashEntry(HashTable* table,Object* ptr,Monitor* ptr2,int add_if_absent,int scavenge,int locked) { int hash; int i; Thread *self; hash = HASH(ptr); if(locked) { self = threadSelf(); lockHashTable0(table, self); } i = hash & (table->hash_size - 1); for(;;) { ptr2 = table->hash_table[i].data; if((ptr2 == NULL) || (COMPARE(ptr, ptr2, hash, table->hash_table[i].hash))) break; i = (i+1) & (table->hash_size - 1); } if(ptr2) { ptr2 = FOUND(ptr, ptr2); } else if(add_if_absent) { table->hash_table[i].hash = hash; ptr2 = table->hash_table[i].data = PREPARE(ptr); if(ptr2) { table->hash_count++; if((table->hash_count * 4) > (table->hash_size * 3)) { int new_size; if(scavenge) { HashEntry *entry = table->hash_table; int cnt = table->hash_count; for(; cnt; entry++) { void *data = entry->data; if(data) { if(SCAVENGE(data)) { entry->data = NULL; table->hash_count--; } cnt--; } } if((table->hash_count * 3) > (table->hash_size * 2)) new_size = table->hash_size*2; else new_size = table->hash_size; } else new_size = table->hash_size*2; resizeHash(table, new_size); } } } if(locked) unlockHashTable0(table, self); }
void dumpThreadsLoop(Thread *self) { //return; // do nothing for now //assert(false); char buffer[256]; Thread *thread; sigset_t mask; int sig; sigemptyset(&mask); sigaddset(&mask, SIGQUIT); sigaddset(&mask, SIGINT); disableSuspend0(self, &self); for(;;) { sigwait(&mask, &sig); /* If it was an interrupt (e.g. Ctrl-C) terminate the VM */ if(sig == SIGINT) exitVM(0); /* It must be a SIGQUIT. Do a thread dump */ suspendAllThreads(self); jam_printf("\n------ JamVM version %s Full Thread Dump -------\n", VERSION); for(thread = &main_thread; thread != NULL; thread = thread->next) { //uintptr_t *thr_data = INST_DATA(thread->ee->thread); uintptr_t *thr_data = INST_DATA(thread->thread); int priority = thr_data[priority_offset]; int daemon = thr_data[daemon_offset]; assert(false); //Frame *last = thread->ee->last_frame; Frame* last = threadSelf()->get_current_spmt_thread()->get_current_mode()->frame; /* Get thread name; we don't use String2Cstr(), as this mallocs memory and may deadlock with a thread suspended in malloc/realloc/free */ String2Buff((Object*)thr_data[name_offset], buffer, sizeof(buffer)); jam_printf("\n\"%s\"%s %p priority: %d tid: %p id: %d state: %s (%d)\n", buffer, daemon ? " (daemon)" : "", thread, priority, thread->tid, thread->id, getThreadStateString(thread), thread->state); while(last->prev != NULL) { for(; last->mb != NULL; last = last->prev) { MethodBlock *mb = last->mb; ClassBlock *cb = CLASS_CB(mb->classobj); /* Convert slashes in class name to dots. Similar to above, we don't use slash2dots(), as this mallocs memory */ slash2dots2buff(cb->name, buffer, sizeof(buffer)); jam_printf("\tat %s.%s(", buffer, mb->name); if(mb->is_native()) jam_printf("Native method"); else if(cb->source_file_name == NULL) jam_printf("Unknown source"); else { int line = mapPC2LineNo(mb, last->last_pc); jam_printf("%s", cb->source_file_name); if(line != -1) jam_printf(":%d", line); } jam_printf(")\n"); } last = last->prev; } } resumeAllThreads(self); } }
static void suspendHandler(int sig) { Thread *thread = threadSelf(); suspendLoop(thread); }
/*! Check whether the calling thread is the thread running by this * object. * \deprecated Obsolete coding style. */ bool Thread::ThreadSelf() const { return threadSelf(); }