📄 thread-impl.c
字号:
/* * thread-impl.c - pthread based ThreadInterface implementation * * Copyright (c) 1998 * Transvirtual Technologies, Inc. All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file. */#include "config.h"#include "config-std.h"#include "config-signal.h"#include "config-setjmp.h"#include "config-io.h"#include "locks.h"#include "thread-impl.h"#include "debug.h"static char stat_act[] = { ' ', 'a' };static char stat_susp[] = { ' ', 's', ' ', 'r', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };static char stat_block[] = { ' ', 'T', 'm', ' ', 'c', ' ', ' ', ' ', 't', ' ', ' ' };#if defined(KAFFE_VMDEBUG)#define TMSG_SHORT(_msg,_nt) \ dprintf(_msg" %p [tid:%4ld, java:%p]\n", \ _nt, _nt->tid, _nt->data.jlThread)#define TMSG_LONG(_msg,_nt) \ dprintf(_msg" %p [tid:%4ld, java:%p], stack [%p..%p..%p], state: %c%c%c\n", \ _nt, _nt->tid, _nt->data.jlThread, _nt->stackMin, _nt->stackCur, _nt->stackMax, \ stat_act[_nt->active], stat_susp[_nt->suspendState], stat_block[_nt->blockState])#define CHECK_CURRENT_THREAD(_nt) \ if ( ((uintp) &_nt < (uintp) _nt->stackMin) || \ ((uintp) &_nt > (uintp) _nt->stackMax) ) { \ printf( "?? inconsistent current thread: %x [tid: %d, java: %x]\n", \ _nt, _nt->tid, _nt->data.jlThread); \ tDump(); \ }#endif /* KAFFE_VMDEBUG *//*********************************************************************** * typedefs & defines */#include <bits/local_lim.h>/* * This is the configurable section. Note that SCHED_FIFO is the only * schedule policy which conforms to the "old" Java thread model (with * stringent priorities), but it usually isn't available on desktop * OSes (or imposes certain restrictions, e.g. root privileges). */#define SCHEDULE_POLICY SCHED_OTHER/* our upper create limit, to ensure we don't blow the system */#define MAX_SYS_THREADS _POSIX_THREAD_THREADS_MAX - 1/* our upper limit for cached threads (0 = no caching at all) */#define MAX_CACHED_THREADS MAX_SYS_THREADS - 3/* * Now it starts to get hackish - we have to pick some signals * for suspend/resume (enter/exitCritSect) which don't interfere * with pthread implementations. Note that we can't rely on when * a suspend signal is delivered, and it's therefore not safe * to mulitplex a sinle signal for both suspend & resume purposes */#if !defined(__SIGRTMIN) || (__SIGRTMAX - __SIGRTMIN < 3)#define SIG_SUSPEND SIGURG#define SIG_RESUME SIGTSTP#define SIG_DUMP SIGXCPU/* * Sneak these signal in from the thread library. */#define PSIG_RESTART SIGUSR1#define PSIG_CANCEL SIGUSR2#else#define SIG_SUSPEND SIGUSR1#define SIG_RESUME SIGUSR2#define SIG_DUMP SIGXCPU/* * Sneak these signal in from the thread library. */#define PSIG_RESTART (__SIGRTMIN)#define PSIG_CANCEL (__SIGRTMIN+1)#endif/*********************************************************************** * global data *//* We keep a list of all active threads, so that we can enumerate them */static jthread_t activeThreads;/* We don't throw away threads when their user func terminates, but suspend * and cache them for later re-use */static jthread_t cache;/* The notorious first thread, which has to be handled differently because * it isn't created explicitly */static jthread_t firstThread;/* Number of active non-daemon threads (the last terminating nonDaemon * causes the process to shut down */static int nonDaemons;/* Number of system threads (either running (activeThreads) or * blocked (cache). We need this to implement our own barrier, since * many kernel thread systems don't behave graceful on exceeding their limit */static int nSysThreads;/* number of currently cached threads */static int nCached;/* map the Java priority levels to whatever the pthreads impl gives us */static int *priorities;/* thread-specific-data key to retrieve 'nativeData' */pthread_key_t ntKey;/* our lock to protect list manipulation/iteration */static iStaticLock tLock;/* a hint to avoid unnecessary pthread_creates (with pending exits) */static volatile int pendingExits;/* level of critical sections (0 = none) */static int critSection;/* helper semaphore to signal completion of critical section enter/exit */static sem_t critSem;static sigset_t suspendSet;/* an optional deadlock watchdog thread (not in the activeThread list), * activated by KAFFE_VMDEBUG topic JTHREAD */#ifdef KAFFE_VMDEBUGstatic pthread_t deadlockWatchdog;#endif /* KAFFE_VMDEBUG */static void suspend_signal_handler ( int sig );static void resume_signal_handler ( int sig );static void tDispose ( jthread_t nt );static void* (*thread_malloc)(size_t);static void (*thread_free)(void*);#define TLOCK(_nt) do { \ (_nt)->blockState |= BS_THREAD; \ lockStaticMutex (&tLock); \} while(0)#define TUNLOCK(_nt) do { \ unlockStaticMutex (&tLock); \ (_nt)->blockState &= ~BS_THREAD; \} while(0)/*********************************************************************** * internal functions *//* * dump a thread list, marking the supposed to be current thread */voidtDumpList ( jthread_t cur, jthread_t list ){ int i; char a1, a2, a3; jthread_t t; for ( t=list, i=0; t; t=t->next, i++ ){ /* the supposed to be current thread? */ a1 = (t == cur) ? '*' : ' '; /* the current thread from a stack point-of view? */ a2 = (((uintp)&i > (uintp)t->stackMin) && ((uintp)&i < (uintp)t->stackMax)) ? 'S' : ' '; /* the first one? */ a3 = (t == firstThread) ? '1' : ' '; dprintf("%4d: %c%c%c %c%c%c %p [tid: %4ld, java: %p] " "stack: [%p..%p..%p]\n", i, a1, a2, a3, stat_act[t->active], stat_susp[t->suspendState], stat_block[t->blockState], t, t->tid, t->data.jlThread, t->stackMin, t->stackCur, t->stackMax); }}/* * dump the state of the threading system */voidtDump (void){ DBG(JTHREAD, { jthread_t cur = jthread_current(); void *lock = tLock.lock; void *holder = tLock.heavyLock.holder; void *mux = tLock.heavyLock.mux; //void *muxNat = tLock.heavyLock.mux ? unhand(tLock.heavyLock.mux)->PrivateInfo : 0; void *cv = tLock.heavyLock.cv; //void *cvNat = tLock.heavyLock.cv ? unhand(tLock.heavyLock.cv)->PrivateInfo : 0; int iLockRoot; TLOCK( cur); /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tLock */ dprintf("\n======================== thread dump =========================\n"); dprintf("state: nonDaemons: %d, critSection: %d\n", nonDaemons, critSection); /* dprintf("tLock: %p [holder: %p, mux: %p (native: %p), cv: %p (native: %p)]\n", lock, holder, mux, muxNat, cv, cvNat); */ dprintf("tLock: %p [holder: %p, mux: %p, cv: %p]\n", lock, holder, mux, cv); dprintf("active threads:\n"); tDumpList( cur, activeThreads); dprintf("\ncached threads:\n"); tDumpList( cur, cache); dprintf("====================== end thread dump =======================\n"); TUNLOCK( cur); /* ------------------------------------------------------ tLock */ })}/* * On demand debug signal to dump the current thread state(s) (requested * by a external "kill -s <SIG_DUMP> <proc-id>" */voiddump_signal_handler ( int sig ){ tDump();}#ifdef KAFFE_VMDEBUGstaticvoid* tWatchdogRun (void* p){ jthread_t t; int life; while ( nonDaemons ) { life = 0; for ( t=activeThreads; t != NULL; t = t->next ){ /* * if we have a single thread that is not blocked at all, is in a * timeout wait, and is not suspended, we are still safe (even though * the timeout value might effectively be a deadlock) */ if ( (!t->blockState || (t->blockState == BS_CV_TO)) && !t->suspendState ){ life = 1; break; } } if ( !life ) { DBG( JTHREAD, dprintf("deadlock\n")) tDump(); ABORT(); } usleep( 5000); } return 0;}void tStartDeadlockWatchdog (void){ pthread_attr_t attr; struct sched_param sp; sp.sched_priority = priorities[0]; /* looow */ pthread_attr_init( &attr); pthread_attr_setschedparam( &attr, &sp); pthread_attr_setstacksize( &attr, 4096); pthread_create( &deadlockWatchdog, &attr, tWatchdogRun, 0);}#endif /* KAFFE_VMDEBUG *//*********************************************************************** * thread system initialization *//* * static init of signal handlers */voidtInitSignalHandlers (void){ struct sigaction sigSuspend, sigResume, sigDump; unsigned int flags = 0;#if defined(SA_RESTART) flags |= SA_RESTART;#endif sigSuspend.sa_flags = flags; sigSuspend.sa_handler = suspend_signal_handler; sigemptyset( &sigSuspend.sa_mask); sigaddset( &sigSuspend.sa_mask, SIG_SUSPEND); sigaddset( &sigSuspend.sa_mask, SIG_RESUME); sigaddset( &sigSuspend.sa_mask, PSIG_RESTART); sigaddset( &sigSuspend.sa_mask, PSIG_CANCEL); sigaddset( &sigSuspend.sa_mask, SIGSTOP); sigaddset( &sigSuspend.sa_mask, SIGCONT); sigaddset( &sigSuspend.sa_mask, SIGWINCH); sigaction( SIG_SUSPEND, &sigSuspend, NULL); sigResume.sa_flags = 0; // Note that we do not want restart here. sigResume.sa_handler = resume_signal_handler; sigResume.sa_mask = sigSuspend.sa_mask; sigaction( SIG_RESUME, &sigResume, NULL);#if defined(SIG_DUMP) sigDump.sa_flags = flags; sigDump.sa_handler = dump_signal_handler; sigemptyset( &sigDump.sa_mask); sigaction( SIG_DUMP, &sigDump, NULL);#endif}/* * static init set up of Java-to-pthread priority mapping (pthread prioritiy levels * are implementation dependent) */staticvoid tMapPriorities (int npr){ int d, min, max, i; float r; min = sched_get_priority_min( SCHEDULE_POLICY); max = sched_get_priority_max( SCHEDULE_POLICY); 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' */ sem_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)); 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,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -