Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 31 Jul 2002 08:47:11 -0700 (PDT)
From:      Jonathan Mini <mini@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 15313 for review
Message-ID:  <200207311547.g6VFlBv5087041@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://people.freebsd.org/~peter/p4db/chv.cgi?CH=15313

Change 15313 by mini@mini_stylus on 2002/07/31 08:46:11

	Convert uthreads from setjmp()/longjmp() to swapcontext() and friends.

Affected files ...

.. //depot/projects/kse/lib/libc_r/uthread/Makefile.inc#2 edit
.. //depot/projects/kse/lib/libc_r/uthread/pthread_private.h#2 edit
.. //depot/projects/kse/lib/libc_r/uthread/uthread_create.c#2 edit
.. //depot/projects/kse/lib/libc_r/uthread/uthread_init.c#2 edit
.. //depot/projects/kse/lib/libc_r/uthread/uthread_jmp.c#2 delete
.. //depot/projects/kse/lib/libc_r/uthread/uthread_kern.c#2 edit
.. //depot/projects/kse/lib/libc_r/uthread/uthread_sig.c#2 edit

Differences ...

==== //depot/projects/kse/lib/libc_r/uthread/Makefile.inc#2 (text+ko) ====

@@ -69,7 +69,6 @@
 	uthread_info.c \
 	uthread_init.c \
 	uthread_ioctl.c \
-	uthread_jmp.c \
 	uthread_join.c \
 	uthread_kern.c \
 	uthread_kevent.c \

==== //depot/projects/kse/lib/libc_r/uthread/pthread_private.h#2 (text+ko) ====

@@ -49,7 +49,6 @@
 /*
  * Include files.
  */
-#include <setjmp.h>
 #include <signal.h>
 #include <stdio.h>
 #include <sys/queue.h>
@@ -62,47 +61,15 @@
 #include <pthread_np.h>
 
 /*
- * Define machine dependent macros to get and set the stack pointer
- * from the supported contexts.  Also define a macro to set the return
- * address in a jmp_buf context.
- *
- * XXX - These need to be moved into architecture dependent support files.
+ * XXX - Grovelling around in the machine-dependant context only serves
+ * to get our hands dirty.
  */
 #if	defined(__i386__)
-#define	GET_STACK_JB(jb)	((unsigned long)((jb)[0]._jb[2]))
-#define	GET_STACK_SJB(sjb)	((unsigned long)((sjb)[0]._sjb[2]))
-#define	GET_STACK_UC(ucp)	((unsigned long)((ucp)->uc_mcontext.mc_esp))
-#define	SET_STACK_JB(jb, stk)	(jb)[0]._jb[2] = (int)(stk)
-#define	SET_STACK_SJB(sjb, stk)	(sjb)[0]._sjb[2] = (int)(stk)
-#define	SET_STACK_UC(ucp, stk)	(ucp)->uc_mcontext.mc_esp = (int)(stk)
-#define	FP_SAVE_UC(ucp)		do {			\
-	char	*fdata;					\
-	fdata = (char *) (ucp)->uc_mcontext.mc_fpregs;	\
-	__asm__("fnsave %0": :"m"(*fdata));		\
-} while (0)
-#define	FP_RESTORE_UC(ucp)	do {			\
-	char	*fdata;					\
-	fdata = (char *) (ucp)->uc_mcontext.mc_fpregs;	\
-	__asm__("frstor %0": :"m"(*fdata));		\
-} while (0)
-#define SET_RETURN_ADDR_JB(jb, ra)	(jb)[0]._jb[0] = (int)(ra)
+#define	UCP_STACK(ucp)	((unsigned long)((ucp)->uc_mcontext.mc_esp))
 #elif	defined(__alpha__)
