chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / hurd / catch-signal.c
1 /* Convenience function to catch expected signals during an operation.
2    Copyright (C) 1996 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
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.
9
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
13    Lesser General Public License for more details.
14
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.  */
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,
28                    error_t (*operate) (struct hurd_signal_preemptor *),
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
35   struct hurd_signal_preemptor preemptor =
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     {
53       /* Install a signal preemptor for the thread.  */
54       __spin_lock (&ss->lock);
55       preemptor.next = ss->preemptors;
56       ss->preemptors = &preemptor;
57       __spin_unlock (&ss->lock);
58
59       /* Try the operation that might crash.  */
60       (*operate) (&preemptor);
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
65      code in ERROR.  Now we can remove the preemptor and return.  */
66
67   __spin_lock (&ss->lock);
68   assert (ss->preemptors == &preemptor);
69   ss->preemptors = preemptor.next;
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 {
79   error_t operate (struct hurd_signal_preemptor *preemptor)
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 }
88
89
90 error_t
91 hurd_safe_copyout (void *dest, const void *src, size_t nbytes)
92 {
93   error_t operate (struct hurd_signal_preemptor *preemptor)
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 {
106   error_t operate (struct hurd_signal_preemptor *preemptor)
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
123   struct hurd_signal_preemptor src_preemptor =
124     {
125       sigmask (SIGBUS) | sigmask (SIGSEGV),
126       (vm_address_t) src, (vm_address_t) src + nbytes,
127       NULL, (sighandler_t) &throw,
128     };
129   struct hurd_signal_preemptor dest_preemptor =
130     {
131       sigmask (SIGBUS) | sigmask (SIGSEGV),
132       (vm_address_t) dest, (vm_address_t) dest + nbytes,
133       NULL, (sighandler_t) &throw,
134       &src_preemptor
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     {
145       /* Install a signal preemptor for the thread.  */
146       __spin_lock (&ss->lock);
147       src_preemptor.next = ss->preemptors;
148       ss->preemptors = &dest_preemptor;
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
157      code in ERROR.  Now we can remove the preemptor and return.  */
158
159   __spin_lock (&ss->lock);
160   assert (ss->preemptors == &dest_preemptor);
161   ss->preemptors = src_preemptor.next;
162   __spin_unlock (&ss->lock);
163
164   return error;
165 }