]> sourceware.org Git - glibc.git/blame - hurd/sigunwind.c
Fix leading whitespaces.
[glibc.git] / hurd / sigunwind.c
CommitLineData
e607b492 1/* longjmp cleanup function for unwinding past signal handlers.
568035b7 2 Copyright (C) 1995-2013 Free Software Foundation, Inc.
c84142e8 3 This file is part of the GNU C Library.
e607b492 4
c84142e8 5 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
e607b492 9
c84142e8
UD
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 13 Lesser General Public License for more details.
e607b492 14
41bdb6e2 15 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
e607b492
RM
18
19#include <hurd.h>
8f480b4b 20#include <thread_state.h>
e9915a66 21#include <jmpbuf-unwind.h>
e607b492 22#include <assert.h>
d745642e 23#include <stdint.h>
e607b492 24
e607b492
RM
25
26/* _hurd_setup_sighandler puts a link on the `active resources' chain so that
27 _longjmp_unwind will call this function with the `struct sigcontext *'
28 describing the context interrupted by the signal, when `longjmp' is jumping
29 to an environment that unwinds past the interrupted frame. */
30
31void
32_hurdsig_longjmp_from_handler (void *data, jmp_buf env, int val)
33{
34 struct sigcontext *scp = data;
35 struct hurd_sigstate *ss = _hurd_self_sigstate ();
36 int onstack;
37 inline void cleanup (void)
38 {
39 /* Destroy the MiG reply port used by the signal handler, and restore
40 the reply port in use by the thread when interrupted. */
41 mach_port_t *reply_port =
42 (mach_port_t *) __hurd_threadvar_location (_HURD_THREADVAR_MIG_REPLY);
43 if (*reply_port)
574ce5e4
MB
44 {
45 mach_port_t port = *reply_port;
46 /* Assigning MACH_PORT_DEAD here tells libc's mig_get_reply_port
47 not to get another reply port, but avoids mig_dealloc_reply_port
48 trying to deallocate it after the receive fails (which it will,
49 because the reply port will be bogus, regardless). */
50 *reply_port = MACH_PORT_DEAD;
51 __mach_port_destroy (__mach_task_self (), port);
52 }
e607b492
RM
53 *reply_port = scp->sc_reply_port;
54 }
55
56 __spin_lock (&ss->lock);
57 /* We should only ever be called from _longjmp_unwind (in jmp-unwind.c),
58 which calls us inside a critical section. */
8f0c527e 59 assert (__spin_lock_locked (&ss->critical_section_lock));
e607b492 60 /* Are we on the alternate signal stack now? */
7ce241a0 61 onstack = (ss->sigaltstack.ss_flags & SS_ONSTACK);
e607b492
RM
62 __spin_unlock (&ss->lock);
63
64 if (onstack && ! scp->sc_onstack)
65 {
66 /* We are unwinding off the signal stack. We must use sigreturn to
67 do it robustly. Mutate the sigcontext so that when sigreturn
68 resumes from that context, it will be as if `__longjmp (ENV, VAL)'
69 were done. */
70
71 struct hurd_userlink *link;
72
db169ed5
RM
73 inline uintptr_t demangle_ptr (uintptr_t x)
74 {
75# ifdef PTR_DEMANGLE
76 PTR_DEMANGLE (x);
77# endif
78 return x;
79 }
80
e607b492
RM
81 /* Continue _longjmp_unwind's job of running the unwind
82 forms for frames being unwound, since we will not
83 return to its loop like this one, which called us. */
84 for (link = ss->active_resources;
db169ed5 85 link && _JMPBUF_UNWINDS (env[0].__jmpbuf, link, demangle_ptr);
e607b492
RM
86 link = link->thread.next)
87 if (_hurd_userlink_unlink (link))
88 {
89 if (link->cleanup == &_hurdsig_longjmp_from_handler)
90 {
91 /* We are unwinding past another signal handler invocation.
92 Just finish the cleanup for this (inner) one, and then
93 swap SCP to restore to the outer context. */
94 cleanup ();
95 scp = link->cleanup_data;
96 }
97 else
98 (*link->cleanup) (link->cleanup_data, env, val);
99 }
100
101#define sc_machine_thread_state paste(sc_,machine_thread_state)
102#define paste(a,b) paste1(a,b)
103#define paste1(a,b) a##b
104
105 /* There are no more unwind forms to be run!
106 Now we can just have the sigreturn do the longjmp for us. */
107 _hurd_longjmp_thread_state
108 ((struct machine_thread_state *) &scp->sc_machine_thread_state,
109 env, val);
110
111 /* Restore to the same current signal mask. If sigsetjmp saved the
112 mask, longjmp has already restored it as desired; if not, we
113 should leave it as it is. */
114 scp->sc_mask = ss->blocked;
115
116 /* sigreturn expects the link added by _hurd_setup_sighandler
117 to still be there, but _longjmp_unwind removed it just before
118 calling us. Put it back now so sigreturn can find it. */
119 link = (void *) &scp[1];
120 assert (! link->resource.next && ! link->resource.prevp);
121 assert (link->thread.next == ss->active_resources);
f9f7fcbe 122 assert (link->thread.prevp == &ss->active_resources);
e607b492
RM
123 if (link->thread.next)
124 link->thread.next->thread.prevp = &link->thread.next;
125 ss->active_resources = link;
126
127 /* We must momentarily exit the critical section so that sigreturn
128 does not get upset with us. But we don't want signal handlers
129 running right now, because we are presently in the bogus state of
130 having run all the unwind forms back to ENV's frame, but our SP is
131 still inside those unwound frames. */
132 __spin_lock (&ss->lock);
8f0c527e 133 __spin_unlock (&ss->critical_section_lock);
e607b492
RM
134 ss->blocked = ~(sigset_t) 0 & ~_SIG_CANT_MASK;
135 __spin_unlock (&ss->lock);
136
137 /* Restore to the modified signal context that now
138 performs `longjmp (ENV, VAL)'. */
139 __sigreturn (scp);
140 assert (! "sigreturn returned!");
141 }
142
143 /* We are not unwinding off the alternate signal stack. So nothing
144 really funny is going on here. We can just clean up this handler
145 frame and let _longjmp_unwind continue unwinding. */
146 cleanup ();
147 ss->intr_port = scp->sc_intr_port;
148}
This page took 0.350542 seconds and 5 git commands to generate.