-#include <machine/reg.h>
-#define	GET_STACK_JB(jb)	((unsigned long)((jb)[0]._jb[R_SP + 4]))
-#define	GET_STACK_SJB(sjb)	((unsigned long)((sjb)[0]._sjb[R_SP + 4]))
-#define	GET_STACK_UC(ucp)	((ucp)->uc_mcontext.mc_regs[R_SP])
-#define	SET_STACK_JB(jb, stk)	(jb)[0]._jb[R_SP + 4] = (long)(stk)
-#define	SET_STACK_SJB(sjb, stk)	(sjb)[0]._sjb[R_SP + 4] = (long)(stk)
-#define	SET_STACK_UC(ucp, stk)	(ucp)->uc_mcontext.mc_regs[R_SP] = (unsigned long)(stk)
-#define	FP_SAVE_UC(ucp)
-#define	FP_RESTORE_UC(ucp)
-#define SET_RETURN_ADDR_JB(jb, ra) do {			\
-	(jb)[0]._jb[2] = (long)(ra);			\
-	(jb)[0]._jb[R_RA + 4] = (long)(ra);		\
-	(jb)[0]._jb[R_T12 + 4] = (long)(ra);		\
-} while (0)
+#define	UCP_STACK(ucp)	((ucp)->uc_mcontext.mc_regs[R_SP])
 #else
-#error "Don't recognize this architecture!"
+#error	"Don't recognize this architecture!"
 #endif
 
 /*
@@ -595,22 +562,12 @@
  * up the thread to run a signal handler.
  */
 struct pthread_signal_frame {
-	/*
-	 * This stores the threads state before the signal.
-	 */
-	struct pthread_state_data saved_state;
-
-	/*
-	 * Threads return context; we use only jmp_buf's for now.
-	 */
-	union {
-		jmp_buf		jb;
-		ucontext_t	uc;
-	} ctx;
-	int			signo;	/* signal, arg 1 to sighandler */
-	int			sig_has_args;	/* use signal args if true */
-	ucontext_t		uc;
-	siginfo_t		siginfo;
+	struct pthread_state_data saved_state; /* State before the signal. */
+	ucontext_t	ctx;		/* Thread's return context. */
+	int		signo;		/* Signal, arg 1 to sighandler. */
+	int		sig_has_args;	/* Use signal args if true. */
+	ucontext_t	uc;		/* Pre-signal context. */
+	siginfo_t	siginfo;
 };
 
 struct pthread_specific_elem {
@@ -652,12 +609,9 @@
 	struct pthread_attr	attr;
 
 	/*
-	 * Threads return context; we use only jmp_buf's for now.
+	 * Machine context.
 	 */
-	union {
-		jmp_buf		jb;
-		ucontext_t	uc;
-	} ctx;
+	ucontext_t		ctx;
 
 	/*
 	 * Used for tracking delivery of signal handlers.
@@ -1096,9 +1050,9 @@
 /*
  * Declare the kernel scheduler jump buffer and stack:
  */
-SCLASS jmp_buf	_thread_kern_sched_jb;
+SCLASS ucontext_t	_thread_kern_sched_ctx;
 
-SCLASS void *	_thread_kern_sched_stack
+SCLASS void *		_thread_kern_sched_stack
 #ifdef GLOBAL_PTHREAD_PRIVATE
 = NULL
 #endif
@@ -1322,12 +1276,6 @@
 ssize_t	__sys_write(int, const void *, size_t);
 #endif
 
-/* #include <setjmp.h> */
-#ifdef _SETJMP_H_
-extern void	__siglongjmp(sigjmp_buf, int) __dead2;
-extern void	__longjmp(jmp_buf, int) __dead2;
-extern void	___longjmp(jmp_buf, int) __dead2;
-#endif
 __END_DECLS
 
 #endif  /* !_PTHREAD_PRIVATE_H */

==== //depot/projects/kse/lib/libc_r/uthread/uthread_create.c#2 (text+ko) ====

@@ -128,21 +128,13 @@
 			/* Initialize the signal frame: */
 			new_thread->curframe = NULL;
 
-			/* Initialise the jump buffer: */
-			_setjmp(new_thread->ctx.jb);
-
-			/*
-			 * Set up new stack frame so that it looks like it
-			 * returned from a longjmp() to the beginning of
-			 * _thread_start().
-			 */
-			SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start);
+			/* Initialise the machine context: */
+			getcontext(&new_thread->ctx);
+			new_thread->ctx.uc_stack.ss_sp = new_thread->stack;
+			new_thread->ctx.uc_stack.ss_size =
+			    pattr->stacksize_attr;
+			makecontext(&new_thread->ctx, _thread_start, 1);
 
-			/* The stack starts high and builds down: */
-			SET_STACK_JB(new_thread->ctx.jb,
-			    (long)new_thread->stack + pattr->stacksize_attr
-			    - sizeof(double));
-
 			/* Copy the thread attributes: */
 			memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
 
@@ -257,7 +249,7 @@
 {
 	struct pthread	*curthread = _get_curthread();
 
-	/* We just left the scheduler via longjmp: */
+	/* We just left the scheduler via swapcontext: */
 	_thread_kern_in_sched = 0;
 
 	/* Run the current thread's start routine with argument: */

==== //depot/projects/kse/lib/libc_r/uthread/uthread_init.c#2 (text+ko) ====

@@ -312,15 +312,16 @@
 		/* Set the main thread stack pointer. */
 		_thread_initial->stack = _usrstack - PTHREAD_STACK_INITIAL;
 
-		/* Set the stack attributes: */
+		/* Set the stack attributes. */
 		_thread_initial->attr.stackaddr_attr = _thread_initial->stack;
 		_thread_initial->attr.stacksize_attr = PTHREAD_STACK_INITIAL;
 
 		/* Setup the context for the scheduler: */
-		_setjmp(_thread_kern_sched_jb);
-		SET_STACK_JB(_thread_kern_sched_jb, _thread_kern_sched_stack +
-		    sched_stack_size - sizeof(double));
-		SET_RETURN_ADDR_JB(_thread_kern_sched_jb, _thread_kern_scheduler);
+		getcontext(&_thread_kern_sched_ctx);
+		_thread_kern_sched_ctx.uc_stack.ss_sp =
+		    _thread_kern_sched_stack;
+		_thread_kern_sched_ctx.uc_stack.ss_size = sched_stack_size;
+		makecontext(&_thread_kern_sched_ctx, _thread_kern_scheduler, 1);
 
 		/*
 		 * Write a magic value to the thread structure
@@ -332,6 +333,11 @@
 		_thread_initial->cancelflags = PTHREAD_CANCEL_ENABLE |
 		    PTHREAD_CANCEL_DEFERRED;
 
+		/* Setup the context for initial thread. */
+		getcontext(&_thread_initial->ctx);
+		_thread_kern_sched_ctx.uc_stack.ss_sp = _thread_initial->stack;
+		_thread_kern_sched_ctx.uc_stack.ss_size = PTHREAD_STACK_INITIAL;
+
 		/* Default the priority of the initial thread: */
 		_thread_initial->base_priority = PTHREAD_DEFAULT_PRIORITY;
 		_thread_initial->active_priority = PTHREAD_DEFAULT_PRIORITY;

==== //depot/projects/kse/lib/libc_r/uthread/uthread_kern.c#2 (text+ko) ====

@@ -38,7 +38,6 @@
 #include <stdarg.h>
 #include <string.h>
 #include <unistd.h>
-#include <setjmp.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/signalvar.h>
@@ -95,7 +94,7 @@
 	curthread->check_pending = 1;
 
 	/* Switch to the thread scheduler: */
-	___longjmp(_thread_kern_sched_jb, 1);
+	swapcontext(&curthread->ctx, &_thread_kern_sched_ctx);
 }
 
 
@@ -113,64 +112,56 @@
 
 	/* Check if this function was called from the signal handler: */
 	if (ucp != NULL) {
-		/* XXX - Save FP registers? */
-		FP_SAVE_UC(ucp);
 		called_from_handler = 1;
 		DBG_MSG("Entering scheduler due to signal\n");
 	}
 
-	/* Save the state of the current thread: */
-	if (_setjmp(curthread->ctx.jb) != 0) {
-		DBG_MSG("Returned from ___longjmp, thread %p\n",
-		    curthread);
-		/*
-		 * This point is reached when a longjmp() is called
-		 * to restore the state of a thread.
-		 *
-		 * This is the normal way out of the scheduler.
-		 */
-		_thread_kern_in_sched = 0;
+	/* Switch into the scheduler's context. */
+	swapcontext(&curthread->ctx, &_thread_kern_sched_ctx);
+	DBG_MSG("Returned from swapcontext, thread %p\n", curthread);
 
-		if (curthread->sig_defer_count == 0) {
-			if (((curthread->cancelflags &
-			    PTHREAD_AT_CANCEL_POINT) == 0) &&
-			    ((curthread->cancelflags &
-			    PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
-				/*
-				 * Cancellations override signals.
-				 *
-				 * Stick a cancellation point at the
-				 * start of each async-cancellable
-				 * thread's resumption.
-				 *
-				 * We allow threads woken at cancel
-				 * points to do their own checks.
-				 */
-				pthread_testcancel();
-		}
+	/*
+	 * This point is reached when swapcontext() is called
+	 * to restore the state of a thread.
+	 *
+	 * This is the normal way out of the scheduler.
+	 */
+	_thread_kern_in_sched = 0;
 
-		if (_sched_switch_hook != NULL) {
-			/* Run the installed switch hook: */
-			thread_run_switch_hook(_last_user_thread, curthread);
-		}
-		if (ucp == NULL)
-			return;
-		else {
-			/* XXX - Restore FP registers? */
-			FP_RESTORE_UC(ucp);
-
+	if (curthread->sig_defer_count == 0) {
+		if (((curthread->cancelflags &
+		    PTHREAD_AT_CANCEL_POINT) == 0) &&
+		    ((curthread->cancelflags &
+		    PTHREAD_CANCEL_ASYNCHRONOUS) != 0))
 			/*
-			 * Set the process signal mask in the context; it
-			 * could have changed by the handler.
+			 * Cancellations override signals.
+			 *
+			 * Stick a cancellation point at the
+			 * start of each async-cancellable
+			 * thread's resumption.
+			 *
+			 * We allow threads woken at cancel
+			 * points to do their own checks.
 			 */
-			ucp->uc_sigmask = _process_sigmask;
+			pthread_testcancel();
+	}
+
+	if (_sched_switch_hook != NULL) {
+		/* Run the installed switch hook: */
+		thread_run_switch_hook(_last_user_thread, curthread);
+	}
+	if (ucp == NULL)
+		return;
+	else {
+		/*
+		 * Set the process signal mask in the context; it
+		 * could have changed by the handler.
+		 */
+		ucp->uc_sigmask = _process_sigmask;
 
-			/* Resume the interrupted thread: */
-			__sys_sigreturn(ucp);
-		}
+		/* Resume the interrupted thread: */
+		__sys_sigreturn(ucp);
 	}
-	/* Switch to the thread scheduler: */
-	___longjmp(_thread_kern_sched_jb, 1);
 }
 
 void
@@ -193,30 +184,31 @@
 	unsigned int	current_tick;
 	int		add_to_prioq;
 
-	/* If the currently running thread is a user thread, save it: */
-	if ((curthread->flags & PTHREAD_FLAGS_PRIVATE) == 0)
-		_last_user_thread = curthread;
-
-	if (called_from_handler != 0) {
-		called_from_handler = 0;
-
-		/*
-		 * We were called from a signal handler; restore the process
-		 * signal mask.
-		 */
-		if (__sys_sigprocmask(SIG_SETMASK,
-		    &_process_sigmask, NULL) != 0)
-			PANIC("Unable to restore process mask after signal");
-	}
-
 	/*
 	 * Enter a scheduling loop that finds the next thread that is
 	 * ready to run. This loop completes when there are no more threads
-	 * in the global list or when a thread has its state restored by
-	 * either a sigreturn (if the state was saved as a sigcontext) or a
-	 * longjmp (if the state was saved by a setjmp).
+	 * in the global list. It is interrupted each time a thread is
+	 * scheduled, but will continue when we return.
 	 */
 	while (!(TAILQ_EMPTY(&_thread_list))) {
+
+		/* If the currently running thread is a user thread, save it: */
+		if ((curthread->flags & PTHREAD_FLAGS_PRIVATE) == 0)
+			_last_user_thread = curthread;
+
+		if (called_from_handler != 0) {
+			called_from_handler = 0;
+
+			/*
+			 * We were called from a signal handler; restore
+			 * the process signal mask.
+			 */
+			if (__sys_sigprocmask(SIG_SETMASK,
+				&_process_sigmask, NULL) != 0)
+				PANIC(
+				"Unable to restore process mask after signal");
+		}
+
 		/* Get the current time of day: */
 		GET_CURRENT_TOD(tv);
 		TIMEVAL_TO_TIMESPEC(&tv, &ts);
@@ -584,13 +576,7 @@
 			/*
 			 * Continue the thread at its current frame:
 			 */
-#if NOT_YET
-			_setcontext(&curthread->ctx.uc);
-#else
-			___longjmp(curthread->ctx.jb, 1);
-#endif
-			/* This point should not be reached. */
-			PANIC("Thread has returned from sigreturn or longjmp");
+			swapcontext(&_thread_kern_sched_ctx, &curthread->ctx);
 		}
 	}
 

==== //depot/projects/kse/lib/libc_r/uthread/uthread_sig.c#2 (text+ko) ====

@@ -37,7 +37,6 @@
 #include <signal.h>
 #include <fcntl.h>
 #include <unistd.h>
-#include <setjmp.h>
 #include <errno.h>
 #include <pthread.h>
 #include "pthread_private.h"
@@ -1008,7 +1007,7 @@
 
 	/*
 	 * Lower the priority before calling the handler in case
-	 * it never returns (longjmps back):
+	 * it never returns (e.g., it switchcontext()s):
 	 */
 	thread->active_priority &= ~PTHREAD_SIGNAL_PRIORITY;
 
@@ -1038,9 +1037,11 @@
 {
 	struct pthread_signal_frame *psf = NULL;
 	unsigned long	stackp;
+	size_t		stacksize;
+	char		*stackbase;
 
  	/* Get the top of the threads stack: */
-	stackp = GET_STACK_JB(thread->ctx.jb);
+	stackp = UCP_STACK(&thread->ctx);
 
 	/*
 	 * Leave a little space on the stack and round down to the
@@ -1080,9 +1081,13 @@
 	 * Set up the context:
 	 */
 	stackp -= sizeof(double);
-	_setjmp(thread->ctx.jb);
-	SET_STACK_JB(thread->ctx.jb, stackp);
-	SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper);
+	stackbase = thread->ctx.uc_stack.ss_sp;
+	stacksize = thread->ctx.uc_stack.ss_size;
+	getcontext(&thread->ctx);
+	thread->ctx.uc_stack.ss_sp = stackbase;
+	thread->ctx.uc_stack.ss_size = stacksize;
+	makecontext(&thread->ctx, _thread_sig_wrapper, 1);
+	UCP_STACK(&thread->ctx) = stackp;
 }
 
 void

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe p4-projects" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200207311547.g6VFlBv5087041>