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

📄 jthread.c

📁 kaffe是一个java虚拟机的源代码。里面包含了一些java例程和标准的java包。
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * 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 "jthread.h"#include "jsignal.h"#include "xprofiler.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/* thread status */#define THREAD_SUSPENDED                0#define THREAD_RUNNING                  1#define THREAD_DEAD                     2/* thread flags */#define THREAD_FLAGS_GENERAL            0#define THREAD_FLAGS_NOSTACKALLOC       1   /* this flag is not used anymore */#define THREAD_FLAGS_KILLED             2#define THREAD_FLAGS_ALARM              4#define THREAD_FLAGS_EXITING        	8#define THREAD_FLAGS_DONTSTOP        	16#define THREAD_FLAGS_DYING        	32#define THREAD_FLAGS_BLOCKEDEXTERNAL	64#define THREAD_FLAGS_INTERRUPTED	128/* * 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 */static jthread**threadQhead;	/* double-linked run queue */ static jthread**threadQtail;static jthread* liveThreads;	/* list of all live threads */static jthread* alarmList;	/* list of all threads on alarm queue */static jthread* 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 jthread* readQ[FD_SETSIZE];	/* threads blocked on read */static jthread* writeQ[FD_SETSIZE];	/* threads blocked on write */static jmutex threadLock;	/* static lock to protect liveThreads etc. */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 *//* * the following variables are set by jthread_init, and show how the * threading system is parametrized. */static void *(*allocator)(size_t); 	/* malloc */static void (*deallocator)(void*);	/* free */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;/* 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);/* * 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(jthread *list, jthread *t){	for (; list; list = list->nextQ) {		if (list == t) {			return (1);		}	}	return (0);}/* * yield to another thread */static inline voidinternalYield(void){        int priority = currentJThread->priority;            if (threadQhead[priority] &&		threadQhead[priority] != threadQtail[priority])        {                /* Get the first thread and move it to the end */		jthread *firstThread = threadQhead[priority];                threadQhead[priority] = firstThread->nextQ;                  threadQtail[priority]->nextQ = firstThread;                threadQtail[priority] = firstThread;                firstThread->nextQ = 0;                needReschedule = true;        }}static voidaddToAlarmQ(jthread* jtid, jlong timeout){	jthread** tidp;	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)->nextalarm) {			if ((*tidp)->time > jtid->time) {				break;			}		}		jtid->nextalarm = *tidp;		*tidp = jtid;				/* If I'm head of alarm list, restart alarm */		if (tidp == &alarmList) {			MALARM(timeout);		}	} else {		/* Huge timeout value, ignore it. */	}}static voidremoveFromAlarmQ(jthread* jtid){	jthread** tidp;	assert(intsDisabled());	jtid->flags &= ~THREAD_FLAGS_ALARM;	/* Find thread in alarm list and remove it */	for (tidp = &alarmList; (*tidp) != 0; tidp = &(*tidp)->nextalarm) {		if ((*tidp) == jtid) {			(*tidp) = jtid->nextalarm;			jtid->nextalarm = 0;			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){         /* DEBUG */        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 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 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 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, 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, SIGNAL_CONTEXT_POINTER(sc)){	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.	 *	 * So we check periodically, every 0.2 seconds virtual time.	 */	if (++c % 20 == 0) {		handleIO(false);	}}/* * handle a SIGALRM alarm. */static void alarmException(void){	jthread* jtid;	jlong time;	/* Wake all the threads which need waking */	time = currentTime();	while (alarmList != 0 && alarmList->time <= time) {		/* Restart thread - this will tidy up the alarm and blocked		 * queues.		 */		jtid = alarmList;		alarmList = alarmList->nextalarm;		jtid->flags |= THREAD_FLAGS_INTERRUPTED;		resumeThread(jtid);	}	/* Restart alarm */	if (alarmList != 0) {		MALARM(alarmList->time - time);	}}/* * print thread flags in pretty form. */static char*printflags(unsigned i){	static char b[256];	/* plenty */	struct {		int flagvalue;		char *flagname;	} flags[] = {	    { THREAD_FLAGS_GENERAL, "GENERAL" },	    { THREAD_FLAGS_NOSTACKALLOC, "NOSTACKALLOC" },	    { THREAD_FLAGS_KILLED, "KILLED" },	    { THREAD_FLAGS_ALARM, "ALARM" },	    { THREAD_FLAGS_EXITING, "EXITING" },	    { THREAD_FLAGS_DONTSTOP, "DONTSTOP" },	    { THREAD_FLAGS_DYING, "DYING" },	    { THREAD_FLAGS_BLOCKEDEXTERNAL, "BLOCKEDEXTERNAL" },	    { THREAD_FLAGS_INTERRUPTED, "INTERRUPTED" },	    { 0, NULL }	}, *f = flags;	b[0] = '\0';	while (f->flagname) {		if (i & f->flagvalue) {			strcat(b, f->flagname);			strcat(b, " ");		}		f++;	}	return b;}/*  * dump information about a thread to stderr */voidjthread_dumpthreadinfo(jthread_t tid){	dprintf("tid %p, status %s flags %s\n", tid, 		tid->status == THREAD_SUSPENDED ? "SUSPENDED" :		tid->status == THREAD_RUNNING ? "RUNNING" :		tid->status == THREAD_DEAD ? "DEAD" : "UNKNOWN!!!", 		printflags(tid->flags));	if (tid->blockqueue != NULL) {		jthread *t;		int i;		dprintf(" blocked");		if (isOnList(waitForList, tid)) {			dprintf(": waiting for children");		}#if 0		/* XXX FIXME: alarmList uses nextalarm, but isOnList iterates		 * using nextQ		 */		if (isOnList(alarmList, tid)) {			dprintf(": sleeping");		}#endif		for (i = 0; i < FD_SETSIZE; i++) {			if (isOnList(readQ[i], tid)) {				dprintf(": reading from fd %d ", i);				break;			}			if (isOnList(writeQ[i], tid)) {				dprintf(": writing to fd %d ", i);				break;			}		}		dprintf("@%p (%p->", tid->blockqueue,					     t = *tid->blockqueue);		while (t && t->nextQ) {			t = t->nextQ; 			dprintf("%p->", t);		}		dprintf("|) ");	}}/* * handle an interrupt. *  * this function is either invoked from within a signal handler, or as the * result of intsRestore. */static void handleInterrupt(int sig, SIGNAL_CONTEXT_POINTER(sc)){	switch(sig) {	case SIGALRM:		alarmException();		break;

⌨️ 快捷键说明

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