]>
Commit | Line | Data |
---|---|---|
fb8e70d6 | 1 | /* Convenience function to catch expected signals during an operation. |
bfff8b1b | 2 | Copyright (C) 1996-2017 Free Software Foundation, Inc. |
10dc2a90 | 3 | This file is part of the GNU C Library. |
fb8e70d6 | 4 | |
10dc2a90 | 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. | |
fb8e70d6 | 9 | |
10dc2a90 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. |
fb8e70d6 | 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/>. */ | |
fb8e70d6 RM |
18 | |
19 | #include <hurd/signal.h> | |
20 | #include <hurd/sigpreempt.h> | |
21 | #include <string.h> | |
22 | #include <assert.h> | |
23 | ||
24 | error_t | |
25 | hurd_catch_signal (sigset_t sigset, | |
26 | unsigned long int first, unsigned long int last, | |
10dc2a90 | 27 | error_t (*operate) (struct hurd_signal_preemptor *), |
fb8e70d6 RM |
28 | sighandler_t handler) |
29 | { | |
ecd0de9a ST |
30 | /* We need to restore the signal mask, because otherwise the |
31 | signal-handling code will have blocked the caught signal and for | |
32 | instance calling hurd_catch_signal again would then dump core. */ | |
33 | sigjmp_buf buf; | |
fb8e70d6 | 34 | void throw (int signo, long int sigcode, struct sigcontext *scp) |
ecd0de9a | 35 | { siglongjmp (buf, scp->sc_error ?: EGRATUITOUS); } |
fb8e70d6 | 36 | |
10dc2a90 | 37 | struct hurd_signal_preemptor preemptor = |
fb8e70d6 RM |
38 | { |
39 | sigset, first, last, | |
40 | NULL, handler == SIG_ERR ? (sighandler_t) &throw : handler, | |
41 | }; | |
42 | ||
43 | struct hurd_sigstate *const ss = _hurd_self_sigstate (); | |
44 | error_t error; | |
45 | ||
ecd0de9a | 46 | if (handler != SIG_ERR) |
fb8e70d6 RM |
47 | /* Not our handler; don't bother saving state. */ |
48 | error = 0; | |
49 | else | |
50 | /* This returns again with nonzero value when we preempt a signal. */ | |
ecd0de9a | 51 | error = sigsetjmp (buf, 1); |
fb8e70d6 RM |
52 | |
53 | if (error == 0) | |
54 | { | |
10dc2a90 | 55 | /* Install a signal preemptor for the thread. */ |
fb8e70d6 | 56 | __spin_lock (&ss->lock); |
10dc2a90 UD |
57 | preemptor.next = ss->preemptors; |
58 | ss->preemptors = &preemptor; | |
fb8e70d6 RM |
59 | __spin_unlock (&ss->lock); |
60 | ||
61 | /* Try the operation that might crash. */ | |
10dc2a90 | 62 | (*operate) (&preemptor); |
fb8e70d6 RM |
63 | } |
64 | ||
65 | /* Either FUNCTION completed happily and ERROR is still zero, or it hit | |
66 | an expected signal and `throw' made setjmp return the signal error | |
10dc2a90 | 67 | code in ERROR. Now we can remove the preemptor and return. */ |
fb8e70d6 RM |
68 | |
69 | __spin_lock (&ss->lock); | |
10dc2a90 UD |
70 | assert (ss->preemptors == &preemptor); |
71 | ss->preemptors = preemptor.next; | |
fb8e70d6 RM |
72 | __spin_unlock (&ss->lock); |
73 | ||
74 | return error; | |
75 | } | |
76 | ||
77 | ||
78 | error_t | |
79 | hurd_safe_memset (void *dest, int byte, size_t nbytes) | |
80 | { | |
10dc2a90 | 81 | error_t operate (struct hurd_signal_preemptor *preemptor) |
fb8e70d6 RM |
82 | { |
83 | memset (dest, byte, nbytes); | |
84 | return 0; | |
85 | } | |
86 | return hurd_catch_signal (sigmask (SIGBUS) | sigmask (SIGSEGV), | |
87 | (vm_address_t) dest, (vm_address_t) dest + nbytes, | |
88 | &operate, SIG_ERR); | |
89 | } | |
c3d3967c RM |
90 | |
91 | ||
92 | error_t | |
93 | hurd_safe_copyout (void *dest, const void *src, size_t nbytes) | |
94 | { | |
10dc2a90 | 95 | error_t operate (struct hurd_signal_preemptor *preemptor) |
c3d3967c RM |
96 | { |
97 | memcpy (dest, src, nbytes); | |
98 | return 0; | |
99 | } | |
100 | return hurd_catch_signal (sigmask (SIGBUS) | sigmask (SIGSEGV), | |
101 | (vm_address_t) dest, (vm_address_t) dest + nbytes, | |
102 | &operate, SIG_ERR); | |
103 | } | |
104 | ||
105 | error_t | |
106 | hurd_safe_copyin (void *dest, const void *src, size_t nbytes) | |
107 | { | |
10dc2a90 | 108 | error_t operate (struct hurd_signal_preemptor *preemptor) |
c3d3967c RM |
109 | { |
110 | memcpy (dest, src, nbytes); | |
111 | return 0; | |
112 | } | |
113 | return hurd_catch_signal (sigmask (SIGBUS) | sigmask (SIGSEGV), | |
114 | (vm_address_t) src, (vm_address_t) src + nbytes, | |
115 | &operate, SIG_ERR); | |
116 | } | |
117 | ||
118 | error_t | |
119 | hurd_safe_memmove (void *dest, const void *src, size_t nbytes) | |
120 | { | |
121 | jmp_buf buf; | |
122 | void throw (int signo, long int sigcode, struct sigcontext *scp) | |
123 | { longjmp (buf, scp->sc_error ?: EGRATUITOUS); } | |
124 | ||
10dc2a90 | 125 | struct hurd_signal_preemptor src_preemptor = |
c3d3967c RM |
126 | { |
127 | sigmask (SIGBUS) | sigmask (SIGSEGV), | |
128 | (vm_address_t) src, (vm_address_t) src + nbytes, | |
129 | NULL, (sighandler_t) &throw, | |
130 | }; | |
10dc2a90 | 131 | struct hurd_signal_preemptor dest_preemptor = |
c3d3967c RM |
132 | { |
133 | sigmask (SIGBUS) | sigmask (SIGSEGV), | |
134 | (vm_address_t) dest, (vm_address_t) dest + nbytes, | |
135 | NULL, (sighandler_t) &throw, | |
10dc2a90 | 136 | &src_preemptor |
c3d3967c RM |
137 | }; |
138 | ||
139 | struct hurd_sigstate *const ss = _hurd_self_sigstate (); | |
140 | error_t error; | |
141 | ||
142 | /* This returns again with nonzero value when we preempt a signal. */ | |
143 | error = setjmp (buf); | |
144 | ||
145 | if (error == 0) | |
146 | { | |
10dc2a90 | 147 | /* Install a signal preemptor for the thread. */ |
c3d3967c | 148 | __spin_lock (&ss->lock); |
10dc2a90 UD |
149 | src_preemptor.next = ss->preemptors; |
150 | ss->preemptors = &dest_preemptor; | |
c3d3967c RM |
151 | __spin_unlock (&ss->lock); |
152 | ||
153 | /* Do the copy; it might fault. */ | |
154 | memmove (dest, src, nbytes); | |
155 | } | |
156 | ||
157 | /* Either memmove completed happily and ERROR is still zero, or it hit | |
158 | an expected signal and `throw' made setjmp return the signal error | |
10dc2a90 | 159 | code in ERROR. Now we can remove the preemptor and return. */ |
c3d3967c RM |
160 | |
161 | __spin_lock (&ss->lock); | |
10dc2a90 UD |
162 | assert (ss->preemptors == &dest_preemptor); |
163 | ss->preemptors = src_preemptor.next; | |
c3d3967c RM |
164 | __spin_unlock (&ss->lock); |
165 | ||
166 | return error; | |
167 | } |