Date: Mon, 21 Oct 2002 00:15:14 +0700 From: Max Khon <fjoe@iclub.nsu.ru> To: freebsd-stable@freebsd.org, freebsd-java@freebsd.org Subject: libc_r MFC Message-ID: <20021021001514.A38080@iclub.nsu.ru>
next in thread | raw e-mail | index | archive | help
--UlVJffcvxoiEqYs2 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline hi, there! Please test attached patch. It contains MFC of signal handling, thread suspension and a couple of bug fixes. I have succesfully run Java2D demo and JBuilder 7 with hotspot (compiler2) built from ports/java/jdk13 with these patches. /fjoe --UlVJffcvxoiEqYs2 Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=current-diffs Index: include/pthread_np.h =================================================================== RCS file: /home/ncvs/src/include/pthread_np.h,v retrieving revision 1.7.2.2 diff -u -p -r1.7.2.2 pthread_np.h --- include/pthread_np.h 15 Oct 2002 16:52:04 -0000 1.7.2.2 +++ include/pthread_np.h 20 Oct 2002 15:50:46 -0000 @@ -46,8 +46,10 @@ __BEGIN_DECLS int pthread_attr_setcreatesuspend_np __P((pthread_attr_t *)); int pthread_main_np __P((void)); int pthread_multi_np __P((void)); +void pthread_resume_all_np __P((void)); int pthread_resume_np __P((pthread_t)); int pthread_single_np __P((void)); +void pthread_suspend_all_np __P((void)); int pthread_suspend_np __P((pthread_t)); int pthread_mutexattr_getkind_np __P((pthread_mutexattr_t)); int pthread_mutexattr_setkind_np __P((pthread_mutexattr_t *, int)); Index: lib/libc_r/uthread/pthread_private.h =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/pthread_private.h,v retrieving revision 1.36.2.20 diff -u -p -r1.36.2.20 pthread_private.h --- lib/libc_r/uthread/pthread_private.h 17 Oct 2002 19:37:33 -0000 1.36.2.20 +++ lib/libc_r/uthread/pthread_private.h 20 Oct 2002 14:44:06 -0000 @@ -188,14 +188,15 @@ if ((thrd)->state != newstate) { \ if ((thrd)->state == PS_RUNNING) { \ PTHREAD_PRIOQ_REMOVE(thrd); \ + PTHREAD_SET_STATE(thrd, newstate); \ PTHREAD_WAITQ_INSERT(thrd); \ } else if (newstate == PS_RUNNING) { \ PTHREAD_WAITQ_REMOVE(thrd); \ + PTHREAD_SET_STATE(thrd, newstate); \ PTHREAD_PRIOQ_INSERT_TAIL(thrd); \ } \ } \ _thread_kern_new_state = 0; \ - PTHREAD_SET_STATE(thrd, newstate); \ } while (0) #else #define PTHREAD_ASSERT(cond, msg) @@ -395,18 +396,6 @@ struct pthread_attr { #define PTHREAD_CREATE_SUSPENDED 1 /* - * Additional state for a thread suspended with pthread_suspend_np(). - */ -enum pthread_susp { - SUSP_NO, /* Not suspended. */ - SUSP_YES, /* Suspended. */ - SUSP_JOIN, /* Suspended, joining. */ - SUSP_NOWAIT, /* Suspended, was in a mutex or condition queue. */ - SUSP_MUTEX_WAIT,/* Suspended, still in a mutex queue. */ - SUSP_COND_WAIT /* Suspended, still in a condition queue. */ -}; - -/* * Miscellaneous definitions. */ #define PTHREAD_STACK_DEFAULT 65536 @@ -604,33 +593,8 @@ struct join_status { }; /* - * Normally thread contexts are stored as jmp_bufs via _setjmp()/_longjmp(), - * but they may also be sigjmp_buf and ucontext_t. When a thread is - * interrupted by a signal, it's context is saved as a ucontext_t. An - * application is also free to use [_]longjmp()/[_]siglongjmp() to jump - * between contexts within the same thread. Future support will also - * include setcontext()/getcontext(). - * - * Define an enumerated type that can identify the 4 different context - * types. - */ -typedef enum { - CTX_JB_NOSIG, /* context is jmp_buf without saved sigset */ - CTX_JB, /* context is jmp_buf (with saved sigset) */ - CTX_SJB, /* context is sigjmp_buf (with saved sigset) */ - CTX_UC /* context is ucontext_t (with saved sigset) */ -} thread_context_t; - -/* - * There are 2 basic contexts that a frame may contain at any - * one time: - * - * o ctx - The context that the thread should return to after normal - * completion of the signal handler. - * o sig_jb - The context just before the signal handler is invoked. - * Attempts at abnormal returns from user supplied signal handlers - * will return back to the signal context to perform any necessary - * cleanup. + * The frame that is added to the top of a threads stack when setting up + * up the thread to run a signal handler. */ struct pthread_signal_frame { /* @@ -639,19 +603,12 @@ struct pthread_signal_frame { struct pthread_state_data saved_state; /* - * Threads return context; ctxtype identifies the type of context. - * For signal frame 0, these point to the context storage area - * within the pthread structure. When handling signals (frame > 0), - * these point to a context storage area that is allocated off the - * threads stack. + * Threads return context; we use only jmp_buf's for now. */ union { jmp_buf jb; - sigjmp_buf sigjb; ucontext_t uc; } ctx; - thread_context_t ctxtype; - int longjmp_val; int signo; /* signal, arg 1 to sighandler */ int sig_has_args; /* use signal args if true */ ucontext_t uc; @@ -692,15 +649,12 @@ struct pthread { struct pthread_attr attr; /* - * Threads return context; ctxtype identifies the type of context. + * Threads return context; we use only jmp_buf's for now. */ union { jmp_buf jb; - sigjmp_buf sigjb; ucontext_t uc; } ctx; - thread_context_t ctxtype; - int longjmp_val; /* * Used for tracking delivery of signal handlers. @@ -716,8 +670,6 @@ struct pthread { #define PTHREAD_CANCEL_NEEDED 0x0010 int cancelflags; - enum pthread_susp suspended; - thread_continuation_t continuation; /* @@ -759,7 +711,7 @@ struct pthread { int error; /* - * THe joiner is the thread that is joining to this thread. The + * The joiner is the thread that is joining to this thread. The * join status keeps track of a join operation to another thread. */ struct pthread *joiner; @@ -834,7 +786,8 @@ struct pthread { #define PTHREAD_FLAGS_IN_FDQ 0x0040 /* in fd lock queue using qe link */ #define PTHREAD_FLAGS_IN_CONDQ 0x0080 /* in condition queue using sqe link*/ #define PTHREAD_FLAGS_IN_MUTEXQ 0x0100 /* in mutex queue using sqe link */ -#define PTHREAD_FLAGS_TRACE 0x0200 /* for debugging purposes */ +#define PTHREAD_FLAGS_SUSPENDED 0x0200 /* thread is suspended */ +#define PTHREAD_FLAGS_TRACE 0x0400 /* for debugging purposes */ #define PTHREAD_FLAGS_IN_SYNCQ \ (PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ) @@ -917,17 +870,6 @@ SCLASS struct pthread * volatile _last ; #endif -/* - * Ptr to the thread running in single-threaded mode or NULL if - * running multi-threaded (default POSIX behaviour). - */ -SCLASS struct pthread * volatile _thread_single -#ifdef GLOBAL_PTHREAD_PRIVATE -= NULL; -#else -; -#endif - /* List of all threads: */ SCLASS TAILQ_HEAD(, pthread) _thread_list #ifdef GLOBAL_PTHREAD_PRIVATE @@ -1145,9 +1087,6 @@ SCLASS volatile int _sigq_check_reqd #endif ; -/* The signal stack. */ -SCLASS struct sigaltstack _thread_sigstack; - /* Thread switch hook. */ SCLASS pthread_switch_routine_t _sched_switch_hook #ifdef GLOBAL_PTHREAD_PRIVATE @@ -1284,9 +1223,15 @@ void _thread_enter_cancellation_point(vo void _thread_leave_cancellation_point(void); void _thread_cancellation_point(void); +/* #include <aio.h> */ +#ifdef _SYS_AIO_H_ +int __sys_aio_suspend(const struct aiocb * const[], int, const struct timespec *); +#endif + /* #include <sys/event.h> */ #ifdef _SYS_EVENT_H_ -int __sys_kevent(int, const struct kevent *, int, struct kevent *, int, const struct timespec *); +int __sys_kevent(int, const struct kevent *, int, struct kevent *, + int, const struct timespec *); #endif /* #include <sys/ioctl.h> */ @@ -1340,11 +1285,6 @@ ssize_t __sys_writev(int, const struct i /* #include <sys/wait.h> */ #ifdef WNOHANG pid_t __sys_wait4(pid_t, int *, int, struct rusage *); -#endif - -/* #include <aio.h> */ -#ifdef _SYS_AIO_H_ -int __sys_aio_suspend(const struct aiocb * const[], int, const struct timespec *); #endif /* #include <dirent.h> */ Index: lib/libc_r/uthread/uthread_cancel.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_cancel.c,v retrieving revision 1.3.2.8 diff -u -p -r1.3.2.8 uthread_cancel.c --- lib/libc_r/uthread/uthread_cancel.c 17 Oct 2002 19:37:33 -0000 1.3.2.8 +++ lib/libc_r/uthread/uthread_cancel.c 20 Oct 2002 14:43:55 -0000 @@ -61,8 +61,7 @@ pthread_cancel(pthread_t pthread) case PS_JOIN: /* - * Disconnect the thread from the joinee and - * detach: + * Disconnect the thread from the joinee: */ if (pthread->join_status.thread != NULL) { pthread->join_status.thread->joiner @@ -74,20 +73,6 @@ pthread_cancel(pthread_t pthread) break; case PS_SUSPENDED: - if (pthread->suspended == SUSP_NO || - pthread->suspended == SUSP_YES || - pthread->suspended == SUSP_JOIN || - pthread->suspended == SUSP_NOWAIT) { - /* - * This thread isn't in any scheduling - * queues; just change it's state: - */ - pthread->cancelflags |= - PTHREAD_CANCELLING; - PTHREAD_SET_STATE(pthread, PS_RUNNING); - break; - } - /* FALLTHROUGH */ case PS_MUTEX_WAIT: case PS_COND_WAIT: case PS_FDLR_WAIT: @@ -105,7 +90,7 @@ pthread_cancel(pthread_t pthread) */ pthread->interrupted = 1; pthread->cancelflags |= PTHREAD_CANCEL_NEEDED; - PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_NEW_STATE(pthread, PS_RUNNING); pthread->continuation = finish_cancellation; break; Index: lib/libc_r/uthread/uthread_cond.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_cond.c,v retrieving revision 1.22.2.7 diff -u -p -r1.22.2.7 uthread_cond.c --- lib/libc_r/uthread/uthread_cond.c 17 Oct 2002 19:37:33 -0000 1.22.2.7 +++ lib/libc_r/uthread/uthread_cond.c 20 Oct 2002 14:43:55 -0000 @@ -516,15 +516,9 @@ pthread_cond_signal(pthread_cond_t * con if ((pthread = cond_queue_deq(*cond)) != NULL) { /* - * Unless the thread is currently suspended, - * allow it to run. If the thread is suspended, - * make a note that the thread isn't in a wait - * queue any more. + * Wake up the signaled thread: */ - if (pthread->state != PS_SUSPENDED) - PTHREAD_NEW_STATE(pthread,PS_RUNNING); - else - pthread->suspended = SUSP_NOWAIT; + PTHREAD_NEW_STATE(pthread, PS_RUNNING); } /* Check for no more waiters: */ @@ -588,15 +582,9 @@ pthread_cond_broadcast(pthread_cond_t * */ while ((pthread = cond_queue_deq(*cond)) != NULL) { /* - * Unless the thread is currently suspended, - * allow it to run. If the thread is suspended, - * make a note that the thread isn't in a wait - * queue any more. + * Wake up the signaled thread: */ - if (pthread->state != PS_SUSPENDED) - PTHREAD_NEW_STATE(pthread,PS_RUNNING); - else - pthread->suspended = SUSP_NOWAIT; + PTHREAD_NEW_STATE(pthread, PS_RUNNING); } /* There are no more waiting threads: */ Index: lib/libc_r/uthread/uthread_create.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_create.c,v retrieving revision 1.24.2.4 diff -u -p -r1.24.2.4 uthread_create.c --- lib/libc_r/uthread/uthread_create.c 17 Oct 2002 19:37:35 -0000 1.24.2.4 +++ lib/libc_r/uthread/uthread_create.c 20 Oct 2002 14:44:06 -0000 @@ -53,16 +53,11 @@ int _thread_next_offset = OFF(tle.tqe_ int _thread_uniqueid_offset = OFF(uniqueid); int _thread_state_offset = OFF(state); int _thread_name_offset = OFF(name); -int _thread_ctxtype_offset = OFF(ctxtype); int _thread_ctx_offset = OFF(ctx); #undef OFF int _thread_PS_RUNNING_value = PS_RUNNING; int _thread_PS_DEAD_value = PS_DEAD; -int _thread_CTX_JB_NOSIG_value = CTX_JB_NOSIG; -int _thread_CTX_JB_value = CTX_JB; -int _thread_CTX_SJB_value = CTX_SJB; -int _thread_CTX_UC_value = CTX_UC; int pthread_create(pthread_t * thread, const pthread_attr_t * attr, @@ -202,9 +197,6 @@ pthread_create(pthread_t * thread, const (long)new_thread->stack + pattr->stacksize_attr - sizeof(double)); - /* Initialize the rest of the frame: */ - new_thread->ctxtype = CTX_JB_NOSIG; - /* Copy the thread attributes: */ memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); @@ -269,9 +261,10 @@ pthread_create(pthread_t * thread, const /* Add the thread to the linked list of all threads: */ TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle); - if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) + if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) { + new_thread->flags |= PTHREAD_FLAGS_SUSPENDED; new_thread->state = PS_SUSPENDED; - else { + } else { new_thread->state = PS_RUNNING; PTHREAD_PRIOQ_INSERT_TAIL(new_thread); } Index: lib/libc_r/uthread/uthread_exit.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_exit.c,v retrieving revision 1.16.2.7 diff -u -p -r1.16.2.7 uthread_exit.c --- lib/libc_r/uthread/uthread_exit.c 17 Oct 2002 19:37:35 -0000 1.16.2.7 +++ lib/libc_r/uthread/uthread_exit.c 20 Oct 2002 14:43:55 -0000 @@ -210,22 +210,8 @@ pthread_exit(void *status) pthread = curthread->joiner; curthread->joiner = NULL; - switch (pthread->suspended) { - case SUSP_JOIN: - /* - * The joining thread is suspended. Change the - * suspension state to make the thread runnable when it - * is resumed: - */ - pthread->suspended = SUSP_NO; - break; - case SUSP_NO: - /* Make the joining thread runnable: */ - PTHREAD_NEW_STATE(pthread, PS_RUNNING); - break; - default: - PANIC("Unreachable code reached"); - } + /* Make the joining thread runnable: */ + PTHREAD_NEW_STATE(pthread, PS_RUNNING); /* Set the return value for the joining thread: */ pthread->join_status.ret = curthread->ret; Index: lib/libc_r/uthread/uthread_gc.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_gc.c,v retrieving revision 1.11.2.4 diff -u -p -r1.11.2.4 uthread_gc.c --- lib/libc_r/uthread/uthread_gc.c 17 Oct 2002 19:44:38 -0000 1.11.2.4 +++ lib/libc_r/uthread/uthread_gc.c 20 Oct 2002 14:43:55 -0000 @@ -123,13 +123,13 @@ _thread_gc(pthread_addr_t arg) * Check if this thread has detached: */ else if ((pthread->attr.flags & - PTHREAD_DETACHED) != 0) { + PTHREAD_DETACHED) != 0) { /* Remove this thread from the dead list: */ TAILQ_REMOVE(&_dead_list, pthread, dle); /* * Check if the stack was not specified by - * the caller to pthread_create and has not + * the caller to pthread_create() and has not * been destroyed yet: */ if (pthread->attr.stackaddr_attr == NULL && @@ -170,7 +170,7 @@ _thread_gc(pthread_addr_t arg) * not destroy it. * * Check if the stack was not specified by - * the caller to pthread_create and has not + * the caller to pthread_create() and has not * been destroyed yet: */ if (pthread->attr.stackaddr_attr == NULL && Index: lib/libc_r/uthread/uthread_init.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_init.c,v retrieving revision 1.23.2.9 diff -u -p -r1.23.2.9 uthread_init.c --- lib/libc_r/uthread/uthread_init.c 17 Oct 2002 19:37:36 -0000 1.23.2.9 +++ lib/libc_r/uthread/uthread_init.c 20 Oct 2002 15:12:33 -0000 @@ -147,20 +147,21 @@ _thread_init(void) PANIC("Can't open console"); if (setlogin("root") == -1) PANIC("Can't set login to root"); - if (__sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1) + if (__sys_ioctl(fd, TIOCSCTTY, (char *) NULL) == -1) PANIC("Can't set controlling terminal"); - if (__sys_dup2(fd,0) == -1 || - __sys_dup2(fd,1) == -1 || - __sys_dup2(fd,2) == -1) + if (__sys_dup2(fd, 0) == -1 || + __sys_dup2(fd, 1) == -1 || + __sys_dup2(fd, 2) == -1) PANIC("Can't dup2"); } /* Get the standard I/O flags before messing with them : */ - for (i = 0; i < 3; i++) + for (i = 0; i < 3; i++) { if (((_pthread_stdio_flags[i] = - __sys_fcntl(i,F_GETFL, NULL)) == -1) && + __sys_fcntl(i, F_GETFL, NULL)) == -1) && (errno != EBADF)) PANIC("Cannot get stdio flags"); + } /* * Create a pipe that is written to by the signal handler to prevent @@ -170,8 +171,21 @@ _thread_init(void) /* Cannot create pipe, so abort: */ PANIC("Cannot create kernel pipe"); } + + /* + * Make sure the pipe does not get in the way of stdio: + */ + for (i = 0; i < 2; i++) { + if (_thread_kern_pipe[i] < 3) { + fd = __sys_fcntl(_thread_kern_pipe[i], F_DUPFD, 3); + if (fd == -1) + PANIC("Cannot create kernel pipe"); + __sys_close(_thread_kern_pipe[i]); + _thread_kern_pipe[i] = fd; + } + } /* Get the flags for the read pipe: */ - else if ((flags = __sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) { + if ((flags = __sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) { /* Abort this application: */ PANIC("Cannot get kernel read pipe flags"); } @@ -231,7 +245,7 @@ _thread_init(void) mib[1] = KERN_USRSTACK; len = sizeof (int); if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1) - _usrstack = USRSTACK; + _usrstack = (void *)USRSTACK; /* * Create a red zone below the main stack. All other stacks are * constrained to a maximum size by the paramters passed to @@ -291,7 +305,6 @@ _thread_init(void) /* Initialize the initial context: */ _thread_initial->curframe = NULL; - _thread_initial->ctxtype = CTX_JB_NOSIG; /* Initialise the rest of the fields: */ _thread_initial->poll_data.nfds = 0; @@ -316,17 +329,6 @@ _thread_init(void) /* Clear the signal queue: */ memset(_thread_sigq, 0, sizeof(_thread_sigq)); - - /* - * Create and install an alternate signal stack of - * the recommended size: - */ - _thread_sigstack.ss_sp = malloc(SIGSTKSZ); - _thread_sigstack.ss_size = SIGSTKSZ; - _thread_sigstack.ss_flags = 0; - if ((_thread_sigstack.ss_sp == NULL) || - (__sys_sigaltstack(&_thread_sigstack, NULL) != 0)) - PANIC("Unable to install alternate signal stack"); /* Enter a loop to get the existing signal status: */ for (i = 1; i < NSIG; i++) { Index: lib/libc_r/uthread/uthread_kern.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_kern.c,v retrieving revision 1.28.2.12 diff -u -p -r1.28.2.12 uthread_kern.c --- lib/libc_r/uthread/uthread_kern.c 17 Oct 2002 20:09:23 -0000 1.28.2.12 +++ lib/libc_r/uthread/uthread_kern.c 20 Oct 2002 16:04:03 -0000 @@ -101,7 +101,7 @@ _thread_kern_sched_frame(struct pthread_ void -_thread_kern_sched(ucontext_t *scp) +_thread_kern_sched(ucontext_t *ucp) { struct pthread *curthread = _get_curthread(); @@ -113,50 +113,61 @@ _thread_kern_sched(ucontext_t *scp) _thread_kern_in_sched = 1; /* Check if this function was called from the signal handler: */ - if (scp != NULL) { + if (ucp != NULL) { + /* XXX - Save FP registers? */ + FP_SAVE_UC(ucp); called_from_handler = 1; DBG_MSG("Entering scheduler due to signal\n"); - } else { - /* Save the state of the current thread: */ - if (_setjmp(curthread->ctx.jb) == 0) { - /* Flag the jump buffer was the last state saved: */ - curthread->ctxtype = CTX_JB_NOSIG; - curthread->longjmp_val = 1; - } else { - 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; + } - 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(); - } + /* 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; - if (_sched_switch_hook != NULL) { - /* Run the installed switch hook: */ - thread_run_switch_hook(_last_user_thread, - 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(); + } + + 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); + + /* + * Set the process signal mask in the context; it + * could have changed by the handler. + */ + ucp->uc_sigmask = _process_sigmask; + + /* Resume the interrupted thread: */ + sigreturn(ucp); } } /* Switch to the thread scheduler: */ @@ -191,20 +202,12 @@ _thread_kern_scheduler(void) called_from_handler = 0; /* - * The signal handler should have saved the state of - * the current thread. Restore the process signal - * mask. + * 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"); - - /* - * Since the signal handler didn't return normally, we - * have to tell the kernel to reuse the signal stack. - */ - if (__sys_sigaltstack(&_thread_sigstack, NULL) != 0) - PANIC("Unable to restore alternate signal stack"); } /* @@ -582,42 +585,11 @@ _thread_kern_scheduler(void) /* * Continue the thread at its current frame: */ - switch(curthread->ctxtype) { - case CTX_JB_NOSIG: - ___longjmp(curthread->ctx.jb, - curthread->longjmp_val); - break; - case CTX_JB: - __longjmp(curthread->ctx.jb, - curthread->longjmp_val); - break; - case CTX_SJB: - __siglongjmp(curthread->ctx.sigjb, - curthread->longjmp_val); - break; - case CTX_UC: - /* XXX - Restore FP regsisters? */ - FP_RESTORE_UC(&curthread->ctx.uc); - - /* - * Do a sigreturn to restart the thread that - * was interrupted by a signal: - */ - _thread_kern_in_sched = 0; - #if NOT_YET - _setcontext(&curthread->ctx.uc); + _setcontext(&curthread->ctx.uc); #else - /* - * Ensure the process signal mask is set - * correctly: - */ - curthread->ctx.uc.uc_sigmask = - _process_sigmask; - sigreturn(&curthread->ctx.uc); + ___longjmp(curthread->ctx.jb, 1); #endif - break; - } /* This point should not be reached. */ PANIC("Thread has returned from sigreturn or longjmp"); } Index: lib/libc_r/uthread/uthread_multi_np.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_multi_np.c,v retrieving revision 1.4 diff -u -p -r1.4 uthread_multi_np.c --- lib/libc_r/uthread/uthread_multi_np.c 12 Jan 2000 09:28:46 -0000 1.4 +++ lib/libc_r/uthread/uthread_multi_np.c 20 Oct 2002 14:43:55 -0000 @@ -34,13 +34,18 @@ #include <string.h> #ifdef _THREAD_SAFE #include <pthread.h> -#include "pthread_private.h" +#include <pthread_np.h> int pthread_multi_np() { + /* Return to multi-threaded scheduling mode: */ - _thread_single = NULL; - return(0); + /* + * XXX - Do we want to do this? + * __is_threaded = 1; + */ + pthread_resume_all_np(); + return (0); } #endif Index: lib/libc_r/uthread/uthread_mutex.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_mutex.c,v retrieving revision 1.20.2.7 diff -u -p -r1.20.2.7 uthread_mutex.c --- lib/libc_r/uthread/uthread_mutex.c 17 Oct 2002 19:37:37 -0000 1.20.2.7 +++ lib/libc_r/uthread/uthread_mutex.c 20 Oct 2002 16:25:48 -0000 @@ -793,21 +793,9 @@ mutex_unlock_common(pthread_mutex_t * mu */ if (((*mutex)->m_owner = mutex_queue_deq(*mutex)) != NULL) { - /* - * Unless the new owner of the mutex is - * currently suspended, allow the owner - * to run. If the thread is suspended, - * make a note that the thread isn't in - * a wait queue any more. - */ - if (((*mutex)->m_owner->state != - PS_SUSPENDED)) { - PTHREAD_NEW_STATE((*mutex)->m_owner, - PS_RUNNING); - } else { - (*mutex)->m_owner->suspended = - SUSP_NOWAIT; - } + /* Make the new owner runnable: */ + PTHREAD_NEW_STATE((*mutex)->m_owner, + PS_RUNNING); /* * Add the mutex to the threads list of @@ -925,20 +913,10 @@ mutex_unlock_common(pthread_mutex_t * mu (*mutex)->m_prio; /* - * Unless the new owner of the mutex is - * currently suspended, allow the owner - * to run. If the thread is suspended, - * make a note that the thread isn't in - * a wait queue any more. - */ - if (((*mutex)->m_owner->state != - PS_SUSPENDED)) { - PTHREAD_NEW_STATE((*mutex)->m_owner, - PS_RUNNING); - } else { - (*mutex)->m_owner->suspended = - SUSP_NOWAIT; - } + * Make the new owner runnable: + */ + PTHREAD_NEW_STATE((*mutex)->m_owner, + PS_RUNNING); } } break; @@ -1054,20 +1032,10 @@ mutex_unlock_common(pthread_mutex_t * mu (*mutex)->m_prio; /* - * Unless the new owner of the mutex is - * currently suspended, allow the owner - * to run. If the thread is suspended, - * make a note that the thread isn't in - * a wait queue any more. - */ - if (((*mutex)->m_owner->state != - PS_SUSPENDED)) { - PTHREAD_NEW_STATE((*mutex)->m_owner, - PS_RUNNING); - } else { - (*mutex)->m_owner->suspended = - SUSP_NOWAIT; - } + * Make the new owner runnable: + */ + PTHREAD_NEW_STATE((*mutex)->m_owner, + PS_RUNNING); } } break; Index: lib/libc_r/uthread/uthread_priority_queue.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_priority_queue.c,v retrieving revision 1.5.2.2 diff -u -p -r1.5.2.2 uthread_priority_queue.c --- lib/libc_r/uthread/uthread_priority_queue.c 17 Oct 2002 19:37:38 -0000 1.5.2.2 +++ lib/libc_r/uthread/uthread_priority_queue.c 20 Oct 2002 14:43:55 -0000 @@ -165,52 +165,74 @@ _pq_remove(pq_queue_t *pq, pthread_t pth void _pq_insert_head(pq_queue_t *pq, pthread_t pthread) { - int prio = pthread->active_priority; + int prio; /* - * Make some assertions when debugging is enabled: + * Don't insert suspended threads into the priority queue. + * The caller is responsible for setting the threads state. */ - _PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active"); - _PQ_SET_ACTIVE(); - _PQ_ASSERT_NOT_QUEUED(pthread, - "_pq_insert_head: Already in priority queue"); - _PQ_ASSERT_PROTECTED("_pq_insert_head: prioq not protected!"); - - TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe); - if (pq->pq_lists[prio].pl_queued == 0) - /* Insert the list into the priority queue: */ - pq_insert_prio_list(pq, prio); + if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) { + /* Make sure the threads state is suspended. */ + if (pthread->state != PS_SUSPENDED) + PTHREAD_SET_STATE(pthread, PS_SUSPENDED); + } else { + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active"); + _PQ_SET_ACTIVE(); + _PQ_ASSERT_NOT_QUEUED(pthread, + "_pq_insert_head: Already in priority queue"); + _PQ_ASSERT_PROTECTED("_pq_insert_head: prioq not protected!"); + + prio = pthread->active_priority; + TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe); + if (pq->pq_lists[prio].pl_queued == 0) + /* Insert the list into the priority queue: */ + pq_insert_prio_list(pq, prio); - /* Mark this thread as being in the priority queue. */ - pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; + /* Mark this thread as being in the priority queue. */ + pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; - _PQ_CLEAR_ACTIVE(); + _PQ_CLEAR_ACTIVE(); + } } void _pq_insert_tail(pq_queue_t *pq, pthread_t pthread) { - int prio = pthread->active_priority; + int prio; /* - * Make some assertions when debugging is enabled: + * Don't insert suspended threads into the priority queue. + * The caller is responsible for setting the threads state. */ - _PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active"); - _PQ_SET_ACTIVE(); - _PQ_ASSERT_NOT_QUEUED(pthread, - "_pq_insert_tail: Already in priority queue"); - _PQ_ASSERT_PROTECTED("_pq_insert_tail: prioq not protected!"); - - TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe); - if (pq->pq_lists[prio].pl_queued == 0) - /* Insert the list into the priority queue: */ - pq_insert_prio_list(pq, prio); + if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) { + /* Make sure the threads state is suspended. */ + if (pthread->state != PS_SUSPENDED) + PTHREAD_SET_STATE(pthread, PS_SUSPENDED); + } else { + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active"); + _PQ_SET_ACTIVE(); + _PQ_ASSERT_NOT_QUEUED(pthread, + "_pq_insert_tail: Already in priority queue"); + _PQ_ASSERT_PROTECTED("_pq_insert_tail: prioq not protected!"); + + prio = pthread->active_priority; + TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe); + if (pq->pq_lists[prio].pl_queued == 0) + /* Insert the list into the priority queue: */ + pq_insert_prio_list(pq, prio); - /* Mark this thread as being in the priority queue. */ - pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; + /* Mark this thread as being in the priority queue. */ + pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; - _PQ_CLEAR_ACTIVE(); + _PQ_CLEAR_ACTIVE(); + } } @@ -238,6 +260,17 @@ _pq_first(pq_queue_t *pq) /* Mark the list as not being in the queue: */ pql->pl_queued = 0; + } else if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) { + /* + * This thread is suspended; remove it from the + * list and ensure its state is suspended. + */ + TAILQ_REMOVE(&pql->pl_head, pthread, pqe); + PTHREAD_SET_STATE(pthread, PS_SUSPENDED); + + /* This thread is now longer in the priority queue. */ + pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ; + pthread = NULL; } } Index: lib/libc_r/uthread/uthread_resume_np.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_resume_np.c,v retrieving revision 1.7.2.3 diff -u -p -r1.7.2.3 uthread_resume_np.c --- lib/libc_r/uthread/uthread_resume_np.c 23 Jun 2001 00:47:05 -0000 1.7.2.3 +++ lib/libc_r/uthread/uthread_resume_np.c 20 Oct 2002 14:43:55 -0000 @@ -36,61 +36,75 @@ #include <pthread.h> #include "pthread_private.h" +static void resume_common(struct pthread *); + /* Resume a thread: */ int pthread_resume_np(pthread_t thread) { - int ret; - enum pthread_susp old_suspended; + int ret; /* Find the thread in the list of active threads: */ if ((ret = _find_thread(thread)) == 0) { - /* Cancel any pending suspensions: */ - old_suspended = thread->suspended; - thread->suspended = SUSP_NO; - - /* Is it currently suspended? */ - if (thread->state == PS_SUSPENDED) { - /* - * Defer signals to protect the scheduling queues - * from access by the signal handler: - */ - _thread_kern_sig_defer(); - - switch (old_suspended) { - case SUSP_MUTEX_WAIT: - /* Set the thread's state back. */ - PTHREAD_SET_STATE(thread,PS_MUTEX_WAIT); - break; - case SUSP_COND_WAIT: - /* Set the thread's state back. */ - PTHREAD_SET_STATE(thread,PS_COND_WAIT); - break; - case SUSP_JOIN: - /* Set the thread's state back. */ - PTHREAD_SET_STATE(thread,PS_JOIN); - break; - case SUSP_NOWAIT: - /* Allow the thread to run. */ - PTHREAD_SET_STATE(thread,PS_RUNNING); - PTHREAD_WAITQ_REMOVE(thread); - PTHREAD_PRIOQ_INSERT_TAIL(thread); - break; - case SUSP_NO: - case SUSP_YES: - /* Allow the thread to run. */ - PTHREAD_SET_STATE(thread,PS_RUNNING); - PTHREAD_PRIOQ_INSERT_TAIL(thread); - break; - } - - /* - * Undefer and handle pending signals, yielding if - * necessary: - */ - _thread_kern_sig_undefer(); - } + /* + * Defer signals to protect the scheduling queues + * from access by the signal handler: + */ + _thread_kern_sig_defer(); + + if ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) + resume_common(thread); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + return (ret); +} + +void +pthread_resume_all_np(void) +{ + struct pthread *curthread = _get_curthread(); + struct pthread *thread; + + /* + * Defer signals to protect the scheduling queues from access + * by the signal handler: + */ + _thread_kern_sig_defer(); + + TAILQ_FOREACH(thread, &_thread_list, tle) { + if ((thread != curthread) && + ((thread->flags & PTHREAD_FLAGS_SUSPENDED) != 0)) + resume_common(thread); + } + + /* + * Undefer and handle pending signals, yielding if necessary: + */ + _thread_kern_sig_undefer(); +} + +static void +resume_common(struct pthread *thread) +{ + /* Clear the suspend flag: */ + thread->flags &= ~PTHREAD_FLAGS_SUSPENDED; + + /* + * If the thread's state is suspended, that means it is + * now runnable but not in any scheduling queue. Set the + * state to running and insert it into the run queue. + */ + if (thread->state == PS_SUSPENDED) { + PTHREAD_SET_STATE(thread, PS_RUNNING); + if (thread->priority_mutex_count > 0) + PTHREAD_PRIOQ_INSERT_HEAD(thread); + else + PTHREAD_PRIOQ_INSERT_TAIL(thread); } - return(ret); } #endif Index: lib/libc_r/uthread/uthread_select.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_select.c,v retrieving revision 1.16.2.4 diff -u -p -r1.16.2.4 uthread_select.c --- lib/libc_r/uthread/uthread_select.c 17 Oct 2002 19:37:38 -0000 1.16.2.4 +++ lib/libc_r/uthread/uthread_select.c 20 Oct 2002 16:53:00 -0000 @@ -51,7 +51,7 @@ _select(int numfds, fd_set * readfds, fd struct pthread *curthread = _get_curthread(); struct timespec ts; int i, ret = 0, f_wait = 1; - int pfd_index, got_one = 0, fd_count = 0; + int pfd_index, got_events = 0, fd_count = 0; struct pthread_poll_data data; if (numfds > _thread_dtablesize) { @@ -165,13 +165,23 @@ _select(int numfds, fd_set * readfds, fd * this file descriptor from the fdset if * the requested event wasn't ready. */ - got_one = 0; + + /* + * First check for invalid descriptor. + * If found, set errno and return -1. + */ + if (data.fds[i].revents & POLLNVAL) { + errno = EBADF; + return -1; + } + + got_events = 0; if (readfds != NULL) { if (FD_ISSET(data.fds[i].fd, readfds)) { if ((data.fds[i].revents & (POLLIN | POLLRDNORM | POLLERR | POLLHUP | POLLNVAL)) != 0) - got_one = 1; + got_events++; else FD_CLR(data.fds[i].fd, readfds); } @@ -181,7 +191,7 @@ _select(int numfds, fd_set * readfds, fd if ((data.fds[i].revents & (POLLOUT | POLLWRNORM | POLLWRBAND | POLLERR | POLLHUP | POLLNVAL)) != 0) - got_one = 1; + got_events++; else FD_CLR(data.fds[i].fd, writefds); @@ -190,16 +200,15 @@ _select(int numfds, fd_set * readfds, fd if (exceptfds != NULL) { if (FD_ISSET(data.fds[i].fd, exceptfds)) { if (data.fds[i].revents & (POLLRDBAND | - POLLPRI | POLLHUP | POLLERR | - POLLNVAL)) - got_one = 1; + POLLPRI)) + got_events++; else FD_CLR(data.fds[i].fd, exceptfds); } } - if (got_one) - numfds++; + if (got_events != 0) + numfds+=got_events; } ret = numfds; } Index: lib/libc_r/uthread/uthread_sig.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_sig.c,v retrieving revision 1.25.2.12 diff -u -p -r1.25.2.12 uthread_sig.c --- lib/libc_r/uthread/uthread_sig.c 17 Oct 2002 19:37:38 -0000 1.25.2.12 +++ lib/libc_r/uthread/uthread_sig.c 20 Oct 2002 16:10:05 -0000 @@ -48,11 +48,12 @@ static void thread_sig_add(struct pthrea static void thread_sig_check_state(struct pthread *pthread, int sig); static struct pthread *thread_sig_find(int sig); static void thread_sig_handle_special(int sig); -static void thread_sig_savecontext(struct pthread *pthread, ucontext_t *ucp); static void thread_sigframe_add(struct pthread *thread, int sig, int has_args); static void thread_sigframe_save(struct pthread *thread, struct pthread_signal_frame *psf); +static void thread_sig_invoke_handler(int sig, siginfo_t *info, + ucontext_t *ucp); /* #define DEBUG_SIGNAL */ #ifdef DEBUG_SIGNAL @@ -74,22 +75,13 @@ _thread_sig_handler(int sig, siginfo_t * { struct pthread *curthread = _get_curthread(); struct pthread *pthread, *pthread_h; - void *stackp; - int in_sched = 0; + int in_sched = _thread_kern_in_sched; char c; if (ucp == NULL) PANIC("Thread signal handler received null context"); DBG_MSG("Got signal %d, current thread %p\n", sig, curthread); - if (_thread_kern_in_sched != 0) - in_sched = 1; - else { - stackp = (void *)GET_STACK_UC(ucp); - if ((stackp >= _thread_kern_sched_stack) && - (stackp <= _thread_kern_sched_stack + SCHED_STACK_SIZE)) - in_sched = 1; - } /* Check if an interval timer signal: */ if (sig == _SCHED_SIGNAL) { /* Update the scheduling clock: */ @@ -110,16 +102,7 @@ _thread_sig_handler(int sig, siginfo_t * else if (curthread->sig_defer_count > 0) curthread->yield_on_sig_undefer = 1; else { - /* - * Save the context of the currently running thread: - */ - thread_sig_savecontext(curthread, ucp); - - /* - * Schedule the next thread. This function is not - * expected to return because it will do a longjmp - * instead. - */ + /* Schedule the next thread: */ _thread_kern_sched(ucp); /* @@ -213,18 +196,30 @@ _thread_sig_handler(int sig, siginfo_t * thread_sig_handle_special(sig); pthread_h = NULL; - if ((pthread = thread_sig_find(sig)) != NULL) { - DBG_MSG("Got signal %d, adding frame to thread %p\n", - sig, pthread); + if ((pthread = thread_sig_find(sig)) == NULL) + DBG_MSG("No thread to handle signal %d\n", sig); + else if (pthread == curthread) { /* - * A thread was found that can handle the signal. - * Save the context of the currently running thread - * so that we can switch to another thread without - * losing track of where the current thread left off. - * This also applies if the current thread is the - * thread to be signaled. + * Unblock the signal and restore the process signal + * mask in case we don't return from the handler: */ - thread_sig_savecontext(curthread, ucp); + _thread_sigq[sig - 1].blocked = 0; + __sys_sigprocmask(SIG_SETMASK, &_process_sigmask, NULL); + + /* Call the signal handler for the current thread: */ + thread_sig_invoke_handler(sig, info, ucp); + + /* + * Set the process signal mask in the context; it + * could have changed by the handler. + */ + ucp->uc_sigmask = _process_sigmask; + + /* Resume the interrupted thread: */ + sigreturn(ucp); + } else { + DBG_MSG("Got signal %d, adding frame to thread %p\n", + sig, pthread); /* Setup the target thread to receive the signal: */ thread_sig_add(pthread, sig, /*has_args*/ 1); @@ -234,8 +229,6 @@ _thread_sig_handler(int sig, siginfo_t * DBG_MSG("Finished adding frame, head of prio list %p\n", pthread_h); } - else - DBG_MSG("No thread to handle signal %d\n", sig); SIG_SET_INACTIVE(); /* @@ -244,8 +237,8 @@ _thread_sig_handler(int sig, siginfo_t * * signal and the currently running thread is not in a * signal handler. */ - if ((pthread == curthread) || ((pthread_h != NULL) && - (pthread_h->active_priority > curthread->active_priority))) { + if ((pthread_h != NULL) && + (pthread_h->active_priority > curthread->active_priority)) { /* Enter the kernel scheduler: */ _thread_kern_sched(ucp); } @@ -258,15 +251,45 @@ _thread_sig_handler(int sig, siginfo_t * } static void -thread_sig_savecontext(struct pthread *pthread, ucontext_t *ucp) -{ - memcpy(&pthread->ctx.uc, ucp, sizeof(*ucp)); +thread_sig_invoke_handler(int sig, siginfo_t *info, ucontext_t *ucp) + { + struct pthread *curthread = _get_curthread(); + void (*sigfunc)(int, siginfo_t *, void *); + int saved_seqno; + sigset_t saved_sigmask; - /* XXX - Save FP registers too? */ - FP_SAVE_UC(&pthread->ctx.uc); + /* Invoke the signal handler without going through the scheduler: + */ + DBG_MSG("Got signal %d, calling handler for current thread %p\n", + sig, curthread); - /* Mark the context saved as a ucontext: */ - pthread->ctxtype = CTX_UC; + /* Save the threads signal mask: */ + saved_sigmask = curthread->sigmask; + saved_seqno = curthread->sigmask_seqno; + + /* Setup the threads signal mask: */ + SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask); + sigaddset(&curthread->sigmask, sig); + + /* + * Check that a custom handler is installed and if + * the signal is not blocked: + */ + sigfunc = _thread_sigact[sig - 1].sa_sigaction; + if (((__sighandler_t *)sigfunc != SIG_DFL) && + ((__sighandler_t *)sigfunc != SIG_IGN)) { + if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO) != 0) || + (info == NULL)) + (*(sigfunc))(sig, info, ucp); + else + (*(sigfunc))(sig, (siginfo_t *)info->si_code, ucp); + } + /* + * Only restore the signal mask if it hasn't been changed by the + * application during invocation of the signal handler: + */ + if (curthread->sigmask_seqno == saved_seqno) + curthread->sigmask = saved_sigmask; } /* @@ -353,7 +376,8 @@ thread_sig_find(int sig) return (NULL); } else if ((handler_installed != 0) && - !sigismember(&pthread->sigmask, sig)) { + !sigismember(&pthread->sigmask, sig) && + ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) == 0)) { if (pthread->state == PS_SIGSUSPEND) { if (suspended_thread == NULL) suspended_thread = pthread; @@ -769,10 +793,17 @@ thread_sig_add(struct pthread *pthread, /* * The thread should be removed from all scheduling * queues at this point. Raise the priority and place - * the thread in the run queue. + * the thread in the run queue. It is also possible + * for a signal to be sent to a suspended thread, + * mostly via pthread_kill(). If a thread is suspended, + * don't insert it into the priority queue; just set + * its state to suspended and it will run the signal + * handler when it is resumed. */ pthread->active_priority |= PTHREAD_SIGNAL_PRIORITY; - if (thread_is_active == 0) + if ((pthread->flags & PTHREAD_FLAGS_SUSPENDED) != 0) + PTHREAD_SET_STATE(pthread, PS_SUSPENDED); + else if (thread_is_active == 0) PTHREAD_PRIOQ_INSERT_TAIL(pthread); } } @@ -901,17 +932,13 @@ _thread_sig_send(struct pthread *pthread /* Return the signal number: */ pthread->signo = sig; - } else if (pthread == curthread) { + } else if (sigismember(&pthread->sigmask, sig)) /* Add the signal to the pending set: */ sigaddset(&pthread->sigpend, sig); - if (!sigismember(&pthread->sigmask, sig)) { - /* - * Call the kernel scheduler which will safely - * install a signal frame for this thread: - */ - _thread_kern_sched_sig(); - } - } else if (!sigismember(&pthread->sigmask, sig)) { + else if (pthread == curthread) + /* Call the signal handler for the current thread: */ + thread_sig_invoke_handler(sig, NULL, NULL); + else { /* Protect the scheduling queues: */ _thread_kern_sig_defer(); /* @@ -921,9 +948,6 @@ _thread_sig_send(struct pthread *pthread thread_sig_add(pthread, sig, /* has args */ 0); /* Unprotect the scheduling queues: */ _thread_kern_sig_undefer(); - } else { - /* Increment the pending signal count. */ - sigaddset(&pthread->sigpend,sig); } } } @@ -936,7 +960,6 @@ _thread_sig_send(struct pthread *pthread void _thread_sig_wrapper(void) { - void (*sigfunc)(int, siginfo_t *, void *); struct pthread_signal_frame *psf; struct pthread *thread = _get_curthread(); @@ -1002,27 +1025,13 @@ _thread_sig_wrapper(void) thread->sig_defer_count = 0; /* - * Check that a custom handler is installed and if the signal - * is not blocked: + * Dispatch the signal via the custom signal handler: */ - sigfunc = _thread_sigact[psf->signo - 1].sa_sigaction; - if (((__sighandler_t *)sigfunc != SIG_DFL) && - ((__sighandler_t *)sigfunc != SIG_IGN)) { - DBG_MSG("_thread_sig_wrapper: Calling signal handler for " - "thread 0x%p\n", thread); - /* - * Dispatch the signal via the custom signal - * handler: - */ - if (psf->sig_has_args == 0) - (*(sigfunc))(psf->signo, NULL, NULL); - else if ((_thread_sigact[psf->signo - 1].sa_flags & - SA_SIGINFO) != 0) - (*(sigfunc))(psf->signo, &psf->siginfo, &psf->uc); - else - (*(sigfunc))(psf->signo, - (siginfo_t *)psf->siginfo.si_code, &psf->uc); - } + if (psf->sig_has_args == 0) + thread_sig_invoke_handler(psf->signo, NULL, NULL); + else + thread_sig_invoke_handler(psf->signo, &psf->siginfo, &psf->uc); + /* * Call the kernel scheduler to safely restore the frame and * schedule the next thread: @@ -1034,24 +1043,10 @@ static void thread_sigframe_add(struct pthread *thread, int sig, int has_args) { struct pthread_signal_frame *psf = NULL; - unsigned long stackp = 0; + unsigned long stackp; - /* Get the top of the threads stack: */ - switch (thread->ctxtype) { - case CTX_JB: - case CTX_JB_NOSIG: - stackp = GET_STACK_JB(thread->ctx.jb); - break; - case CTX_SJB: - stackp = GET_STACK_SJB(thread->ctx.sigjb); - break; - case CTX_UC: - stackp = GET_STACK_UC(&thread->ctx.uc); - break; - default: - PANIC("Invalid thread context type"); - break; - } + /* Get the top of the threads stack: */ + stackp = GET_STACK_JB(thread->ctx.jb); /* * Leave a little space on the stack and round down to the @@ -1085,8 +1080,6 @@ thread_sigframe_add(struct pthread *thre /* Set up the new frame: */ thread->curframe = psf; - thread->ctxtype = CTX_JB_NOSIG; - thread->longjmp_val = 1; thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE | PTHREAD_FLAGS_IN_SYNCQ; /* @@ -1102,8 +1095,7 @@ void _thread_sigframe_restore(struct pthread *thread, struct pthread_signal_frame *psf) { - thread->ctxtype = psf->ctxtype; - memcpy(&thread->ctx.uc, &psf->ctx.uc, sizeof(thread->ctx.uc)); + memcpy(&thread->ctx, &psf->ctx, sizeof(thread->ctx)); /* * Only restore the signal mask if it hasn't been changed * by the application during invocation of the signal handler: @@ -1116,7 +1108,6 @@ _thread_sigframe_restore(struct pthread thread->state = psf->saved_state.psd_state; thread->flags = psf->saved_state.psd_flags; thread->interrupted = psf->saved_state.psd_interrupted; - thread->longjmp_val = psf->saved_state.psd_longjmp_val; thread->signo = psf->saved_state.psd_signo; thread->sig_defer_count = psf->saved_state.psd_sig_defer_count; } @@ -1124,8 +1115,7 @@ _thread_sigframe_restore(struct pthread static void thread_sigframe_save(struct pthread *thread, struct pthread_signal_frame *psf) { - psf->ctxtype = thread->ctxtype; - memcpy(&psf->ctx.uc, &thread->ctx.uc, sizeof(thread->ctx.uc)); + memcpy(&psf->ctx, &thread->ctx, sizeof(thread->ctx)); psf->saved_state.psd_sigmask = thread->sigmask; psf->saved_state.psd_curframe = thread->curframe; psf->saved_state.psd_wakeup_time = thread->wakeup_time; @@ -1134,7 +1124,6 @@ thread_sigframe_save(struct pthread *thr psf->saved_state.psd_flags = thread->flags & (PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE); psf->saved_state.psd_interrupted = thread->interrupted; - psf->saved_state.psd_longjmp_val = thread->longjmp_val; psf->saved_state.psd_sigmask_seqno = thread->sigmask_seqno; psf->saved_state.psd_signo = thread->signo; psf->saved_state.psd_sig_defer_count = thread->sig_defer_count; Index: lib/libc_r/uthread/uthread_sigpending.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_sigpending.c,v retrieving revision 1.6.2.1 diff -u -p -r1.6.2.1 uthread_sigpending.c --- lib/libc_r/uthread/uthread_sigpending.c 17 Oct 2002 19:37:39 -0000 1.6.2.1 +++ lib/libc_r/uthread/uthread_sigpending.c 20 Oct 2002 16:12:30 -0000 @@ -31,6 +31,9 @@ * * $FreeBSD: src/lib/libc_r/uthread/uthread_sigpending.c,v 1.6.2.1 2002/10/17 19:37:39 fjoe Exp $ */ +#include <sys/param.h> +#include <sys/types.h> +#include <sys/signalvar.h> #include <signal.h> #include <errno.h> #ifdef _THREAD_SAFE @@ -38,7 +41,7 @@ #include "pthread_private.h" int -_sigpending(sigset_t * set) +_sigpending(sigset_t *set) { struct pthread *curthread = _get_curthread(); int ret = 0; @@ -50,6 +53,7 @@ _sigpending(sigset_t * set) } else { *set = curthread->sigpend; + SIGSETOR(*set, _process_sigpending); } /* Return the completion status: */ return (ret); Index: lib/libc_r/uthread/uthread_sigsuspend.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_sigsuspend.c,v retrieving revision 1.9.2.1 diff -u -p -r1.9.2.1 uthread_sigsuspend.c --- lib/libc_r/uthread/uthread_sigsuspend.c 17 Oct 2002 19:37:39 -0000 1.9.2.1 +++ lib/libc_r/uthread/uthread_sigsuspend.c 20 Oct 2002 16:10:05 -0000 @@ -32,6 +32,8 @@ * $FreeBSD: src/lib/libc_r/uthread/uthread_sigsuspend.c,v 1.9.2.1 2002/10/17 19:37:39 fjoe Exp $ */ #include <signal.h> +#include <sys/param.h> +#include <sys/signalvar.h> #include <errno.h> #ifdef _THREAD_SAFE #include <pthread.h> @@ -42,7 +44,7 @@ _sigsuspend(const sigset_t * set) { struct pthread *curthread = _get_curthread(); int ret = -1; - sigset_t oset; + sigset_t oset, sigset; /* Check if a new signal set was provided by the caller: */ if (set != NULL) { @@ -52,8 +54,24 @@ _sigsuspend(const sigset_t * set) /* Change the caller's mask: */ curthread->sigmask = *set; - /* Wait for a signal: */ - _thread_kern_sched_state(PS_SIGSUSPEND, __FILE__, __LINE__); + /* + * Check if there are pending signals for the running + * thread or process that aren't blocked: + */ + sigset = curthread->sigpend; + SIGSETOR(sigset, _process_sigpending); + SIGSETNAND(sigset, curthread->sigmask); + if (SIGNOTEMPTY(sigset)) { + /* + * Call the kernel scheduler which will safely + * install a signal frame for the running thread: + */ + _thread_kern_sched_sig(); + } else { + /* Wait for a signal: */ + _thread_kern_sched_state(PS_SIGSUSPEND, + __FILE__, __LINE__); + } /* Always return an interrupted error: */ errno = EINTR; Index: lib/libc_r/uthread/uthread_single_np.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_single_np.c,v retrieving revision 1.3.2.1 diff -u -p -r1.3.2.1 uthread_single_np.c --- lib/libc_r/uthread/uthread_single_np.c 17 Oct 2002 19:37:39 -0000 1.3.2.1 +++ lib/libc_r/uthread/uthread_single_np.c 20 Oct 2002 14:43:55 -0000 @@ -34,12 +34,17 @@ #include <string.h> #ifdef _THREAD_SAFE #include <pthread.h> -#include "pthread_private.h" +#include <pthread_np.h> int pthread_single_np() { + /* Enter single-threaded (non-POSIX) scheduling mode: */ - _thread_single = _get_curthread(); - return(0); + pthread_suspend_all_np(); + /* + * XXX - Do we want to do this? + * __is_threaded = 0; + */ + return (0); } #endif Index: lib/libc_r/uthread/uthread_suspend_np.c =================================================================== RCS file: /home/ncvs/src/lib/libc_r/uthread/uthread_suspend_np.c,v retrieving revision 1.7.2.5 diff -u -p -r1.7.2.5 uthread_suspend_np.c --- lib/libc_r/uthread/uthread_suspend_np.c 17 Oct 2002 19:37:39 -0000 1.7.2.5 +++ lib/libc_r/uthread/uthread_suspend_np.c 20 Oct 2002 14:43:55 -0000 @@ -36,7 +36,7 @@ #include <pthread.h> #include "pthread_private.h" -static void finish_suspension(void *arg); +static void suspend_common(struct pthread *thread); /* Suspend a thread: */ int @@ -44,100 +44,19 @@ pthread_suspend_np(pthread_t thread) { int ret; + /* Suspending the current thread doesn't make sense. */ + if (thread == _get_curthread()) + ret = EDEADLK; + /* Find the thread in the list of active threads: */ - if ((ret = _find_thread(thread)) == 0) { + else if ((ret = _find_thread(thread)) == 0) { /* * Defer signals to protect the scheduling queues from * access by the signal handler: */ _thread_kern_sig_defer(); - switch (thread->state) { - case PS_RUNNING: - /* - * Remove the thread from the priority queue and - * set the state to suspended: - */ - PTHREAD_PRIOQ_REMOVE(thread); - PTHREAD_SET_STATE(thread, PS_SUSPENDED); - break; - - case PS_SPINBLOCK: - case PS_FDR_WAIT: - case PS_FDW_WAIT: - case PS_POLL_WAIT: - case PS_SELECT_WAIT: - /* - * Remove these threads from the work queue - * and mark the operation as interrupted: - */ - if ((thread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0) - PTHREAD_WORKQ_REMOVE(thread); - _thread_seterrno(thread,EINTR); - - /* FALLTHROUGH */ - case PS_SLEEP_WAIT: - thread->interrupted = 1; - - /* FALLTHROUGH */ - case PS_SIGTHREAD: - case PS_WAIT_WAIT: - case PS_SIGSUSPEND: - case PS_SIGWAIT: - /* - * Remove these threads from the waiting queue and - * set their state to suspended: - */ - PTHREAD_WAITQ_REMOVE(thread); - PTHREAD_SET_STATE(thread, PS_SUSPENDED); - break; - - case PS_MUTEX_WAIT: - /* Mark the thread as suspended and still in a queue. */ - thread->suspended = SUSP_MUTEX_WAIT; - - PTHREAD_SET_STATE(thread, PS_SUSPENDED); - break; - case PS_COND_WAIT: - /* Mark the thread as suspended and still in a queue. */ - thread->suspended = SUSP_COND_WAIT; - - PTHREAD_SET_STATE(thread, PS_SUSPENDED); - break; - case PS_JOIN: - /* Mark the thread as suspended and joining: */ - thread->suspended = SUSP_JOIN; - - PTHREAD_NEW_STATE(thread, PS_SUSPENDED); - break; - case PS_FDLR_WAIT: - case PS_FDLW_WAIT: - case PS_FILE_WAIT: - /* Mark the thread as suspended: */ - thread->suspended = SUSP_YES; - - /* - * Threads in these states may be in queues. - * In order to preserve queue integrity, the - * cancelled thread must remove itself from the - * queue. Mark the thread as interrupted and - * set the state to running. When the thread - * resumes, it will remove itself from the queue - * and call the suspension completion routine. - */ - thread->interrupted = 1; - _thread_seterrno(thread, EINTR); - PTHREAD_NEW_STATE(thread, PS_RUNNING); - thread->continuation = finish_suspension; - break; - - case PS_DEAD: - case PS_DEADLOCK: - case PS_STATE_MAX: - case PS_SUSPENDED: - /* Nothing needs to be done: */ - break; - } + suspend_common(thread); /* * Undefer and handle pending signals, yielding if @@ -145,17 +64,40 @@ pthread_suspend_np(pthread_t thread) */ _thread_kern_sig_undefer(); } - return(ret); + return (ret); } -static void -finish_suspension(void *arg) +void +pthread_suspend_all_np(void) { struct pthread *curthread = _get_curthread(); + struct pthread *thread; - if (curthread->suspended != SUSP_NO) - _thread_kern_sched_state(PS_SUSPENDED, __FILE__, __LINE__); -} + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + TAILQ_FOREACH(thread, &_thread_list, tle) { + if (thread != curthread) + suspend_common(thread); + } + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); +} +void +suspend_common(struct pthread *thread) +{ + thread->flags |= PTHREAD_FLAGS_SUSPENDED; + if (thread->flags & PTHREAD_FLAGS_IN_PRIOQ) { + PTHREAD_PRIOQ_REMOVE(thread); + PTHREAD_SET_STATE(thread, PS_SUSPENDED); + } +} #endif --UlVJffcvxoiEqYs2-- To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-stable" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20021021001514.A38080>