📄 thread-impl.c
字号:
psigCancel = SIGRTMIN+1; sigInterrupt = SIGRTMIN+2; }}/* * static init set up of Java-to-pthread priority mapping (pthread prioritiy levels * are implementation dependent) */staticvoid tMapPriorities (int npr){ int d, max, min, i; float r;#if defined(HAVE_SCHED_GET_PRIORITY_MIN) && defined(SCHEDULE_POLICY) min = sched_get_priority_min( SCHEDULE_POLICY);#else min = 0;#endif /* defined(HAVE_SCHED_GET_PRIORITY_MIN) */#if defined(HAVE_SCHED_GET_PRIORITY_MAX) && defined(SCHEDULE_POLICY) max = sched_get_priority_max( SCHEDULE_POLICY);#else max = 0;#endif /* defined(HAVE_SCHED_GET_PRIORITY_MAX) */ d = max - min; r = (float)d / (float)npr; for ( i=0; i<npr; i++ ) { priorities[i] = (int)(i*r + 0.5) + min; }}/* * per-native thread init of semaphore */staticvoidtInitLock ( jthread_t nt ){ /* init a non-shared (process-exclusive) semaphore with value '0' */ repsem_init( &nt->sem, 0, 0);}/* * We must have a certain amount of credible thread information setup * as soon as possible. */staticvoidtSetupFirstNative(void){ jthread_t nt; /* * We need to have a native thread context available as soon as possible. */ nt = thread_malloc( sizeof(struct _jthread)); KGC_addRef(threadCollector, nt); nt->tid = pthread_self(); pthread_setspecific( ntKey, nt); nt->stackMin = (void*)0; nt->stackMax = (void*)-1;}/** * The global, one-time initialization goes here. This is a * alternative to scattered pthread_once() calls */voidjthread_init(int pre UNUSED, int maxpr, int minpr UNUSED, Collector *thread_collector, void (*destructor)(void *), void (*_onstop)(void) UNUSED, void (*_ondeadlock)(void) UNUSED){ DBG(JTHREAD, dprintf("initialized\n")); threadCollector = thread_collector; threadDestructor = destructor; tInitSignals(); pthread_key_create( &ntKey, NULL); repsem_init( &critSem, 0, 0); priorities = (int *)KGC_malloc (threadCollector, (maxpr+1) * sizeof(int), KGC_ALLOC_STATIC_THREADDATA); tMapPriorities(maxpr+1); tInitSignalHandlers(); sigemptyset( &suspendSet); sigaddset( &suspendSet, sigResume); tSetupFirstNative(); jthreadInitialized = true; DBG( JTHREAD, tStartDeadlockWatchdog() );}jthread_tjthread_createfirst(size_t mainThreadStackSize, unsigned int pri UNUSED, void* jlThread){ jthread_t nt; int oldCancelType; nt = jthread_current(); /* we can't use nt->attr, because it wasn't used to create this thread */ pthread_attr_init( &nt->attr); nt->tid = pthread_self(); nt->data.jlThread = jlThread; nt->suspendState = 0; nt->active = 1; nt->func = NULL; nt->next = NULL; nt->daemon = false; pthread_mutex_init(&nt->suspendLock, NULL); /* Get stack boundaries. Note that this is just an approximation * which should cover all gc-relevant stack locations */ KaffePThread_detectStackBoundaries(nt, mainThreadStackSize); DBG( JTHREAD, TMSG_SHORT( "create first ", nt)); /* init our cv and mux fields for locking */ tInitLock( nt); /* Link native and Java thread objects * We already are executing in the right thread, so we can set the specific * data straight away */ pthread_setspecific( ntKey, nt); pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, &oldCancelType); /* if we aren't the first one, we are in trouble */ assert( activeThreads == 0); activeThreads = firstThread = nt; nonDaemons=1; nSysThreads=1; return (nt);}/** * Interrupt a thread. * * If tid is currently blocked its interrupted flag is set * and the blocking operation is canceled. */void jthread_interrupt(jthread_t tid){ pthread_mutex_lock(&tid->suspendLock); tid->interrupting = 1; if ((tid->blockState & (BS_CV|BS_CV_TO)) != 0) { pthread_cond_signal (&tid->data.sem.cv); } else if (tid->blockState == 0 || (tid->blockState & BS_SYSCALL) != 0) { /* We need to send some signal to interrupt syscalls. */ pthread_kill(tid->tid, sigInterrupt); } pthread_mutex_unlock(&tid->suspendLock);}/** * Peek at the interrupted flag of a thread. * * @return true iff jt was interrupted. */int jthread_is_interrupted(jthread_t jt){ return jt->interrupting;}/** * Read and clear the interrupted flag of a thread. * * @return true iff jt was interrupted. */int jthread_interrupted(jthread_t jt){ int i = jt->interrupting; jt->interrupting = 0; return i;}bool jthread_attach_current_thread (bool isDaemon){ jthread_t nt; rlim_t stackSize; if (jthread_current() != NULL) return false; /* create the jthread* thingy */ nt = thread_malloc( sizeof(struct _jthread) ); nt->func = NULL; nt->suspendState = 0;#if defined(KAFFEMD_STACKSIZE) stackSize = mdGetStackSize(); if (stackSize == KAFFEMD_STACK_ERROR) { fprintf(stderr, "WARNING: Impossible to retrieve the real stack size\n"); fprintf(stderr, "WARNING: You may experience deadlocks\n"); } else if (stackSize == KAFFEMD_STACK_INFINITE) { fprintf(stderr, "WARNING: Kaffe may experience problems with unlimited\n" "WARNING: stack sizes (e.g. deadlocks).\n"); stackSize = MAINSTACKSIZE; }#else stackSize = MAINSTACKSIZE;#endif /* link everything together */ nt->tid = pthread_self(); pthread_setspecific( ntKey, nt); KaffePThread_detectThreadStackBoundaries(nt); tInitSignalHandlers(); nt->stackCur = NULL; nt->daemon = isDaemon; /* and done */ return true;}bool jthread_detach_current_thread (void){ jthread_t cur = jthread_current (); tDispose (cur); return true;}/* * This is our thread function wrapper, which we need because of two * reasons. First, there is no way to set thread specific data from * outside the current thread (and it should be propperly set before we * enter the *real* thread func). Second, this is a better place to handle * the recycle looping than Texit (would be strange to loop in there) */staticvoid* tRun ( void* p ){ jthread_t cur = (jthread_t)p; jthread_t t; size_t ss; int oldCancelType; /* get the stack boundaries */ pthread_attr_getstacksize( &cur->attr, &ss);#if defined(STACK_GROWS_UP) cur->stackMin = &cur; cur->stackMax = (void*) ((unsigned long)cur->stackMin + ss);#else cur->stackMax = &cur; cur->stackMin = (void*) ((unsigned long)cur->stackMax - ss);#endif pthread_setspecific( ntKey, cur); pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, &oldCancelType); cur->tid = pthread_self(); /* we are reasonably operational now, flag our creator that it's safe to give * up the thread lock */ repsem_post( &cur->sem); while ( 1 ) { DBG( JTHREAD, TMSG_LONG( "calling user func of: ", cur)); /* Now call our thread function, which happens to be firstStartThread(), * which will call TExit before it returns */ cur->func(cur->data.jlThread); DBG( JTHREAD, TMSG_LONG( "exiting user func of: ", cur)); if (threadDestructor) threadDestructor(cur->data.jlThread); protectThreadList(cur); /* remove from active list */ if ( cur == activeThreads ){ activeThreads = cur->next; } else { for ( t=activeThreads; t->next && (t->next != cur); t=t->next ); assert( t->next != 0 ); t->next = cur->next; } /* unlink Java and native thread */ cur->data.jlThread = NULL; cur->suspendState = 0; /* link into cache list (if still within limit) */ if ( ++nCached < MAX_CACHED_THREADS ){ cur->next = cache; cache = cur; DBG( JTHREAD, TMSG_SHORT( "cached thread ", cur)); } pendingExits--; unprotectThreadList(cur); if ( nCached >= MAX_CACHED_THREADS ){ break; } if (cur->status == THREAD_KILL) break; /* Wait until we get re-used (by TcreateThread). No need to update the * blockState, since we aren't active anymore */ repsem_wait( &cur->sem); if (cur->status == THREAD_KILL) break; /* * we have already been moved back to the activeThreads list by * Tcreate (saves us a lock) */ DBG( JTHREAD, TMSG_SHORT( "reused thread ", cur)); } tDispose( cur); return NULL;}/* * Create a new native thread for a given Java Thread object. Note * that we are called from Thread.start(), i.e. we are already allowed to * call func() (which happens to be threads.c:firstStartThread) * * Our call graph looks like this: * * Thread.start * startThread * Kaffe_ThreadInterface.create (firstStartThread) == Tcreate * pthread_create(..tRun..) * creator-thread * -------------------------------------------------------------- * created-thread * tRun * firstStartThread * Thread.run * exitThread * Thread.finish * Kaffe_ThreadInterface.exit == Texit */jthread_tjthread_create ( unsigned int pri, void* func, int isDaemon, void* jlThread, size_t threadStackSize ){ jthread_t cur = jthread_current(); jthread_t nt;#if defined(SCHEDULE_POLICY) struct sched_param sp;#endif /* if we are the first one, it's seriously broken */ assert( activeThreads != 0 ); /* * This is a safeguard to avoid creating too many new threads * because of a high Tcreate call frequency from a high priority * thread (which doesn't give exiters a chance to aquire the lock * to update the cache list). */ if ( cache == 0 ) { while ( pendingExits && (cache == 0) ) sched_yield(); }#if defined(SCHEDULE_POLICY) sp.sched_priority = priorities[pri];#endif protectThreadList(cur); if ( !isDaemon ) nonDaemons++; unprotectThreadList(cur); if ( cache ) { protectThreadList(cur); /* move thread from the cache to the active list */ nt = cache; cache = cache->next; nCached--; nt->next = activeThreads; activeThreads = nt; nt->data.jlThread = jlThread; nt->daemon = isDaemon; nt->func = func; nt->stackCur = NULL; nt->status = THREAD_RUNNING;#if defined(SCHEDULE_POLICY) pthread_setschedparam( nt->tid, SCHEDULE_POLICY, &sp);#endif DBG( JTHREAD, TMSG_SHORT( "create recycled ", nt)); /* resurrect it */ nt->active = 1; repsem_post( &nt->sem); unprotectThreadList(cur); } else { int creation_succeeded; nt = thread_malloc( sizeof(struct _jthread) ); KGC_addRef(threadCollector, nt); pthread_attr_init( &nt->attr);#if defined(SCHEDULE_POLICY) pthread_attr_setschedparam( &nt->attr, &sp);#if defined(HAVE_PTHREAD_ATTR_SETSCHEDPOLICY) pthread_attr_setschedpolicy( &nt->attr, SCHEDULE_POLICY);#endif /* defined(HAVE_PTHREAD_ATTR_SETSCHEDPOLICY) */#endif /* defined(SCHEDULE_POLICY) */ pthread_attr_setstacksize( &nt->attr, threadStackSize); nt->data.jlThread = jlThread; nt->func = func; nt->suspendState = 0; nt->stackMin = NULL; nt->stackMax = NULL; nt->stackCur = NULL; nt->daemon = isDaemon; nt->status = THREAD_RUNNING; pthread_mutex_init(&nt->suspendLock, NULL); DBG( JTHREAD, TMSG_SHORT( "create new ", nt)); /* init our cv and mux fields for locking */ tInitLock( nt); /* Link the new one into the activeThreads list. We lock until * the newly created thread is set up correctly (i.e. is walkable) */ protectThreadList(cur); nt->active = 1; nt->next = activeThreads; activeThreads = nt; /* Note that we don't directly start 'func' because we (a) still need to * set the thread specifics, and (b) we need a looper for our thread * recycling. We create the new thread while still holding the lock, because * we otherwise might have a invalid tid in the activeList. The new thread * in turn doesn't need the lock until it exits */ creation_succeeded = pthread_create( &nt->tid, &nt->attr, tRun, nt); /* If the creation of the new thread failed for some reason, * print the reason, clean up and bail out.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -