jthread.c

来自「kaffe Java 解释器语言,源码,Java的子集系统,开放源代码」· C语言 代码 · 共 2,882 行 · 第 1/5 页

C
2,882
字号
		jthread* tid;		KaffeNodeQueue* node = lock->waiting;		tid = JTHREADQ(node);		lock->waiting = node->next;		KaffePoolReleaseNode(queuePool, node);		assert(tid->status != THREAD_RUNNING);		resumeThread(tid);	}	intsRestore();}voidjmutex_destroy(jmutex *lock){	assert(lock->holder == NULL);	assert(lock->waiting == NULL);}voidjcondvar_initialise(jcondvar *cv){	*cv = NULL;}jbooljcondvar_wait(jcondvar *cv, jmutex *lock, jlong timeout){	jthread *current = jthread_current();	jbool r;	intsDisable();	/* give up mutex */	lock->holder = NULL;	if (lock->waiting != NULL) {		jthread* tid;		KaffeNodeQueue* node = lock->waiting;		tid = JTHREADQ(node);		lock->waiting = node->next;		KaffePoolReleaseNode(queuePool, node);		assert(tid->status != THREAD_RUNNING);		resumeThread(tid);	}#if defined(DETECTDEADLOCK)	/* a limited wait should not cause us to scream deadlock */	if (timeout != 0) {		BLOCKED_ON_EXTERNAL(currentJThread);	}#endif	/* wait to be signaled */	current->flags |= THREAD_FLAGS_WAIT_CONDVAR;	r = suspendOnQThread(current, cv, timeout);	current->flags &= ~THREAD_FLAGS_WAIT_CONDVAR;	/* reacquire mutex */	current->flags |= THREAD_FLAGS_WAIT_MUTEX;	while (lock->holder != NULL) {		suspendOnQThread(current, &lock->waiting, NOTIMEOUT);	}	current->flags &= ~THREAD_FLAGS_WAIT_MUTEX;	lock->holder = current;	intsRestore();	return (r);}voidjcondvar_signal(jcondvar *cv, jmutex *lock){	intsDisable();	if (*cv != NULL) {		KaffeNodeQueue* condQ;		/* take off condvar queue */		condQ = *cv;		*cv = condQ->next;		/* put on lock queue */		condQ->next = lock->waiting;		lock->waiting = condQ;	}	intsRestore();}voidjcondvar_broadcast(jcondvar *cv, jmutex *lock){	intsDisable();	if (*cv != NULL) {		/* splice the lists `*cv' and `lock->waiting' */		KaffeNodeQueue** condp;		/* advance to last element in cv list */		for (condp = cv; *condp != 0; condp = &(*condp)->next)			;		(*condp) = lock->waiting;		lock->waiting = *condp;		*condp = NULL;	}	intsRestore();}voidjcondvar_destroy(jcondvar* cv){	assert(*cv == NULL);}/*============================================================================ *  * I/O routines that are exported to the user * *//* * Create a threaded file descriptor. * * We try various fcntl and ioctl to put the file descriptor in non-blocking * mode and to enable asynchronous notifications. */static intjthreadedFileDescriptor(int fd){	int r;#if (defined(FIOSSAIOSTAT) && !((defined(hpux) || defined (__hpux__)) && defined(FIOASYNC))) || \    (defined(FIOASYNC) && !defined(linux))	int on = 1;#endif#if (defined(FIOSSAIOOWN) && !((defined(hpux) || defined (__hpux__)) && defined(F_SETOWN))) || \    defined(F_SETOWN)	/* cache pid to accommodate antique C libraries */	static int pid = -1;		if (pid == -1)		pid = getpid();#endif	if (fd == -1)		return (fd);#if defined(F_SETFD)	/* set close-on-exec flag for this file descriptor */	if ((r = fcntl(fd, F_SETFD, 1)) < 0) {		perror("F_SETFD");		return (r);	}#endif	/* Make non-blocking */	if ((r = fcntl(fd, F_GETFL, 0)) < 0) {		perror("F_GETFL");		return (r);	}	/*	 * Apparently, this can fail, for instance when we stdout is 	 * redirected to /dev/null. (On FreeBSD)	 */	fcntl(fd, F_SETFL, r | O_NONBLOCK #if defined(O_ASYNC)		| O_ASYNC#elif defined(FASYNC)		| FASYNC#endif		);#if defined(FIOSSAIOSTAT) && !((defined(hpux) || defined (__hpux__)) && defined(FIOASYNC))	r = ioctl(fd, FIOSSAIOSTAT, &on);	if (r < 0 && errno != ENOTTY) {		/* Defines ENOTTY to be an acceptable error */		perror("FIOSSAIOSTAT"); 		return (r);	}#elif defined(FIOASYNC) && !defined(linux)	/* Don't do this on Linux because Linux version < 2.2.5 doesn't	 * know what FIOASYNC means.  It thinks FIOASYNC == O_SYNC. I kid you	 * not.  You can imagine what that means. ;-)	 * Never mind, FASYNC work as expected and is already set :)	 */	/* 	 * This ioctl fails for so many systems on so many occasions.	 * Reasons include ENXIO, ENOTTY, EINVAL(?)	 */	r = ioctl(fd, FIOASYNC, &on);	if (r < 0) {		DBG(JTHREAD, perror("FIOASYNC"); )        }#endif#if !(defined(O_ASYNC) || defined(FIOASYNC) ||  \      defined(FASYNC) || defined(FIOSSAIOSTAT))#error	Could not put socket in async mode#endif	/* Allow socket to signal this process when new data is available */#if defined(FIOSSAIOOWN) && !((defined(hpux) || defined (__hpux__)) && defined(F_SETOWN))	r = ioctl(fd, FIOSSAIOOWN, &pid);        if (r == -1 && errno != ENOTTY) {		perror("Error doing FIOSSAIOWN");	}	#elif defined(F_SETOWN)	/* On some systems, this will flag an error if fd is not a socket */	r = fcntl(fd, F_SETOWN, pid);	if (r < 0) {		DBG(JTHREAD, perror("F_SETOWN"); )	}#endif	return (fd);}/* * clear non-blocking flag for a file descriptor */voidjthreadRestoreFD(int fd){	/* clear nonblocking flag */	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);}/* * In SVR4 systems (notably AIX and HPUX 9.x), putting a file descriptor  * in non-blocking mode affects the actual terminal file.   * Thus, the shell we see the fd in * non-blocking mode when we exit and log the user off. * * Under Solaris, this happens if you use FIONBIO to get into non-blocking  * mode.  (as opposed to O_NONBLOCK) */static voidrestore_fds(void){	int i;	/* clear non-blocking flag for file descriptor stdin, stdout, stderr */	for (i = 0; i < 3; i++) {		jthreadRestoreFD(i);    	}}static voidrestore_fds_and_exit(){	restore_fds();	/* technically, we should restore the original handler and rethrow	 * the signal.	 */	EXIT(-1);		/* XXX */}/* * Threaded socket create. */intjthreadedSocket(int af, int type, int proto, int *out){	int r;	intsDisable();	r = socket(af, type, proto);	if (r == -1) {		r = errno;	} else {		*out = jthreadedFileDescriptor(r);		r = 0;	}	intsRestore();	return (r);}/* * Return thread-specific data for a given jthread. */threadData*jthread_get_data(jthread_t tid){	return (&tid->localData);}/* * Return thread status. */int jthread_get_status(jthread_t jt){	return (jt->status);}/* * Check if thread is interrupted. */int jthread_is_intrerrupted(jthread_t jt){	return (jt->flags & THREAD_FLAGS_INTERRUPTED);}int jthread_on_mutex(jthread_t jt){	return (jt->flags & THREAD_FLAGS_WAIT_MUTEX);}int jthread_on_condvar(jthread_t jt){	return (jt->flags & THREAD_FLAGS_WAIT_CONDVAR);}void jthread_clear_run(jthread_t jt){	jt->startUsed = 0;}int jthread_has_run(jthread_t jt){	return (jt->startUsed != 0);}/* * Threaded file open. */intjthreadedOpen(const char* path, int flags, int mode, int *out){	int r;	intsDisable();	/* Cygnus WinNT requires this */	r = open(path, flags|O_BINARY, mode);	if (r == -1) {		r = errno;	} else {		*out = jthreadedFileDescriptor(r);		r = 0;	}	intsRestore();	return (r);}/* * various building blocks for timeout system call functions */#define SET_DEADLINE(deadline, timeout) 		\	if (timeout != NOTIMEOUT) { 			\		jlong ct = currentTime();		\		deadline = timeout + ct;		\		if( deadline < ct ) {			\			deadline = 0;			\			timeout = NOTIMEOUT;		\		}					\	}#define BREAK_IF_LATE(deadline, timeout)		\	if (timeout != NOTIMEOUT) {			\		if (currentTime() >= deadline) {	\			errno = ETIMEDOUT;		\			break;				\		}					\	}#define IGNORE_EINTR(r)					\	if (r == -1 && errno == EINTR) {		\		continue;				\	}#define SET_RETURN(r)					\	if (r == -1) {					\		r = errno;				\	} #define SET_RETURN_OUT(r, out, ret)			\	if (r == -1) {					\		r = errno;				\	} else {					\		*out = ret;				\		r = 0;					\	}#define CALL_BLOCK_ON_FILE(A, B, C)				\	if (blockOnFile(A, B, C)) {				\		/* interrupted via jthread_interrupt() */ 	\		errno = EINTR; 					\		break;						\	}/* * Threaded socket connect. */intjthreadedConnect(int fd, struct sockaddr* addr, int len, int timeout){	int r;	jlong deadline = 0;	int inProgress = 0;	intsDisable();	SET_DEADLINE(deadline, timeout)	for (;;) {		r = connect(fd, addr, len);		if (r == 0 || !(errno == EINPROGRESS 				|| errno == EINTR || errno == EISCONN)) {			break;	/* success or real error */		}		if (r == -1 && errno == EISCONN) {			/* On Solaris 2.5, after getting EINPROGRESS			   from a non-blocking connect request, we			   won't ever get success.  When we're waken			   up, we'll either get EISCONN, which should			   be taken as success, or a real failure.			   However, we can't map EISCONN to success			   inconditionally, because attempting to			   connect the same socket again should raise			   an exception.			   Mapping EISCONN to success might lead to			   false positives if connect fails and			   another thread succeeds to connect this			   socket before this one is waken up.  Let's			   just hope it doesn't happen for now.  */			if (inProgress) {				r = 0;			}			break;		} else if (r == -1 && errno == EINPROGRESS) {			inProgress = 1;			if (!blockingFD[fd]) {				intsRestore();				return (EWOULDBLOCK);			}		}		IGNORE_EINTR(r)		CALL_BLOCK_ON_FILE(fd, TH_CONNECT, timeout)		BREAK_IF_LATE(deadline, timeout)	}	SET_RETURN(r)	intsRestore();	return (r);}/* * Threaded socket accept. */intjthreadedAccept(int fd, struct sockaddr* addr, int* len, 		int timeout, int* out){	/* absolute time at which time out is reached */	jlong deadline = 0;	int r;	intsDisable();	SET_DEADLINE(deadline, timeout)	for (;;) {		r = accept(fd, addr, len);		if (r >= 0 || !(errno == EWOULDBLOCK || errno == EINTR 				|| errno == EAGAIN)) {			break;	/* success or real error */		}		if (r == EWOULDBLOCK && !blockingFD[fd]) {			intsRestore();			return (EWOULDBLOCK);		}		IGNORE_EINTR(r)		CALL_BLOCK_ON_FILE(fd, TH_ACCEPT, timeout)		BREAK_IF_LATE(deadline, timeout)	}	SET_RETURN_OUT(r, out, jthreadedFileDescriptor(r))	intsRestore();	return (r);}/* * Threaded read with timeout */intjthreadedTimedRead(int fd, void* buf, size_t len, int timeout, ssize_t *out){	ssize_t r = -1;	/* absolute time at which timeout is reached */	jlong deadline = 0;	assert(timeout >= 0 || timeout == NOTIMEOUT);	intsDisable();	SET_DEADLINE(deadline, timeout)	for (;;) {		r = read(fd, buf, len);		if (r >= 0 || !(errno == EWOULDBLOCK || errno == EINTR 				|| errno == EAGAIN)) {			break;	/* real error or success */		}		IGNORE_EINTR(r)		CALL_BLOCK_ON_FILE(fd, TH_READ, timeout)		BREAK_IF_LATE(deadline, timeout)	}	SET_RETURN_OUT(r, out, r)	intsRestore();	return (r);}/* * Threaded write with timeout */intjthreadedTimedWrite(int fd, const void* buf, size_t len, int timeout, ssize_t *out){	ssize_t r = 1;	/* absolute time at which timeout is reached */	jlong deadline = 0;	const void *ptr = buf;	assert(timeout >= 0 || timeout == NOTIMEOUT);	intsDisable();	SET_DEADLINE(deadline, timeout)	while (len > 0 && r > 0) {		r = write(fd, ptr, len);		if (r >= 0) {			(char *) ptr += r;			len -= r;			r = (char *) ptr - (char *) buf;			continue;		}		if (!(errno == EWOULDBLOCK || errno == EINTR 				|| errno == EAGAIN)) {			break;	/* real error or success */		}		if (errno == EINTR) {			r = 1;			continue;		}		if (blockOnFile(fd, TH_WRITE, timeout)) {			/* interrupted by jthread_interrupt() */			errno = EINTR;			*out = (char *) ptr - (char *) buf;			break;		}		BREAK_IF_LATE(deadline, timeout)		r = 1;	}	SET_RETURN_OUT(r, out, r)	intsRestore();	return (r);}/* * Threaded read with no time out */intjthreadedRead(int fd, void* buf, size_t len, ssize_t *out){	return (jthreadedTimedRead(fd, buf, len, NOTIMEOUT, out));}/* * Threaded write */intjthreadedWrite(int fd, const void* buf, size_t len, ssize_t *out){	ssize_t r = 1;	const void* ptr;	ptr = buf;	intsDisable();	while (len > 0 && r > 0) {		r = (ssize_t)write(fd, ptr, len);		if (r >= 0) {			(char *) ptr += r;			len -= r;			r = (char *) ptr - (char *) buf;			

⌨️ 快捷键说明

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