📄 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 <pthread.h>#include <semaphore.h>#include <sched.h>#include "config.h"#include "config-std.h"#include "config-signal.h"#include "java_lang_Throwable.h"#include "gtypes.h"#include "thread.h"#include "gc.h"#include "jni.h"#include "locks.h"#define DBG(X,Y)/* these are required for handling exceptions */#include "exception.h"#if defined(INTERPRETER)#define DEFINEFRAME() /* Does nothing */#define EXCEPTIONPROTO int sig#define EXCEPTIONFRAME(f, c) /* Does nothing */#define EXCEPTIONFRAMEPTR 0#elif defined(TRANSLATOR)#define DEFINEFRAME() exceptionFrame frame#define EXCEPTIONFRAMEPTR &frame#endif /* TRANSLATOR *//* Some systems need special setups for the exception handling */#if !defined(EXCEPTIONSTART)#define EXCEPTIONSTART()#endif#if !defined(EXCEPTIONEND)#define EXCEPTIONEND()#endif#if defined(DEBUG)char stat_act[] = { ' ', 'a' };char stat_susp[] = { ' ', 's', ' ', 'r', ' ', ' ', ' ', ' ', ' ', ' ', ' ' };char stat_block[] = { ' ', 'T', 'm', ' ', 'c', ' ', ' ', ' ', 't', ' ', ' ' };#endif/*********************************************************************** * 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 */nativeThread *activeThreads;/* We don't throw away threads when their user func terminates, but suspend * and cache them for later re-use */nativeThread *cache;/* The notorious first thread, which has to be handled differently because * it isn't created explicitly */nativeThread *firstThread;/* Number of active non-daemon threads (the last terminating nonDaemon * causes the process to shut down */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 */int nSysThreads;/* number of currently cached threads */int nCached;/* map the Java priority levels to whatever the pthreads impl gives us */int priorities[java_lang_Thread_MAX_PRIORITY];/* thread-specific-data key to retrieve 'nativeData' */pthread_key_t ntKey;/* our lock to protect list manipulation/iteration */static iLock* tLock;/* a hint to avoid unnecessary pthread_creates (with pending exits) */volatile int pendingExits;/* level of critical sections (0 = none) */int critSection;/* helper semaphore to signal completion of critical section enter/exit */sem_t critSem;sigset_t suspendSet;/* an optional deadlock watchdog thread (not in the activeThread list), * activated by DEBUG topic vm_thread */pthread_t deadlockWatchdog;void suspend_signal_handler ( int sig );void resume_signal_handler ( int sig );static void tDispose ( nativeThread* nt );static void* (*thread_malloc)(size_t);static void (*thread_free)(void*);extern void nullException(int);#define LOCKSLOT int iLockRoot#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 *//* * 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();}/* * dump a thread list, marking the supposed to be current thread */voidtDumpList ( nativeThread *cur, nativeThread* list ){ int i; char a1, a2, a3; nativeThread *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' : ' '; DBG( vm_thread, ("%4d: %c%c%c %c%c%c %p [tid: %4d, 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->thread, t->stackMin, t->stackCur, t->stackMax)); }}/* * dump the state of the threading system */voidtDump (void){ DBG_ACTION( vm_thread, { nativeThread *cur = pthread_getspecific( ntKey); void *lock = tLock; void *holder = tLock->holder; void *mux = tLock->mux; void *muxNat = tLock->mux ? unhand(tLock->mux)->PrivateInfo : 0; void *cv = tLock->cv; void *cvNat = tLock->cv ? unhand(tLock->cv)->PrivateInfo : 0; TLOCK( cur); /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ tLock */ DBG( vm_thread,("\n======================== thread dump =========================\n")); DBG( vm_thread, ("state: nonDaemons: %d, critSection: %d\n", nonDaemons, critSection)); DBG( vm_thread, ("tLock: %p [holder: %p, mux: %p (native: %p), cv: %p (native: %p)]\n", lock, holder, mux, muxNat, cv, cvNat)); DBG( vm_thread, ("active threads:\n")); tDumpList( cur, activeThreads); DBG( vm_thread, ("\ncached threads:\n")); tDumpList( cur, cache); DBG( vm_thread, ("====================== end thread dump =======================\n")); TUNLOCK( cur); /* ------------------------------------------------------ tLock */ });}staticvoid*tWatchdogRun (void* p){ nativeThread *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( vm_thread, ("deadlock\n")); tDump(); ABORT(); } usleep( 5000); } return 0;}voidtStartDeadlockWatchdog (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);}/*********************************************************************** * thread system initialization *//* * static init of signal handlers */voidtInitSignalHandlers (void){ struct sigaction sigSuspend, sigResume, sigSegv, 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 = flags; 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 sigSegv.sa_flags = flags;#if defined(SA_SIGINFO) sigSegv.sa_flags |= SA_SIGINFO;#endif#if defined(SA_NOMASK) sigSegv.sa_flags |= SA_NOMASK;#endif sigSegv.sa_handler = (void(*)(int)) nullException; sigemptyset( &sigSegv.sa_mask); sigaction( SIGSEGV, &sigSegv, NULL);}/* * static init set up of Java-to-pthread priority mapping (pthread prioritiy levels * are implementation dependent) */staticvoidtMapPriorities (void){ int d, min, max, n, i; float r; min = sched_get_priority_min( SCHEDULE_POLICY); max = sched_get_priority_max( SCHEDULE_POLICY); d = max - min; n = sizeof(priorities) / sizeof(priorities[0]); r = (float)d / (float)n; for ( i=0; i<n; i++ ) { priorities[i] = (int)(i*r + 0.5) + min; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -