⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 jthread.c

📁 linux下建立JAVA虚拟机的源码KAFFE
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * jthread.c * Java thread package - derived from thread-internal.c * * Internal threading system support * * Copyright (c) 1996, 1997, 1998 *      Transvirtual Technologies, Inc.  All rights reserved. * * See the file "license.terms" for information on usage and redistribution * of this file. * * Written by Godmar Back <gback@cs.utah.edu> and  *            Tim Wilkinson <tim@transvirtual.com> */#include "config.h"#if defined(HAVE_SYS_TYPES_H)#include <sys/types.h>#endif /* defined(HAVE_SYS_TYPES_H) */#if defined(HAVE_SYS_WAIT_H)#include <sys/wait.h>#endif /* defined(HAVE_SYS_WAIT_H) */#include "jthread.h"#include "jsignal.h"#include "xprofiler.h"#include "jqueue.h"/* For NOTIMEOUT */#include "jsyscall.h"/* For jlong */#include "jni_md.h"/* For Hjava_lang_VMThread */#include "thread.h"#include "gc.h"/* Flags used for threading I/O calls */#define TH_READ                         0#define TH_WRITE                        1#define TH_ACCEPT                       TH_READ#define TH_CONNECT                      TH_WRITE/* * If option DETECTDEADLOCK is given, detect deadlocks.   * A deadlock is defined as a situation where no thread is runnable and  * no threads is blocked on a timer, IO, or other external events. * * Undeffing this will save a few cycles, but kaffe will just hang if * there is a deadlock. */#define DETECTDEADLOCK#if defined(DETECTDEADLOCK)#define BLOCKED_ON_EXTERNAL(t)						\	do {								\	    tblocked_on_external++; 					\	    t->flags |= THREAD_FLAGS_BLOCKEDEXTERNAL;			\	} while (0)#define CLEAR_BLOCKED_ON_EXTERNAL(t) 					\	do {								\		if (t->flags & THREAD_FLAGS_BLOCKEDEXTERNAL) { 		\			tblocked_on_external--; 			\			t->flags &= ~THREAD_FLAGS_BLOCKEDEXTERNAL;	\		}							\	} while (0)/* number of threads blocked on external events */static int tblocked_on_external;#else /* !DETECTDEADLOCK */#define BLOCKED_ON_EXTERNAL(t)#define CLEAR_BLOCKED_ON_EXTERNAL(t)#endif/* * Variables. * These should be kept static to ensure encapsulation. */static int preemptive = true;	/* enable preemptive scheduling */static int talive; 		/* number of threads alive */static int tdaemon;		/* number of daemons alive */static void (*runOnExit)(void);	/* function to run when all non-daemon die */#define JTHREADQ(q) ((jthread *)(q)->element)static KaffePool *queuePool;    /* pool of single-linked node */static KaffeNodeQueue**threadQhead;	/* double-linked run queue */ static KaffeNodeQueue**threadQtail;static KaffeNodeQueue* liveThreads;	/* list of all live threads */static KaffeNodeQueue* alarmList;	/* list of all threads on alarm queue */static KaffeNodeQueue* waitForList;	/* list of all threads waiting for a child */static int maxFd = -1;		/* highest known fd */static fd_set readsPending;	/* fds we want to read from */static fd_set writesPending;	/* fds we want to write to */static KaffeNodeQueue* readQ[FD_SETSIZE];	/* threads blocked on read */static KaffeNodeQueue* writeQ[FD_SETSIZE];	/* threads blocked on write */static jboolean blockingFD[FD_SETSIZE];            /* file descriptor which should 						   really block */static jmutex threadLock;	/* static lock to protect liveThreads etc. */static jmutex GClock;static int sigPending;		/* flags that says whether a intr is pending */static int pendingSig[NSIG];	/* array that says which intrs are pending */static int sigPipe[2];		/* a pipe to ensure we don't lose our wakeup */static int bytesInPipe;		/* total number of bytes written to pipe */static int wouldlosewakeup;	/* a flag that says whether we're past the				   point where we check for pending signals 				   before sleeping in select() */static int blockInts;		/* counter that says whether irqs are blocked */static int needReschedule;	/* is a change in the current thread required *//** This is the garbage collector to use to allocate thread data. */static Collector *threadCollector;/* * the following variables are set by jthread_init, and show how the * threading system is parametrized. */static void (*destructor1)(void*);	/* call when a thread exits */static void (*onstop)(void);		/* call when a thread is stopped */static void (*ondeadlock)(void);	/* call when we detect deadlock */static int  max_priority;		/* maximum supported priority */static int  min_priority;		/* minimum supported priority */jthread* currentJThread = NULL;static jthread* firstThread = NULL;/* Context switch related functions */#ifndef JTHREAD_CONTEXT_SAVE#define JTHREAD_CONTEXT_SAVE(buf)		JTHREAD_SETJMP((buf))#endif#ifndef JTHREAD_CONTEXT_RESTORE#define JTHREAD_CONTEXT_RESTORE(buf, val)	JTHREAD_LONGJMP((buf), (val))#endif/* The arguments to a signal handler */#ifndef SIGNAL_ARGS#define SIGNAL_ARGS(sig, sc) int sig#endif/* Get a signal context pointer from signal arguments */#ifndef GET_SIGNAL_CONTEXT_POINTER#define GET_SIGNAL_CONTEXT_POINTER(x) 0#endif/* A signal context pointer type, used in parameter lists/declarations */#ifndef SIGNAL_CONTEXT_POINTER#define SIGNAL_CONTEXT_POINTER(x) void *x#endif/* Get the PC from a signal context pointer */#ifndef SIGNAL_PC#define SIGNAL_PC(scp) 0#endif/* * Function declarations. * Again, keep these static to ensure encapsulation. */static void handleInterrupt(int sig, SIGNAL_CONTEXT_POINTER(sc));static void interrupt(SIGNAL_ARGS(sig, sc));static void childDeath(void);static void handleIO(int);static void killThread(jthread *jtid);static void resumeThread(jthread* jtid);static void reschedule(void);static void restore_fds(void);static void restore_fds_and_exit(void);static void die(void);static int jthreadedFileDescriptor(int fd);static void intsDisable(void);static void intsRestore(void);static void addWaitQThread(jthread *jtid, KaffeNodeQueue **queue);static void cleanupWaitQ(jthread *jtid);/* * macros to set and extract stack pointer from jmp_buf * make sure SP_OFFSET has the correct value for your architecture! */#define GET_SP(E)       (((void**)(E))[SP_OFFSET])#define SET_SP(E, V)    ((void**)(E))[SP_OFFSET] = (V)#define GET_FP(E)       (((void**)(E))[FP_OFFSET])#define SET_FP(E, V)    ((void**)(E))[FP_OFFSET] = (V)/* * Macros to set and extract backing store pointer from jmp_buf * (IA-64 specific) */#if defined(__ia64__)#define BSP_OFFSET	17#define GET_BSP(E)	(((void**)(E))[BSP_OFFSET])#define SET_BSP(E, V)	((void**)(E))[BSP_OFFSET] = (V)#endif/* Set the base pointer in a jmp_buf if we can (only a convenience) */#if defined(BP_OFFSET)#define SET_BP(E, V)    ((void**)(E))[BP_OFFSET] = (V)#endif/* amount of stack space to be duplicated at stack creation time */#if !defined(STACK_COPY)#define STACK_COPY      (32*4)#endif#if defined(HAVE_SYS_WAIT_H)#include <sys/wait.h>#endif/* Select an alarm system */#if defined(HAVE_SETITIMER) && defined(ITIMER_REAL)#define	MALARM(_mt)							\	{								\		struct itimerval tm;					\		tm.it_interval.tv_sec = 0;				\		tm.it_interval.tv_usec = 0;				\		tm.it_value.tv_sec = (_mt) / 1000;			\		tm.it_value.tv_usec = ((_mt) % 1000) * 1000;		\		setitimer(ITIMER_REAL, &tm, 0);				\	}#elif defined(HAVE_ALARM)#define	MALARM(_mt)	alarm((int)(((_mt) + 999) / 1000))#endif/*============================================================================ * * Functions related to list manipulation and interrupt handling * *//* * Check whether a thread is on a given list */static intisOnList(KaffeNodeQueue *list, jthread *t){	for (; list != NULL; list = list->next) {		if (JTHREADQ(list) == t) {			return (1);		}	}	return (0);}/* * yield to another thread */static inline voidinternalYield(void){        int priority = currentJThread->priority;            if (threadQhead[priority] != 0 &&		threadQhead[priority] != threadQtail[priority])        {                /* Get the first thread and move it to the end */		KaffeNodeQueue *firstThreadNode = threadQhead[priority];                threadQhead[priority] = firstThreadNode->next;                  threadQtail[priority]->next = firstThreadNode;                threadQtail[priority] = firstThreadNode;                firstThreadNode->next = 0;                needReschedule = true;        }}static voidaddToAlarmQ(jthread* jtid, jlong timeout){	KaffeNodeQueue** tidp;	KaffeNodeQueue* node;	jlong ct;	assert(intsDisabled());	ct = currentTime();	if( (timeout + ct) > ct ) {		jtid->flags |= THREAD_FLAGS_ALARM;				/* Get absolute time */		jtid->time = timeout + ct;				/* Find place in alarm list and insert it */		for (tidp = &alarmList;		     (*tidp) != 0;		     tidp = &(*tidp)->next) {		        if (JTHREADQ(*tidp)->time > jtid->time)			{				break;			}		}		node = KaffePoolNewNode(queuePool);		node->next = *tidp;		node->element = jtid;		*tidp = node;				/* If I'm head of alarm list, restart alarm */		if (tidp == &alarmList)		{			MALARM(timeout);		}	} else {		/* Huge timeout value, ignore it. */	}}static voidremoveFromAlarmQ(jthread* jtid){	KaffeNodeQueue** tidp;	assert(intsDisabled());	jtid->flags &= ~THREAD_FLAGS_ALARM;	/* Find thread in alarm list and remove it */	for (tidp = &alarmList; (*tidp) != 0; tidp = &(*tidp)->next)	{		if (JTHREADQ(*tidp) == jtid)		{			KaffeNodeQueue *node = *tidp;					(*tidp) = node->next;			KaffePoolReleaseNode(queuePool, node);			break;		}	}}/* * check whether interrupts are disabled */intintsDisabled(void){        return (blockInts > 0);}/* * disable interrupts * * Instead of blocking signals, we increment a counter. * If a signal comes in while the counter is non-zero, we set a pending flag * and mark the signal as pending. * * intsDisable may be invoked recursively. (is that really a good idea? - gb) */static inline void intsDisable(void){        blockInts++;}static inline voidprocessSignals(void){	int i;	for (i = 1; i < NSIG; i++)	{		if (pendingSig[i])		{			pendingSig[i] = 0;			handleInterrupt(i, 0);		}	}	sigPending = 0;}/* * restore interrupts * * If interrupts are about to be reenabled, execute the handlers for all * signals that are pending. */static inline voidintsRestore(void){         /* KAFFE_VMDEBUG */        assert(blockInts >= 1);        if (blockInts == 1) {                if (sigPending) {			processSignals();		} 		/* reschedule if necessary */                if (needReschedule == true) {                        reschedule(); 		}        }        blockInts--;}/* * Prevent all other threads from running. * In this uniprocessor implementation, this is simple. */void jthread_suspendall(void){        intsDisable();}/* * Reallow other threads. * In this uniprocessor implementation, this is simple. */void jthread_unsuspendall(void){        intsRestore();}  /* * Handle an asynchronous signal (i.e. a software interrupt). * * This is the handler given to registerAsyncSignalHandler(). * * It is guaranteed that all asynchronous signals are delayed when * this handler begins execution (see registerAsyncSignalHandler()). * There are two ways for the asynchronous signals to get unblocked: * (1) return from the function.  The OS will unblock them.  (2) * explicitly unblock the signals.  We must do this before performing * a thread context switch as the target thread should (obviously) not * be running with all signals blocked. */static voidinterrupt(SIGNAL_ARGS(sig, sc)){	if( currentJThread->status != THREAD_SUSPENDED )	{#ifdef ENABLE_JVMPI		EXCEPTIONFRAME(jthread_current()->localData.topFrame, sc);#endif	}		/*	 * If ints are blocked, this might indicate an inconsistent state of	 * one of the thread queues (either alarmList or threadQhead/tail).	 *	 * Record this interrupt as pending so that the forthcoming	 * intsRestore() (the intsRestore() in the interrupted thread)	 * will handle it.  Then return from the signal handler.	 *	 * Also mark the interrupt as pending if interrupts are not disabled,	 * but the wouldlosewakeup flag is set.  This is the case before	 * we go in select/poll.	 */	if (intsDisabled() || wouldlosewakeup) {		char c;		pendingSig[sig] = 1;		sigPending = 1;		#if defined(KAFFE_XPROFILER)		/*		 * Since the regular handler won't run with the sig context we		 * need to do the hit here		 */		if( sig == SIGVTALRM )		{			SIGNAL_CONTEXT_POINTER(scp) =				GET_SIGNAL_CONTEXT_POINTER(sc);							profileHit((char *)SIGNAL_PC(scp));		}#endif		/*		 * There is a race condition in handleIO() between		 * zeroing blockints and going into select().		 * sigPipe+wouldlosewakeup is the hack that avoids		 * that race condition.  See handleIO().		 *		 * If we would lose the wakeup because we're about to go to		 * sleep in select(), write into the sigPipe to ensure select		 * returns.		 */		/*		 * Write a byte in the pipe if we get a signal if 		 * wouldlosewakeup is set.  		 * Do not write more than one byte, however.		 */		if (wouldlosewakeup == 1) {			write(sigPipe[1], &c, 1);			bytesInPipe++;			wouldlosewakeup++;		}#if defined(KAFFE_SIGNAL_ONE_SHOT)		/*		 * On some systems, signal handlers are a one-shot deal.		 * Re-install the signal handler for those systems.		 */		restoreAsyncSignalHandler(sig, interrupt);#endif		/*		 * Returning from the signal handler should restore		 * all signal state (if the OS is not broken).		 */		return;	}	/*	 * The interrupted code was not in a critical section,	 * so we enter a critical section now.  Note that we	 * will *not* be interrupted between the blockInts	 * check above and the intsDisable() below because	 * the signal mask delays all asynchronous signals.	 */	intsDisable();#if defined(KAFFE_SIGNAL_ONE_SHOT)	/* Re-enable signal if necessary */        restoreAsyncSignalHandler(sig, interrupt);#endif	/*	 * Restore the signal state.  This means unblock all	 * asynchronous signals.  We can now context switch to another	 * thread as the signal state for the Kaffe process is clear	 * in the eyes of the OS.  Any asynchronous signals that come	 * in because we just unblocked them will discover that	 * blockInts > 0, and flag their arrival in the pendingSig[]	 * array.	 *	 * We clear the signal's pending indicator before reallowing signals.	 */	pendingSig[sig] = 0;	unblockAsyncSignals();	/*	 * Handle the signal.	 */	handleInterrupt(sig, (void*)GET_SIGNAL_CONTEXT_POINTER(sc));	/*	 * Leave the critical section.  This may or may not cause a	 * reschedule.  (Depends on the side-effects of	 * handleInterrupt()).	 */	intsRestore();}/* * handle a SIGVTALRM alarm. * * If preemption is disabled, we have the current thread so that it is * scheduled in a round-robin fashion with its peers who have the same * priority. */static void handleVtAlarm(int sig UNUSED, SIGNAL_CONTEXT_POINTER(sc UNUSED)){	static int c;#if defined(KAFFE_XPROFILER)	if( sc )		profileHit((char *)SIGNAL_PC(sc));#endif	if (preemptive) {		internalYield();	}	/*	 * This is kind of ugly: some fds won't send us SIGIO.	 * Example: the pseudo-tty driver in FreeBSD won't send a signal	 * if we blocked on a write because the output buffer was full, and	 * the output buffer became empty again.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -