diff --git a/ChangeLog b/ChangeLog index 4b5fb9bcdc..1f6e98a6b6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +Sun Apr 2 13:13:52 1995 Roland McGrath + + * sysdeps/mach/hurd/i386/trampoline.c: Add a link to + SS->active_resources, so that _hurdsig_longjmp_from_handler will + be called when a longjmp unwinds the signal frame. + * sysdeps/mach/hurd/i386/sigreturn.c: Remove the link on the + SS->active_resources chain added by _hurd_setup_sighandler. + * hurd/sigunwind.c: New file. + * hurd/Makefile (sig): Add sigunwind. + + * Makerules (lib%.so: lib%_pic.a): Remove dir name from $*. + + * MakeTAGS (tags-sources): Include $(all-dist). + [subdir] (all-dist): Define to $(distribute). + Sat Apr 1 00:08:06 1995 Roland McGrath * Makerules (lib%.so: lib%_pic.a): Pass -L options for subdir and diff --git a/MakeTAGS b/MakeTAGS index acea142bf6..29dfc47f01 100644 --- a/MakeTAGS +++ b/MakeTAGS @@ -1,6 +1,6 @@ # Make the TAGS files. -# Copyright (C) 1992, 1994 Free Software Foundation, Inc. +# Copyright (C) 1992, 1994, 1995 Free Software Foundation, Inc. # This file is part of the GNU C Library. # The GNU C Library is free software; you can redistribute it and/or @@ -33,9 +33,9 @@ ifeq ($(subdir),ctype) # the header files so tags for optimizing #define's in the # headers won't be put in the tags files, but for ctype, # the functions are just backup for the #define's in the header. -tags_sources = $(all-headers) $(all-sources) +tags_sources = $(all-headers) $(all-sources) $(all-dist) else # Not ctype. -tags_sources = $(all-sources) $(all-headers) +tags_sources = $(all-sources) $(all-headers) $(all-dist) endif # ctype endif # No tags_sources @@ -67,6 +67,8 @@ all-dist = $(foreach Dist,$(wildcard $(all-dirs:%=%/Dist)),\ $(filter %.c %.h %.S %.s,\ $(shell cat $(Dist))))) tags_sources = $(all-sources) $(all-headers) $(all-dist) +else +all-dist = $(distribute) endif # All different versions of $(sources), preserving the configured sysdep diff --git a/Makerules b/Makerules index f3fdb37c2f..55e7520c64 100644 --- a/Makerules +++ b/Makerules @@ -343,7 +343,7 @@ ifeq (yes,$(build-shared)) lib%.so: lib%_pic.a $(LINK.o) -shared -o $@ -Wl,--whole-archive $< \ -L$(firstword $(objdir) .) -L$(common-objpfx:%/=%) \ - $(LDLIBS-$*.so) + $(LDLIBS-$(notdir $*).so) endif libobjs: $(foreach o,$(object-suffixes),\ diff --git a/hurd/Makefile b/hurd/Makefile index 278d8ec315..254e89cb50 100644 --- a/hurd/Makefile +++ b/hurd/Makefile @@ -51,7 +51,7 @@ routines = hurdinit hurdid hurdlookup hurdpid hurdrlimit hurdprio hurdexec \ ports-get ports-set hurdports hurdmsg \ $(sig) $(dtable) hurdinline port-cleanup sig = hurdsig hurdfault faultexc siginfo hurd-raise preempt-sig \ - trampoline longjmp-ts catch-exc exc2signal hurdkill + trampoline longjmp-ts catch-exc exc2signal hurdkill sigunwind dtable = dtable port2fd new-fd alloc-fd intern-fd \ getdport openport \ fd-close fd-read fd-write hurdioctl ctty-input ctty-output diff --git a/hurd/sigunwind.c b/hurd/sigunwind.c new file mode 100644 index 0000000000..7420f43ae4 --- /dev/null +++ b/hurd/sigunwind.c @@ -0,0 +1,135 @@ +/* longjmp cleanup function for unwinding past signal handlers. +Copyright (C) 1995 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with the GNU C Library; see the file COPYING.LIB. If +not, write to the Free Software Foundation, Inc., 675 Mass Ave, +Cambridge, MA 02139, USA. */ + +#include +#include "thread_state.h" +#include +#include + +extern void _hurd_longjmp_thread_state (struct machine_thread_state *, + jmp_buf env, int value); + + +/* _hurd_setup_sighandler puts a link on the `active resources' chain so that + _longjmp_unwind will call this function with the `struct sigcontext *' + describing the context interrupted by the signal, when `longjmp' is jumping + to an environment that unwinds past the interrupted frame. */ + +void +_hurdsig_longjmp_from_handler (void *data, jmp_buf env, int val) +{ + struct sigcontext *scp = data; + struct hurd_sigstate *ss = _hurd_self_sigstate (); + int onstack; + inline void cleanup (void) + { + /* Destroy the MiG reply port used by the signal handler, and restore + the reply port in use by the thread when interrupted. */ + mach_port_t *reply_port = + (mach_port_t *) __hurd_threadvar_location (_HURD_THREADVAR_MIG_REPLY); + if (*reply_port) + __mach_port_destroy (__mach_task_self (), *reply_port); + *reply_port = scp->sc_reply_port; + } + + __spin_lock (&ss->lock); + /* We should only ever be called from _longjmp_unwind (in jmp-unwind.c), + which calls us inside a critical section. */ + assert (ss->critical_section); + /* Are we on the alternate signal stack now? */ + onstack = (ss->sigaltstack.ss_flags & SA_ONSTACK); + __spin_unlock (&ss->lock); + + if (onstack && ! scp->sc_onstack) + { + /* We are unwinding off the signal stack. We must use sigreturn to + do it robustly. Mutate the sigcontext so that when sigreturn + resumes from that context, it will be as if `__longjmp (ENV, VAL)' + were done. */ + + struct hurd_userlink *link; + + /* Continue _longjmp_unwind's job of running the unwind + forms for frames being unwound, since we will not + return to its loop like this one, which called us. */ + for (link = ss->active_resources; + link && _JMPBUF_UNWINDS (env[0].__jmpbuf, link); + link = link->thread.next) + if (_hurd_userlink_unlink (link)) + { + if (link->cleanup == &_hurdsig_longjmp_from_handler) + { + /* We are unwinding past another signal handler invocation. + Just finish the cleanup for this (inner) one, and then + swap SCP to restore to the outer context. */ + cleanup (); + scp = link->cleanup_data; + } + else + (*link->cleanup) (link->cleanup_data, env, val); + } + +#define sc_machine_thread_state paste(sc_,machine_thread_state) +#define paste(a,b) paste1(a,b) +#define paste1(a,b) a##b + + /* There are no more unwind forms to be run! + Now we can just have the sigreturn do the longjmp for us. */ + _hurd_longjmp_thread_state + ((struct machine_thread_state *) &scp->sc_machine_thread_state, + env, val); + + /* Restore to the same current signal mask. If sigsetjmp saved the + mask, longjmp has already restored it as desired; if not, we + should leave it as it is. */ + scp->sc_mask = ss->blocked; + + /* sigreturn expects the link added by _hurd_setup_sighandler + to still be there, but _longjmp_unwind removed it just before + calling us. Put it back now so sigreturn can find it. */ + link = (void *) &scp[1]; + assert (! link->resource.next && ! link->resource.prevp); + assert (link->thread.next == ss->active_resources); + assert (link->thread.prevp = &ss->active_resources); + if (link->thread.next) + link->thread.next->thread.prevp = &link->thread.next; + ss->active_resources = link; + + /* We must momentarily exit the critical section so that sigreturn + does not get upset with us. But we don't want signal handlers + running right now, because we are presently in the bogus state of + having run all the unwind forms back to ENV's frame, but our SP is + still inside those unwound frames. */ + __spin_lock (&ss->lock); + ss->critical_section = 0; + ss->blocked = ~(sigset_t) 0 & ~_SIG_CANT_MASK; + __spin_unlock (&ss->lock); + + /* Restore to the modified signal context that now + performs `longjmp (ENV, VAL)'. */ + __sigreturn (scp); + assert (! "sigreturn returned!"); + } + + /* We are not unwinding off the alternate signal stack. So nothing + really funny is going on here. We can just clean up this handler + frame and let _longjmp_unwind continue unwinding. */ + cleanup (); + ss->intr_port = scp->sc_intr_port; +} diff --git a/sysdeps/mach/hurd/i386/sigreturn.c b/sysdeps/mach/hurd/i386/sigreturn.c index 19ba1d472c..d00fa7755f 100644 --- a/sysdeps/mach/hurd/i386/sigreturn.c +++ b/sysdeps/mach/hurd/i386/sigreturn.c @@ -28,6 +28,7 @@ int __sigreturn (struct sigcontext *scp) { struct hurd_sigstate *ss; + struct hurd_userlink *link = (void *) &scp[1]; mach_port_t *reply_port; if (scp == NULL || (scp->sc_mask & _SIG_CANT_MASK)) @@ -39,6 +40,11 @@ __sigreturn (struct sigcontext *scp) ss = _hurd_self_sigstate (); __spin_lock (&ss->lock); + /* Remove the link on the `active resources' chain added by + _hurd_setup_sighandler. Its purpose was to make sure + that we got called; now we have, it is done. */ + _hurd_userlink_unlink (link); + /* Restore the set of blocked signals, and the intr_port slot. */ ss->blocked = scp->sc_mask; ss->intr_port = scp->sc_intr_port; diff --git a/sysdeps/mach/hurd/i386/trampoline.c b/sysdeps/mach/hurd/i386/trampoline.c index a83a8a8e7d..5f3361b97e 100644 --- a/sysdeps/mach/hurd/i386/trampoline.c +++ b/sysdeps/mach/hurd/i386/trampoline.c @@ -18,6 +18,7 @@ not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include +#include #include "thread_state.h" #include #include @@ -55,6 +56,7 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler, void *sigreturn_returns_here; struct sigcontext *return_scp; /* Same; arg to sigreturn. */ struct sigcontext ctx; + struct hurd_userlink link; } *stackframe; if (ss->context) @@ -118,6 +120,24 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler, { int ok; + extern void _hurdsig_longjmp_from_handler (void *, jmp_buf, int); + + /* Add a link to the thread's active-resources list. We mark this as + the only user of the "resource", so the cleanup function will be + called by any longjmp which is unwinding past the signal frame. + The cleanup function (in sigunwind.c) will make sure that all the + appropriate cleanups done by sigreturn are taken care of. */ + stackframe->link.cleanup = &_hurdsig_longjmp_from_handler; + stackframe->link.cleanup_data = &stackframe->ctx; + stackframe->link.resource.next = NULL; + stackframe->link.resource.prevp = NULL; + stackframe->link.thread.next = ss->active_resources; + stackframe->link.thread.prevp = &ss->active_resources; + if (stackframe->link.thread.next) + stackframe->link.thread.next->thread.prevp + = &stackframe->link.thread.next; + ss->active_resources = &stackframe->link; + /* Set up the arguments for the signal handler. */ stackframe->signo = signo; stackframe->sigcode = sigcode;