📄 thread-impl.c
字号:
for ( t=activeThreads; t; t = t->next ) { if ( (t != cur) && (t->suspendState == 0) && (t->active) ) { t->suspendState = SS_PENDING_SUSPEND; } }#endif } unprotectThreadList(cur); DBG( JTHREAD, dprintf("critical section (%d) established\n", critSection));}/** * Resume all temporarily suspended threads. Just take action if this * is the outmost exit */voidjthread_unsuspendall (void){ jthread_t cur = jthread_current(); jthread_t t; if ( !jthreadInitialized || !critSection ) return; if ( --critSection == 0 ){ int val; /* No need to sync, there's nobody else running. However it seems * we cannot use mutexes as they cause a deadlock when the world * is suspended. */ protectThreadList(cur); repsem_getvalue(&critSem, &val); assert(val == 0);#if !defined(KAFFE_BOEHM_GC) for ( t=activeThreads; t; t = t->next ){ int status; pthread_mutex_lock(&t->suspendLock); if ( (t->suspendState & (SS_PENDING_SUSPEND | SS_SUSPENDED)) != 0 ) { DBG( JTHREAD, dprintf("signal resume: %p (sus: %d blk: %d)\n", t, t->suspendState, t->blockState)); t->suspendState = SS_PENDING_RESUME; if ((t->blockState & (BS_SYSCALL|BS_CV|BS_CV_TO|BS_MUTEX)) == 0) { DBG (JTHREADDETAIL, dprintf(" sending sigResume\n")); do { status = pthread_kill( t->tid, sigResume); if ( status ) { DBG( JTHREAD, dprintf("error sending RESUME signal to %p: %d\n", t, status)); } /* ack wait workaround, see jthread_suspendall remarks */ repsem_wait( &critSem); } while (t->suspendState == SS_PENDING_RESUME); } else { DBG (JTHREADDETAIL, dprintf(" clearing suspendState\n")); t->suspendState = 0; } } pthread_mutex_unlock(&t->suspendLock); }#else for ( t=activeThreads; t; t = t->next ){ if ( t->suspendState & (SS_PENDING_SUSPEND | SS_SUSPENDED) ){ t->suspendState = 0; } } GC_enable();#endif repsem_getvalue(&critSem, &val); assert(val == 0); unprotectThreadList(cur); } DBG( JTHREAD, dprintf("exit crit section (%d)\n", critSection));}/******************************************************************************* * GC related stuff *//** * Walk stacks of all threads, except of the current one (doesn't * make much sense since that's the GC itself, and it's task is to * get rid of garbage, not to pin it down - besides the fact that * its stack is a moving target). * * The call chain looks like this * * startGC * Kaffe_ThreadInterface.GcWalkThreads == TwalkThreads * walkMemory * gcFunctions[..].walk == walkThread * */voidjthread_walkLiveThreads (void(*func)(jthread_t,void*), void *private){ jthread_t t; DBG( JTHREAD, dprintf("start walking threads\n")); for ( t = activeThreads; t != NULL; t = t->next) { func(t, private); } DBG( JTHREAD, dprintf("end walking threads\n"));}voidjthread_walkLiveThreads_r (void(*func)(jthread_t, void *), void *private){ jthread_t cur = jthread_current(); protectThreadList(cur); jthread_walkLiveThreads (func, private); unprotectThreadList(cur);}intjthread_is_blocking (int fd){ int r; r = fcntl(fd, F_GETFL, 0); if (r < 0) { perror("fcntl(F_GETFL)"); return 0; } return (r & O_NONBLOCK) != 0;}voidjthread_set_blocking (int fd, int blocking){ int r; /* This code has been copied from jthreadedFileDescriptor in unix-jthreads/jthread.c */ if (!blocking) { /* Make non-blocking */ if ((r = fcntl(fd, F_GETFL, 0)) < 0) { perror("F_GETFL"); return; } /* * Apparently, this can fail, for instance when we stdout is * redirected to /dev/null. (On FreeBSD) */ fcntl(fd, F_SETFL, r | O_NONBLOCK #if defined(O_ASYNC) | O_ASYNC#elif defined(FASYNC) | FASYNC#endif ); } else { /* clear nonblocking flag */ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK); }}/* * Get the current stack limit. * Adapted from kaffe/kaffevm/systems/unix-jthreads/jthread.h *//** * This function increments the pointer stored in "p" by "inc" bytes. * * @param p Pointer to be incremented. * @param inc Amount of bytes to increment the pointer. */static inline void incrPointer(void **p, int inc){ *p = (void *)((uintp)*p + inc);}/** * This function is meant to relax stack boundaries so the virtual machine * may execute some task before the final abort. * * @param yes If it is true, it relaxes the boundaries. If false, it shortens * the stack. */void jthread_relaxstack(int yes){ if( yes ) {#if defined(STACK_GROWS_UP) incrPointer(&jthread_current()->stackMax, STACKREDZONE);#else incrPointer(&jthread_current()->stackMin, -STACKREDZONE);#endif } else {#if defined(STACK_GROWS_UP) incrPointer(&jthread_current()->stackMax, -STACKREDZONE);#else incrPointer(&jthread_current()->stackMin, STACKREDZONE);#endif }}/** * Test whether an address is on the stack of the calling thread. * * @param p the address to check * * @return true if address is on the stack * * Needed for locking and for exception handling. */bool jthread_on_current_stack(void* p){ jthread_t nt = jthread_current();DBG(JTHREADDETAIL, dprintf("on current stack: base=%p size=%ld bp=%p", nt->stackMin, (long)((char *)nt->stackMax - (char *)nt->stackMin), p); ); if (nt == 0 || (p > nt->stackMin && p < nt->stackMax)) {DBG(JTHREADDETAIL, dprintf(" yes\n"); ); return (true); } else {DBG(JTHREADDETAIL, dprintf(" no\n"); ); return (false); }}/** * Lock a mutex which will be used for critical sections when entering * non-reentrant system code, for example. * * @param dummy unused pointer */void jthread_spinon(void *dummy UNUSED){ pthread_mutex_lock(&systemMutex);}/** * Unock a mutex used for critical sections when entering non-reentrant system * code. * * @param dummy unused pointer */void jthread_spinoff(void *dummy UNUSED){ pthread_mutex_unlock(&systemMutex);}/** * Sets a function to be run when all non-daemon threads have exited. * * @param func the function to be called when exiting. */void jthread_atexit(void (* func)(void)){ runOnExit = func;}int KaffePThread_getSuspendSignal(void){ return sigSuspend;}/** * Extract the range of the stack that's in use. * * @param tid the thread whose stack is to be examined * @param from storage for the address of the start address * @param len storage for the size of the used range * * @return true if successful, otherwise false * * Needed by the garbage collector. */bool jthread_extract_stack(jthread_t tid, void** from, unsigned* len){ if (tid->active == 0) { return false; } assert(tid->suspendState == SS_SUSPENDED);#if defined(STACK_GROWS_UP) *from = tid->stackMin; *len = (uintp)tid->stackCur - (uintp)tid->stackMin;#else *from = tid->stackCur; *len = (uintp)tid->stackMax - (uintp)tid->stackCur;#endif return true;}/** * Returns the current native thread. * */jthread_t jthread_current(void) { if (!jthreadInitialized) return NULL; else { void* specific = pthread_getspecific(ntKey); if (specific != NULL) return (jthread_t) specific; else { perror(NULL); abort(); } }}/** * Disable stopping the calling thread. * * Needed to avoid stopping a thread while it holds a lock. */void jthread_disable_stop(void){}/** * Enable stopping the calling thread. * * Needed to avoid stopping a thread while it holds a lock. */void jthread_enable_stop(void){}/** * Stop a thread. * * @param tid the thread to stop. */void jthread_stop(jthread_t tid UNUSED){}/** * Dump some information about a thread to stderr. * * @param tid the thread whose info is to be dumped. */void jthread_dumpthreadinfo(jthread_t tid UNUSED){}/** * Return the java.lang.Thread instance attached to a thread * * @param tid the native thread whose corresponding java thread * is to be returned. * @return the java.lang.Thread instance. */threadData *jthread_get_data(jthread_t tid){ return (&tid->data);}/** * Check for room on stack. * * @param left number of bytes that are needed * * @return true if @left bytes are free, otherwise false * * Needed by intrp in order to implement stack overflow checking. */bool jthread_stackcheck(int left){ int rc;#if defined(STACK_GROWS_UP) rc = jthread_on_current_stack((char*)&rc + left);#else rc = jthread_on_current_stack((char*)&rc - left);#endif return (rc);}/** * Returns the upper bound of the stack of the calling thread. * * Needed by support.c in order to implement stack overflow checking. */void* jthread_stacklimit(void){ jthread_t nt = jthread_current();#if defined(STACK_GROWS_UP) return (void *)((uintp)nt->stackMax - STACKREDZONE);#else return (void *)((uintp)nt->stackMin + STACKREDZONE);#endif}int jthread_on_condvar(jthread_t jt){ return (jt->blockState & (BS_CV|BS_CV_TO)) != 0;}int jthread_on_mutex(jthread_t jt){ return (jt->blockState & (BS_MUTEX)) != 0;}int jthread_get_status(jthread_t jt){ if (jt->status == THREAD_KILL) return THREAD_DEAD; return jt->status;}int jthread_has_run(jthread_t jt UNUSED){ return 1;}void jthread_clear_run(jthread_t jt UNUSED){}void jthread_suspend(jthread_t jt UNUSED, void *suspender UNUSED){ /* TODO */}void jthread_resume(jthread_t jt UNUSED, void *suspender UNUSED){ /* TODO */}jthread_t jthread_from_data(threadData *td, void *suspender UNUSED){ jthread_t cur = jthread_current(); jthread_t iterator; protectThreadList(cur); iterator = activeThreads; while (iterator != NULL) { if (td == &iterator->data) { unprotectThreadList(cur); /* Thread handles are garbage collected so the stack is protecting * us. */ return iterator; } iterator = iterator->next; } unprotectThreadList(cur); return NULL;}jlong jthread_get_usage(jthread_t jt UNUSED){ /* TODO */ return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -