📄 jthread.c
字号:
{ if( jt != currentJThread ) { intsDisable(); if( jt->suspender == suspender ) { assert(jt->suspendCount > 0); jt->suspendCount -= 1; if( jt->suspendCount == 0 ) { if( jt->status == THREAD_RUNNING ) { jt->status = THREAD_SUSPENDED; } resumeThread(jt); jt->suspender = NULL; } } intsRestore(); }}jthread_t jthread_from_data(threadData *td, void *suspender){ jthread_t retval = NULL; intsDisable(); { KaffeNodeQueue *curr; jthread_t tid; for( curr = liveThreads; (curr != NULL) && (retval == NULL); curr = curr->next) { tid = JTHREADQ(curr); if( &tid->localData == td ) { if( tid != currentJThread ) { jthread_suspend(tid, suspender); } retval = tid; } } } intsRestore(); return( retval );}/*============================================================================ * * Functions for initialization and thread creation * */#if defined(HAVE_SETITIMER) && defined(ITIMER_VIRTUAL)/* * set virtual timer for 10ms round-robin time-slicing */static voidactivate_time_slicing(void){ struct itimerval tm; tm.it_interval.tv_sec = tm.it_value.tv_sec = 0; tm.it_interval.tv_usec = tm.it_value.tv_usec = 10000;/* 10 ms */ setitimer(ITIMER_VIRTUAL, &tm, 0);}#elsestatic void activate_time_slicing(void) { }#endif/** * Thread allocation function alias. */static void *thread_static_allocator(size_t bytes){ return KGC_malloc(threadCollector, bytes, KGC_ALLOC_STATIC_THREADDATA);}static void thread_static_free(void *p){ return KGC_free(threadCollector, p);}static void *thread_reallocator(void *p, size_t bytes){ return KGC_realloc(threadCollector, p, bytes, KGC_ALLOC_STATIC_THREADDATA);}/* * Initialize the threading system. */voidjthread_init(int pre, int maxpr, int minpr, Collector *collector, void (*_destructor1)(void*), void (*_onstop)(void), void (*_ondeadlock)(void)){ jthread *jtid; int i; threadCollector = collector; blockInts = 0; /* XXX this is f***ed. On BSD, we get a SIGHUP if we try to put * a process that has a pseudo-tty in async mode in the background * So we'll just ignore it and keep running. Note that this will * detach us from the session too. */ KaffeJThread_ignoreSignal(SIGHUP); KaffeSetDefaultAllocator(thread_static_allocator, thread_static_free, thread_reallocator); queuePool = KaffeCreatePool();#if defined(SIGVTALRM) registerAsyncSignalHandler(SIGVTALRM, interrupt);#endif registerAsyncSignalHandler(SIGALRM, interrupt); registerAsyncSignalHandler(SIGIO, interrupt); registerAsyncSignalHandler(SIGCHLD, interrupt); registerAsyncSignalHandler(SIGUSR1, interrupt); registerAsyncSignalHandler(SIGUSR2, interrupt); /* * If debugging is not enabled, set stdin, stdout, and stderr in * async mode. * * If debugging is enabled and ASYNCSTDIO is not given, do not * put them in async mode. * * If debugging is enabled and ASYNCSTDIO is given, put them in * async mode (as if debug weren't enabled.) * * This is useful because large amounts of fprintfs might be * not be seen if the underlying terminal is put in asynchronous * mode. So by default, when debugging, we want stdio be synchronous. * To override this, give the ASYNCSTDIO flag. */#ifndef _HURD_ASYNC_QUICKFIX_ if (DBGEXPR(ANY, DBGEXPR(ASYNCSTDIO, true, false), true)) { for (i = 0; i < 3; i++) { if (i != jthreadedFileDescriptor(i)) { return; } } }#endif /* * On some systems, it is essential that we put the fds back * in their non-blocking state */ atexit(restore_fds); registerTerminalSignal(SIGINT, restore_fds_and_exit); registerTerminalSignal(SIGTERM, restore_fds_and_exit); preemptive = pre; max_priority = maxpr; min_priority = minpr; onstop = _onstop; ondeadlock = _ondeadlock; destructor1 = _destructor1; threadQhead = (KaffeNodeQueue **)thread_static_allocator((maxpr + 1) * sizeof (KaffeNodeQueue *)); threadQtail = (KaffeNodeQueue **)thread_static_allocator((maxpr + 1) * sizeof (KaffeNodeQueue *)); for (i=0;i<FD_SETSIZE;i++) { readQ[i] = writeQ[i] = NULL; blockingFD[i] = true; } alarmList = NULL; waitForList = NULL; for (i=0;i<=maxpr;i++) threadQhead[i] = threadQtail[i] = NULL; /* create the helper pipe for lost wakeup problem */ if (pipe(sigPipe) != 0) { return; } if (maxFd == -1) { maxFd = sigPipe[0] > sigPipe[1] ? sigPipe[0] : sigPipe[1]; } jtid = newThreadCtx(0); if (!jtid) { return; } /* Fake up some stack bounds until we get the real ones later - we're * the only thread running so this isn't a problem. */ jtid->stackBase = 0; jtid->stackEnd = (char*)0 - 1;#if defined(STACK_GROWS_UP) jtid->restorePoint = jtid->stackEnd;#else jtid->restorePoint = jtid->stackBase;#endif jtid->priority = maxpr; jtid->status = THREAD_SUSPENDED; jtid->flags = THREAD_FLAGS_NOSTACKALLOC; jtid->func = (void (*)(void*))jthread_init; liveThreads = KaffePoolNewNode(queuePool); liveThreads->element = jtid; jtid->time = 0; talive++; currentJThread = jtid; resumeThread(jtid);#if defined(KAFFE_XPROFILER) /* * The profiler is started at program startup, we take over from here * on out so we disable whatever one was installed */ disableProfileTimer();#endif /* Because of the handleVtAlarm hack (poll every 20 SIGVTALRMs) * we turn on the delivery of SIGVTALRM even if no actual time * slicing is possible because only one Java thread is running. * XXX We should be smarter about that. */ activate_time_slicing(); jmutex_initialise(&GClock);}jthread_tjthread_createfirst(size_t mainThreadStackSize, unsigned int prio, void* jlThread){ jthread *jtid; jtid = currentJThread; /* * Note: the stackBase and stackEnd values are used for two purposes: * - to report to the gc what area to scan (extract_stack) * - to help in determining whether the next frame in the link chain * of frames is valid. This is done by checking its range. */ detectStackBoundaries(jtid, mainThreadStackSize); jtid->localData.jlThread = jlThread; jthread_setpriority(jtid, prio); firstThread = jtid; return (jtid);}/* * set a function to be run when all non-daemon threads have exited */void jthread_atexit(void (*f)(void)){ runOnExit = f;}/* * disallow cancellation */void jthread_disable_stop(void){ if (currentJThread) { /* DBG(JTHREAD, dprintf("disable stop for thread %p\n", currentJThread); ) */ intsDisable(); currentJThread->flags |= THREAD_FLAGS_DONTSTOP; currentJThread->stopCounter++; assert(currentJThread->stopCounter > 0); /* XXX Shouldn't recurse that much... ever... hopefully. */ assert(currentJThread->stopCounter < 50); intsRestore(); }}/* * reallow cancellation and stop if cancellation pending */void jthread_enable_stop(void){ if (currentJThread) { /* DBG(JTHREAD, dprintf("enable stop for thread %p\n", currentJThread); ) */ intsDisable(); if (--currentJThread->stopCounter == 0) { currentJThread->flags &= ~THREAD_FLAGS_DONTSTOP; if ((currentJThread->flags & THREAD_FLAGS_KILLED) != 0 && ((currentJThread->flags & THREAD_FLAGS_EXITING) == 0)) { die(); } } assert(currentJThread->stopCounter >= 0); intsRestore(); }}/* * interrupt a thread */voidjthread_interrupt(jthread *jtid){ intsDisable(); /* mark thread as interrupted */ jtid->flags |= THREAD_FLAGS_INTERRUPTED; /* make sure we only resume suspended threads * (and neither dead nor runnable threads) that * are not trying to acquire a mutex. */ if ((jtid->status == THREAD_SUSPENDED) && !jthread_on_mutex(jtid)) { resumeThread(jtid); } intsRestore();}static void die(void){ currentJThread->flags &= ~THREAD_FLAGS_KILLED; currentJThread->flags |= THREAD_FLAGS_DYING; assert(blockInts == 1); blockInts = 0; /* this is used to throw a ThreadDeath exception */ onstop(); assert(!"Rescheduling dead thread");}static voidstart_this_sucker_on_a_new_frame(void){ /* all threads start with interrupts turned off */ blockInts = 1; /* I might be dying already */ if ((currentJThread->flags & THREAD_FLAGS_KILLED) != 0) { die(); } intsRestore(); assert(currentJThread->stopCounter == 0); currentJThread->func(currentJThread->localData.jlThread); jthread_exit(); }/* * create a new jthread */jthread *jthread_create(unsigned int pri, void (*func)(void *), int isDaemon, void *jlThread, size_t threadStackSize){ KaffeNodeQueue *liveQ; jthread *jtid; void *oldstack, *newstack;#if defined(__ia64__) void *oldbsp, *newbsp;#endif size_t page_size; /* * Disable stop to protect the threadLock lock, and prevent * the system from losing a new thread context (before the new * thread is queued up). */ jthread_disable_stop(); /* Adjust stack size */ page_size = getpagesize(); if (threadStackSize == 0) threadStackSize = THREADSTACKSIZE; threadStackSize = (threadStackSize + page_size - 1) & (uintp)-page_size; jmutex_lock(&threadLock); jtid = newThreadCtx(threadStackSize); if (!jtid) { jmutex_unlock(&threadLock); jthread_enable_stop(); return 0; } jtid->priority = pri; jtid->localData.jlThread = jlThread; jtid->status = THREAD_SUSPENDED; jtid->flags = THREAD_FLAGS_GENERAL; jtid->blockqueue = NULL; liveQ = KaffePoolNewNode(queuePool); liveQ->next = liveThreads; liveQ->element = jtid; liveThreads = liveQ; talive++; if ((jtid->daemon = isDaemon) != 0) { tdaemon++; }DBG(JTHREAD, dprintf("creating thread %p, daemon=%d\n", jtid, isDaemon); ); jmutex_unlock(&threadLock); assert(func != 0); jtid->func = func; /* * set the first jmp point * * Note that when we return from setjmp in the context of * a new thread, we must no longer access any local variables * in this function. The reason is that we didn't munge * the base pointer that is used to access these variables. * * To be safe, we immediately call a new function. */ if (JTHREAD_CONTEXT_SAVE(jtid->env)) { /* new thread */ start_this_sucker_on_a_new_frame(); assert(!"Never!"); /* NOT REACHED */ } #if defined(SAVE_FP) SAVE_FP(jtid->fpstate);#endif /* set up context for new thread */ oldstack = GET_SP(jtid->env);#if defined(__ia64__) oldbsp = GET_BSP(jtid->env);#endif#if defined(STACK_GROWS_UP) newstack = jtid->stackBase+STACK_COPY; memcpy(newstack-STACK_COPY, oldstack-STACK_COPY, STACK_COPY);#else /* !STACK_GROWS_UP */ newstack = jtid->stackEnd;#if defined(__ia64__) /* * The stack segment is split in the middle. The upper half is used * as backing store for the register stack which grows upward. * The lower half is used for the traditional memory stack which * grows downward. Both stacks start in the middle and grow outward * from each other. */ newstack = (void *)((uintp)newstack - (threadStackSize >> 1)); newbsp = newstack; /* Make register stack 64-byte aligned */ if ((unsigned long)newbsp & 0x3f) newbsp = newbsp + (0x40 - ((unsigned long)newbsp & 0x3f)); newbsp += STACK_COPY; memcpy(newbsp-STACK_COPY, oldbsp-STACK_COPY, STACK_COPY);#endif newstack = (void *)((uintp)newstack - STACK_COPY); memcpy(newstack, oldstack, STACK_COPY);#endif /* !STACK_GROWS_UP */#if defined(NEED_STACK_ALIGN) newstack = (void *) STACK_ALIGN(newstack);#endif SET_SP(jtid->env, newstack);#if defined(__ia64__) SET_BSP(jtid->env, newbsp);#endif#if defined(SET_BP) /* * Clear the base pointer in the new thread's stack. * Nice for debugging, but not strictly necessary. */ SET_BP(jtid->env, 0);#endif#if defined(FP_OFFSET) /* needed for: IRIX */ SET_FP(jtid->env, newstack + ((void *)GET_FP(jtid->env) - oldstack));#endif resumeThread(jtid); jthread_enable_stop(); return jtid;}/*============================================================================ * * Functions that are part of the user interface * *//* * return the current thread */jthread_tjthread_current(void){ return currentJThread;}/* * determine whether a location is on the stack of the current thread */intjthread_on_current_stack(void *bp){ int rc = bp >= currentJThread->stackBase && bp < currentJThread->stackEnd;DBG(JTHREADDETAIL, dprintf("on current stack: base=%p size=%ld bp=%p %s\n", currentJThread->stackBase, (long)((char *) currentJThread->stackEnd - (char *) currentJThread->stackBase), bp, (rc ? "yes" : "no")); ); return rc;}/* * Check for room on stack. */intjthread_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);}/* * Get the current stack limit. */#define REDZONE 1024voidjthread_relaxstack(int yes){ if( yes ) {#if defined(STACK_GROWS_UP) uintp end = (uintp) currentJThread->stackEnd; end += REDZONE; currentJThread->stackEnd = (void *) end;#else uintp base = (uintp) currentJThread->stackBase; base -= REDZONE; currentJThread->stackBase = (void *) base;#endif } else {#if defined(STACK_GROWS_UP) uintp end = (uintp) currentJThread->stackEnd; end -= REDZONE; currentJThread->stackEnd = (void *) end;#else uintp base = (uintp) currentJThread->stackBase;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -