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