jthread.c
来自「kaffe Java 解释器语言,源码,Java的子集系统,开放源代码」· C语言 代码 · 共 2,882 行 · 第 1/5 页
C
2,882 行
{ 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);}/* * deactivate virtual timer */static voiddeactivate_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 = 0; setitimer(ITIMER_VIRTUAL, &tm, 0);}#elsestatic void activate_time_slicing(void) { }static void deactivate_time_slicing(void) { }#endif/* * Initialize the threading system. */voidjthread_init(int pre, int maxpr, int minpr, void *(*_allocator)(size_t), void (*_deallocator)(void*), void *(*_reallocator)(void*,size_t), void (*_destructor1)(void*), void (*_onstop)(void), void (*_ondeadlock)(void)){ jthread *jtid; int i; /* 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. */ ignoreSignal(SIGHUP); KaffeSetDefaultAllocator(_allocator, _deallocator, _reallocator); queuePool = KaffeCreatePool();#if defined(SIGVTALRM) registerAsyncSignalHandler(SIGVTALRM, interrupt);#endif registerAsyncSignalHandler(SIGALRM, interrupt); registerAsyncSignalHandler(SIGIO, interrupt); registerAsyncSignalHandler(SIGCHLD, interrupt); registerAsyncSignalHandler(SIGUSR1, 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; allocator = _allocator; deallocator = _deallocator; onstop = _onstop; ondeadlock = _ondeadlock; destructor1 = _destructor1; threadQhead = (KaffeNodeQueue **)allocator((maxpr + 1) * sizeof (KaffeNodeQueue *)); threadQtail = (KaffeNodeQueue **)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); JTHREADQ(liveThreads) = 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();}jthread_tjthread_createfirst(size_t mainThreadStackSize, unsigned char 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. */#if defined(STACK_GROWS_UP) jtid->stackBase = (void*)(uintp)(&jtid - 0x100); jtid->stackEnd = jtid->stackBase + mainThreadStackSize; jtid->restorePoint = jtid->stackEnd;#else jtid->stackEnd = (void*)(uintp)(&jtid + 0x100); jtid->stackBase = (char *) jtid->stackEnd - mainThreadStackSize; jtid->restorePoint = jtid->stackBase;#endif jtid->localData.jlThread = jlThread; jthread_setpriority(jtid, prio); 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(); /* make sure we only resume suspended threads * (and neither dead nor runnable threads) */ if (jtid != currentJThread && jtid->status == THREAD_SUSPENDED) { jtid->flags |= THREAD_FLAGS_INTERRUPTED; 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 char pri, void (*func)(void *), int daemon, 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) & -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; JTHREADQ(liveQ) = jtid; liveThreads = liveQ; talive++; if ((jtid->daemon = daemon) != 0) { tdaemon++; }DBG(JTHREAD, dprintf("creating thread %p, daemon=%d\n", jtid, daemon); ) 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. */ (char *) 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 (char *) 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; base += REDZONE; currentJThread->stackBase = (void *) base;#endif }}void*jthread_stacklimit(void){#if defined(STACK_GROWS_UP) return (void*)((uintp)currentJThread->stackEnd - REDZONE);#else return (void*)((uintp)currentJThread->stackBase + REDZONE);#endif}/* Spinlocks: simple since we're uniprocessor *//* ARGSUSED */voidjthread_spinon(void *arg){ jthread_suspendall();}/* ARGSUSED */voidjthread_spinoff(void *arg){ jthread_unsuspendall();}/* * yield to a thread of equal priority */voidjthread_yield(void){ intsDisable(); internalYield(); intsRestore();}/* * sleep for time milliseconds */ voidjthread_sleep(jlong time){
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?