📄 thread-impl.c
字号:
/* * per-native thread init of semaphore */staticvoidtInitLock ( nativeThread* nt ){ /* init a non-shared (process-exclusive) semaphore with value '0' */ sem_init( &nt->sem, 0, 0);}/* * We must have a certain amount of credible thread information setup * as soon as possible. */staticvoidtSetupFirstNative(void){ nativeThread* nt; /* * We need to have a native thread context available as soon as possible. */ nt = thread_malloc( sizeof(nativeThread)); 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, int maxpr, int minpr, void *(*_allocator)(size_t), void (*_deallocator)(void*), void (*_destructor1)(void*), void (*_onstop)(void), void (*_ondeadlock)(void)){ DBG( vm_thread, ("initialized\n")); thread_malloc = _allocator; thread_free = _deallocator; pthread_key_create( &ntKey, NULL); sem_init( &critSem, 0, 0); tMapPriorities(); tInitSignalHandlers(); sigfillset( &suspendSet); sigdelset( &suspendSet, SIG_RESUME); tSetupFirstNative(); DBG_ACTION( vm_thread, { tStartDeadlockWatchdog(); });}nativeThread*jthread_createfirst(size_t mainThreadStackSize, unsigned char pri, void* jlThread){ Hjava_lang_Thread* thread; nativeThread* nt; int oldCancelType; thread = (Hjava_lang_Thread*)jlThread; nt = GET_CURRENT_THREAD( &nt ); /* 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->thread = thread; nt->suspendState = 0; nt->active = 1; nt->func = NULL; nt->next = NULL; /* Get stack boundaries. Note that this is just an approximation * which should cover all gc-relevant stack locations */#if defined(STACK_GROWS_UP) nt->stackMin = (void*) ((uintp)&nt & -0x1000) nt->stackMax = (void*) ((uintp) nt->stackMin + mainThreadStackSize);#else nt->stackMax = (void*) (((uintp)&nt + 0x1000 - 1) & -0x1000); nt->stackMin = (void*) ((uintp) nt->stackMax - mainThreadStackSize);#endif DBG( vm_thread, 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); unhand(thread)->PrivateInfo = (struct Hkaffe_util_Ptr*)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);}/* * 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 ){ nativeThread *cur = (nativeThread*)p; nativeThread *t; size_t ss; int oldCancelType; int iLockRoot; /* 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 */ sem_post( &cur->sem); while ( 1 ) { DBG( vm_thread, 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->thread); DBG( vm_thread, TMSG_LONG( "exiting user func of: ", cur)); TLOCK( cur); /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tLock */ /* 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 */ unhand(cur->thread)->PrivateInfo = 0; cur->thread = 0; cur->suspendState = 0; /* link into cache list (if still within limit) */ if ( ++nCached < MAX_CACHED_THREADS ){ cur->next = cache; cache = cur; DBG( vm_thread, TMSG_SHORT( "cached thread ", cur)); } pendingExits--; TUNLOCK( cur); /* ---------------------------------------------------- tLock */ if ( nCached >= MAX_CACHED_THREADS ){ break; } /* Wait until we get re-used (by TcreateThread). No need to update the * blockState, since we aren't active anymore */ sem_wait( &cur->sem); /* * we have already been moved back to the activeThreads list by * Tcreate (saves us a lock) */ DBG( vm_thread, TMSG_SHORT( "reused thread ", cur)); } tDispose( cur); return 0;}/* * 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 */nativeThread*jthread_create ( unsigned char pri, void* func, int daemon, void* jlThread, size_t threadStackSize ){ nativeThread *cur = GET_CURRENT_THREAD( &self); nativeThread *nt; struct sched_param sp; Hjava_lang_Thread* thread = (Hjava_lang_Thread*)jlThread; int iLockRoot; /* 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(); } sp.sched_priority = priorities[unhand(thread)->priority]; if ( !unhand(thread)->daemon ) nonDaemons++; if ( cache ) { TLOCK( cur); /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tLock */ /* move thread from the cache to the active list */ nt = cache; cache = cache->next; nCached--; nt->next = activeThreads; activeThreads = nt; nt->thread = thread; nt->func = func; nt->stackCur = 0; unhand(thread)->PrivateInfo = (struct Hkaffe_util_Ptr*)nt; pthread_setschedparam( nt->tid, SCHEDULE_POLICY, &sp); DBG( vm_thread, TMSG_SHORT( "create recycled ", nt)); /* resurrect it */ nt->active = 1; sem_post( &nt->sem); TUNLOCK( cur); /* ---------------------------------------------------- tLock */ } else { if ( nSysThreads++ > MAX_SYS_THREADS ){ // bail out, we exceeded our physical thread limit DBG( vm_thread, ( "too many threads (%d)\n", nSysThreads)); return (0); } nt = thread_malloc( sizeof(nativeThread) ); pthread_attr_init( &nt->attr); pthread_attr_setschedparam( &nt->attr, &sp); pthread_attr_setschedpolicy( &nt->attr, SCHEDULE_POLICY); pthread_attr_setstacksize( &nt->attr, threadStackSize); nt->thread = thread; nt->func = func; nt->suspendState = 0; nt->stackMin = 0; nt->stackMax = 0; nt->stackCur = 0; unhand(thread)->PrivateInfo = (struct Hkaffe_util_Ptr*)nt; DBG( vm_thread, 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) */ TLOCK( cur); /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++ tLock */ 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 */ pthread_create( &nt->tid, &nt->attr, tRun, nt); /* wait until the thread specific data has been set, and the new thread * is in a suspendable state */ sem_wait( &nt->sem); TUNLOCK( cur); /* ---------------------------------------------------- tLock */ } return (nt);}/*********************************************************************** * thread exit & cleanup *//* * Native thread cleanup. This is just called in case a native thread * is not cached */staticvoidtDispose ( nativeThread* nt ){ pthread_detach( nt->tid); sem_destroy( &nt->sem); thread_free( nt);}/* * Function to be called (by threads.c firstStartThread) when the thread leaves * the user thread function */voidjthread_exit ( void ){ Hjava_lang_Thread *thread = tCurrentJava(); nativeThread *cur = NATIVE_THREAD( thread); nativeThread *t; int iLockRoot; /* * We are leaving the thread user func, which means we are not * subject to GC, anymore (has to be marked here because the first thread * never goes through tRun) */ cur->active = 0; DBG( vm_thread, TMSG_SHORT( "exit ", cur)); if ( !unhand(thread)->daemon ){ /* the last non daemon should shut down the process */ if ( --nonDaemons == 0 ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -