/** * Detach thread from group if it is attached to. */ IDATA VMCALL hythread_remove_from_group(hythread_t thread) { IDATA status; if (!thread->group) { return TM_ERROR_NONE; } status = hythread_global_lock(); assert(status == TM_ERROR_NONE); // The thread can be detached from the other thread in case // of forceful termination by hythread_cancel(), but thread // local storage can be zeroed only for current thread. if (thread == hythread_self() ) { hythread_set_self(NULL); } fast_thread_array[thread->thread_id] = NULL; thread->prev->next = thread->next; thread->next->prev = thread->prev; thread->group->threads_count--; thread->group = NULL; status = hythread_global_unlock(); assert(status == TM_ERROR_NONE); return TM_ERROR_NONE; }
/** * Detaches a thread from the threading library. * Assumes that the thread is being detached is already attached. * * @param[in] thread A hythread_t representing the thread to be detached. * If this is NULL, the current thread is detached. */ void VMCALL hythread_detach_ex(hythread_t thread) { IDATA status; // Acquire global TM lock to prevent concurrent access to thread list status = hythread_global_lock(); assert(status == TM_ERROR_NONE); if (thread == NULL) { thread = hythread_self(); } assert(thread); // Detach if thread is attached to group. hythread_remove_from_group(thread); if (thread == hythread_self()) // Detach current thread only port_thread_detach(); // FIXME - uncomment after TM state transition complete // release thread data //hythread_struct_release(thread); status = hythread_global_unlock(); assert(status == TM_ERROR_NONE); }
/** * Returns all monitors owned by the specific thread. * * @param[in] java_thread thread which owns monitors * @param[out] monitor_count_ptr number of owned monitors * @param[out] monitors_ptr array of owned monitors */ IDATA VMCALL jthread_get_owned_monitors(jthread java_thread, jint *monitor_count_ptr, jobject **monitors_ptr) { assert(java_thread); assert(monitors_ptr); assert(monitor_count_ptr); IDATA status = hythread_global_lock(); if (status != TM_ERROR_NONE) { return status; } vm_thread_t vm_thread = jthread_get_vm_thread_from_java(java_thread); if (!vm_thread) { status = hythread_global_unlock(); return status; } jvmti_thread_t jvmti_thread = &vm_thread->jvmti_thread; if (!jvmti_thread) { status = hythread_global_unlock(); return status; } jobject *monitors = (jobject *) malloc(sizeof(jobject *) * jvmti_thread->owned_monitors_nmb); if (!monitors) { hythread_global_unlock(); return TM_ERROR_OUT_OF_MEMORY; } tmn_suspend_disable(); for (int i = 0; i < jvmti_thread->owned_monitors_nmb; i++) { jobject new_ref = oh_allocate_local_handle_from_jni(); if (NULL != new_ref) new_ref->object = jvmti_thread->owned_monitors[i]->object; else { tmn_suspend_enable(); hythread_global_unlock(); return TM_ERROR_OUT_OF_MEMORY; } // change the order of reported monitors to be compliant with RI monitors[jvmti_thread->owned_monitors_nmb - 1 - i] = new_ref; } tmn_suspend_enable(); *monitors_ptr = monitors; *monitor_count_ptr = jvmti_thread->owned_monitors_nmb; status = hythread_global_unlock(); return status; } // jthread_get_owned_monitors
/* * Get Thread CPU Time * * Return the CPU time utilized by the specified thread. * * OPTIONAL Functionality. */ jvmtiError JNICALL jvmtiGetThreadCpuTime(jvmtiEnv* env, jthread thread, jlong* nanos_ptr) { TRACE2("jvmti.timer", "GetThreadCpuTime called"); IDATA status; SuspendEnabledChecker sec; /* * Check given env & current phase. */ jvmtiPhase phases[] = {JVMTI_PHASE_LIVE}; CHECK_EVERYTHING(); CHECK_CAPABILITY(can_get_thread_cpu_time); if (NULL == nanos_ptr) return JVMTI_ERROR_NULL_POINTER; if (NULL == thread) { status = jthread_get_thread_cpu_time(NULL, nanos_ptr); } else { if (! is_valid_thread_object(thread)) return JVMTI_ERROR_INVALID_THREAD; // lock thread manager to avoid occasional change of thread state hythread_global_lock(); int state;// =thread_get_thread_state(thread); jvmtiError err = jvmtiGetThreadState(env, thread, &state); if (err != JVMTI_ERROR_NONE){ return err; } switch (state) { case JVMTI_THREAD_STATE_TERMINATED: // thread is terminated case JVMTI_JAVA_LANG_THREAD_STATE_NEW: // thread is new hythread_global_unlock(); return JVMTI_ERROR_THREAD_NOT_ALIVE; default: // thread is alive status = jthread_get_thread_cpu_time(thread, nanos_ptr); break; } hythread_global_unlock(); } if (status != TM_ERROR_NONE) return JVMTI_ERROR_INTERNAL; return JVMTI_ERROR_NONE; }
static IDATA jthread_init_jvmti_monitor_table() { IDATA status = hythread_global_lock(); if (status != TM_ERROR_NONE) { return status; } if (!jvmti_monitor_table) { if (array_create(&jvmti_monitor_table)) { hythread_global_unlock(); return TM_ERROR_OUT_OF_MEMORY; } status = port_mutex_create(&jvmti_monitor_table_lock, APR_THREAD_MUTEX_NESTED); if (status != TM_ERROR_NONE) { hythread_global_unlock(); return status; } } status = hythread_global_unlock(); return status; } // jthread_init_jvmti_monitor_table
ncaiError JNICALL ncaiTerminateThread(ncaiEnv *env, ncaiThread thread) { TRACE2("ncai.thread", "TerminateThread called"); SuspendEnabledChecker sec; if (env == NULL) return NCAI_ERROR_INVALID_ENVIRONMENT; if (thread == NULL) return NCAI_ERROR_INVALID_THREAD; hythread_t hythread = reinterpret_cast<hythread_t>(thread); hythread_t self = hythread_self(); if (hythread == self) return NCAI_ERROR_INVALID_THREAD; assert(thread); // grab hythread global lock hythread_global_lock(); if (!ncai_thread_is_alive(hythread)) { hythread_global_unlock(); return NCAI_ERROR_THREAD_NOT_ALIVE; } IDATA UNUSED status = jthread_vm_detach(jthread_get_vm_thread(hythread)); assert(status == TM_ERROR_NONE); hythread_cancel(hythread); // release hythread global lock hythread_global_unlock(); return NCAI_ERROR_NONE; }
static IDATA destroy_group_list() { hythread_group_t cur; IDATA status,status2; int i; // This method works only if there are no running threads. // there is no good way to kill running threads status=hythread_global_lock(); if (status != TM_ERROR_NONE) return status; cur = group_list->next; status = TM_ERROR_NONE; while (cur != group_list) { if (hythread_group_release(cur) == TM_ERROR_NONE) { cur = group_list->next; } else { status = TM_ERROR_RUNNING_THREADS; cur = cur->next; } } free(lock_table->live_objs); for (i = 0; i < HY_MAX_FAT_TABLES && lock_table->tables[i]; i++) { free(lock_table->tables[i]); } port_mutex_destroy(&lock_table->mutex); hycond_destroy(&lock_table->write); hycond_destroy(&lock_table->read); free(lock_table); status2=hythread_global_unlock(); if (status2 != TM_ERROR_NONE) return status2; return status; }
/** * Wrapper around user thread start proc. * Used to perform some duty jobs right after thread is started * and before thread is finished. */ static int HYTHREAD_PROC hythread_wrapper_start_proc(void *arg) { IDATA UNUSED status; hythread_t thread; hythread_start_proc_data start_proc_data; hythread_entrypoint_t start_proc; // store procedure arguments to local start_proc_data = *(hythread_start_proc_data_t) arg; free(arg); // get hythread global lock status = hythread_global_lock(); assert(status == TM_ERROR_NONE); // get native thread thread = start_proc_data.thread; start_proc = start_proc_data.proc; CTRACE(("TM: native thread started: native: %p tm: %p", port_thread_current(), thread)); // check hythread library state if (hythread_lib_state() != TM_LIBRARY_STATUS_INITIALIZED) { // set TERMINATED state port_mutex_lock(&thread->mutex); thread->state = TM_THREAD_STATE_TERMINATED; port_mutex_unlock(&thread->mutex); // set hythread_self() hythread_set_self(thread); assert(thread == hythread_self()); // release thread structure data hythread_detach(thread); // zero hythread_self() because we don't do it in hythread_detach_ex() hythread_set_self(NULL); CTRACE(("TM: native thread terminated due to shutdown: native: %p tm: %p", port_thread_current(), thread)); // release hythread global lock status = hythread_global_unlock(); assert(status == TM_ERROR_NONE); return 0; } // register to group and set ALIVE & RUNNABLE states status = hythread_set_to_group(thread, start_proc_data.group); assert(status == TM_ERROR_NONE); // set hythread_self() hythread_set_self(thread); assert(thread == hythread_self()); // set priority status = hythread_set_priority(thread, thread->priority); // FIXME - cannot set priority //assert(status == TM_ERROR_NONE); // release hythread global lock status = hythread_global_unlock(); assert(status == TM_ERROR_NONE); // Do actual call of the thread body supplied by the user. start_proc(start_proc_data.proc_args); assert(hythread_is_suspend_enabled()); // get hythread global lock status = hythread_global_lock(); assert(status == TM_ERROR_NONE); // set TERMINATED state port_mutex_lock(&thread->mutex); thread->state = TM_THREAD_STATE_TERMINATED; port_mutex_unlock(&thread->mutex); // detach and free thread hythread_detach(thread); // release hythread global lock status = hythread_global_unlock(); assert(status == TM_ERROR_NONE); return 0; }
IDATA VMCALL hythread_set_to_group(hythread_t thread, hythread_group_t group) { #ifdef ORDER int map_id; #endif IDATA status; hythread_t cur, prev; assert(thread); assert(group); Retry_lock: // Acquire global TM lock to prevent concurrent access to thread list status = hythread_global_lock(); assert(status == TM_ERROR_NONE); #ifdef ORDER #ifdef ORDER_DEBUG printf("[TEST]: hythread mapping to object (%d, %d)\n", thread->p_tid, thread->p_count); #endif if(hythread_vm_is_initializing || (thread->p_tid == 0 && thread->p_count == 0)){ } else{ if(hythread_get_IsRecord()){ #ifdef ORDER_DEBUG printf("[RECORD]: RECORD IN hythread_set_to_group!!!\n"); #endif threadRunOrderFile = fopen("THREAD_CREATE_ORDER.log", "a+"); #ifdef ORDER_DEBUG assert(threadRunOrderFile); #endif fprintf(threadRunOrderFile, "%d %d\n", thread->p_tid, thread->p_count); fflush(threadRunOrderFile); fclose(threadRunOrderFile); threadRunOrderFile = NULL; } else{ //#ifdef ORDER_DEBUG printf("[REPLAY]: REPLAY IN hythread_set_to_group!!!\n"); //#endif if(threadRunOrderFile == NULL){ threadRunOrderFile = fopen("THREAD_CREATE_ORDER.log", "r"); } #ifdef ORDER_DEBUG assert(threadRunOrderFile); #endif if(p_tid == -1 && p_count == -1){ #ifdef ORDER_DEBUG if(feof(threadRunOrderFile)){ assert(0); } #endif fscanf(threadRunOrderFile, "%d %d\n", &p_tid, &p_count); } if(p_tid == thread->p_tid && p_count == thread->p_count){ p_tid = -1; p_count = -1; } else{ IDATA status_temp = hythread_global_unlock(); assert(status_temp == TM_ERROR_NONE); //#ifdef ORDER_DEBUG printf("[THREAD_CREATE]: This is not the correct order of thread create, pthread_self %d\n", pthread_self()); //#endif usleep(1000); hythread_yield(); goto Retry_lock; } } } #endif assert(thread->os_handle); if (!thread->thread_id) { char free_slot_found = 0; unsigned int i; for(i = 0; i < MAX_ID; i++) { // increase next_id to allow thread_id change next_id++; if (next_id == MAX_ID) { next_id = 1; } if (fast_thread_array[next_id] == NULL) { thread->thread_id = next_id; free_slot_found = 1; #ifdef ORDER { char name[40]; FILE* thread_map = NULL; int current_pthread_id = (int)thread->os_handle; sprintf(name, "THREAD_MAP_WORKING_CLASSLIB.log"); thread_map = fopen(name, "a+"); #ifdef ORDER_DEBUG assert(thread_map); #endif fwrite(&next_id, sizeof(int), 1, thread_map); fwrite(¤t_pthread_id, sizeof(int), 1, thread_map); fflush(thread_map); fclose(thread_map); } // printf("create thread id : %d\n", (int)new_thread->os_handle); for (map_id = 0 ; map_id < ORDER_THREAD_NUM ; map_id ++ ) { if (pthreadid_tid_mapping[map_id][0] == (int)thread->os_handle) { Thread_Map tmap; tmap.thread_global_id = next_id; tmap.pthread_id = (int)thread->os_handle; tmap.thread_assigned_id = pthreadid_tid_mapping[map_id][1]; // if (threadMapFile == NULL) threadMapFile = fopen("RECORD_THREAD_MAP.log", "a+"); fwrite((char *)&tmap, 1, sizeof(Thread_Map), threadMapFile); fflush(threadMapFile); fclose(threadMapFile); threadMapFile = NULL; #ifdef ORDER_DEBUG printf("pthread id exists : %d\n", (int)pthreadid_tid_mapping[map_id][0]); printf("tid mapping : %d -> %d\n",pthreadid_tid_mapping[map_id][0], pthreadid_tid_mapping[map_id][1]); #endif break; } else if (pthreadid_tid_mapping[map_id][0] == 0) { Thread_Map tmap; tmap.thread_global_id = next_id; tmap.pthread_id = (int)thread->os_handle; tmap.thread_assigned_id = next_id; // if (threadMapFile == NULL) threadMapFile = fopen("RECORD_THREAD_MAP.log", "a+"); fwrite((char *)&tmap, 1, sizeof(Thread_Map), threadMapFile); fflush(threadMapFile); fclose(threadMapFile); threadMapFile = NULL; pthreadid_tid_mapping[map_id][0] = (int)(int)thread->os_handle; pthreadid_tid_mapping[map_id][1] = next_id; #ifdef ORDER_DEBUG printf("new pthread id : %d\n", (int)pthreadid_tid_mapping[map_id][0]); printf("tid mapping : %d -> %d\n", pthreadid_tid_mapping[map_id][0], pthreadid_tid_mapping[map_id][1]); #endif break; } if(i == (ORDER_THREAD_NUM - 1)) { printf("[yzm]Error : Thread Map overflow!\n"); assert(0); exit(0); } } #endif break; } } if (!free_slot_found) { status = hythread_global_unlock(); assert(status == TM_ERROR_NONE); return TM_ERROR_OUT_OF_MEMORY; } } assert(thread->thread_id); fast_thread_array[thread->thread_id] = thread; thread->group = group; group->threads_count++; cur = group->thread_list->next; prev = cur->prev; thread->next = cur; thread->prev = prev; prev->next = cur->prev = thread; port_mutex_lock(&thread->mutex); thread->state |= TM_THREAD_STATE_ALIVE | TM_THREAD_STATE_RUNNABLE; port_mutex_unlock(&thread->mutex); status = hythread_global_unlock(); assert(status == TM_ERROR_NONE); return TM_ERROR_NONE; }
/** * Creates a new thread in a given group. * * @param[in] new_thread a new allocated thread. * @param[in] group a thread group or NULL * in case of NULL this thread will go to the default group. * @param[in] stacksize a new thread stack size or 0 * in case of 0 the thread will be set the default stack size * @param[in] priority a new thread priority or 0 * in case of 0 the thread will be set HYTHREAD_PRIORITY_NORMAL priority * @param[in] func a function to run in the new thread * @param[in] data an argument to be passed to starting function */ IDATA VMCALL hythread_create_ex(hythread_t new_thread, hythread_group_t group, UDATA stacksize, UDATA priority, hythread_wrapper_t wrapper, hythread_entrypoint_t func, void *data) { int result; hythread_t self; assert(new_thread); #ifdef ORDER U_32 p_tid = new_thread->p_tid; U_32 p_count = new_thread->p_count; #endif hythread_struct_init(new_thread); #ifdef ORDER new_thread->p_tid = p_tid; new_thread->p_count = p_count; #endif self = hythread_self(); new_thread->library = self ? self->library : TM_LIBRARY; new_thread->priority = priority ? priority : HYTHREAD_PRIORITY_NORMAL; if (!wrapper) { hythread_start_proc_data_t start_proc_data; // No need to zero allocated memory because all fields are initilized below. start_proc_data = (hythread_start_proc_data_t) malloc(sizeof(hythread_start_proc_data)); if (start_proc_data == NULL) { return TM_ERROR_OUT_OF_MEMORY; } // Set up thread body procedure start_proc_data->thread = new_thread; start_proc_data->group = group == NULL ? TM_DEFAULT_GROUP : group; start_proc_data->proc = func; start_proc_data->proc_args = data; data = (void*)start_proc_data; // Set wrapper procedure wrapper = hythread_wrapper_start_proc; } // Need to make sure thread will not register itself with a thread group // until port_thread_create returned and initialized thread->os_handle properly. hythread_global_lock(); result = port_thread_create(&new_thread->os_handle, stacksize ? stacksize : TM_DEFAULT_STACKSIZE, priority, wrapper, data); assert(/* error */ result || new_thread->os_handle /* or thread created ok */); hythread_global_unlock(); return result; }