Back to index

glibc  2.9
catch-signal.c
Go to the documentation of this file.
00001 /* Convenience function to catch expected signals during an operation.
00002    Copyright (C) 1996 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <hurd/signal.h>
00021 #include <hurd/sigpreempt.h>
00022 #include <string.h>
00023 #include <assert.h>
00024 
00025 error_t
00026 hurd_catch_signal (sigset_t sigset,
00027                  unsigned long int first, unsigned long int last,
00028                  error_t (*operate) (struct hurd_signal_preemptor *),
00029                  sighandler_t handler)
00030 {
00031   jmp_buf buf;
00032   void throw (int signo, long int sigcode, struct sigcontext *scp)
00033     { longjmp (buf, scp->sc_error ?: EGRATUITOUS); }
00034 
00035   struct hurd_signal_preemptor preemptor =
00036     {
00037       sigset, first, last,
00038       NULL, handler == SIG_ERR ? (sighandler_t) &throw : handler,
00039     };
00040 
00041   struct hurd_sigstate *const ss = _hurd_self_sigstate ();
00042   error_t error;
00043 
00044   if (handler == SIG_ERR)
00045     /* Not our handler; don't bother saving state.  */
00046     error = 0;
00047   else
00048     /* This returns again with nonzero value when we preempt a signal.  */
00049     error = setjmp (buf);
00050 
00051   if (error == 0)
00052     {
00053       /* Install a signal preemptor for the thread.  */
00054       __spin_lock (&ss->lock);
00055       preemptor.next = ss->preemptors;
00056       ss->preemptors = &preemptor;
00057       __spin_unlock (&ss->lock);
00058 
00059       /* Try the operation that might crash.  */
00060       (*operate) (&preemptor);
00061     }
00062 
00063   /* Either FUNCTION completed happily and ERROR is still zero, or it hit
00064      an expected signal and `throw' made setjmp return the signal error
00065      code in ERROR.  Now we can remove the preemptor and return.  */
00066 
00067   __spin_lock (&ss->lock);
00068   assert (ss->preemptors == &preemptor);
00069   ss->preemptors = preemptor.next;
00070   __spin_unlock (&ss->lock);
00071 
00072   return error;
00073 }
00074 
00075 
00076 error_t
00077 hurd_safe_memset (void *dest, int byte, size_t nbytes)
00078 {
00079   error_t operate (struct hurd_signal_preemptor *preemptor)
00080     {
00081       memset (dest, byte, nbytes);
00082       return 0;
00083     }
00084   return hurd_catch_signal (sigmask (SIGBUS) | sigmask (SIGSEGV),
00085                          (vm_address_t) dest, (vm_address_t) dest + nbytes,
00086                          &operate, SIG_ERR);
00087 }
00088 
00089 
00090 error_t
00091 hurd_safe_copyout (void *dest, const void *src, size_t nbytes)
00092 {
00093   error_t operate (struct hurd_signal_preemptor *preemptor)
00094     {
00095       memcpy (dest, src, nbytes);
00096       return 0;
00097     }
00098   return hurd_catch_signal (sigmask (SIGBUS) | sigmask (SIGSEGV),
00099                          (vm_address_t) dest, (vm_address_t) dest + nbytes,
00100                          &operate, SIG_ERR);
00101 }
00102 
00103 error_t
00104 hurd_safe_copyin (void *dest, const void *src, size_t nbytes)
00105 {
00106   error_t operate (struct hurd_signal_preemptor *preemptor)
00107     {
00108       memcpy (dest, src, nbytes);
00109       return 0;
00110     }
00111   return hurd_catch_signal (sigmask (SIGBUS) | sigmask (SIGSEGV),
00112                          (vm_address_t) src, (vm_address_t) src + nbytes,
00113                          &operate, SIG_ERR);
00114 }
00115 
00116 error_t
00117 hurd_safe_memmove (void *dest, const void *src, size_t nbytes)
00118 {
00119   jmp_buf buf;
00120   void throw (int signo, long int sigcode, struct sigcontext *scp)
00121     { longjmp (buf, scp->sc_error ?: EGRATUITOUS); }
00122 
00123   struct hurd_signal_preemptor src_preemptor =
00124     {
00125       sigmask (SIGBUS) | sigmask (SIGSEGV),
00126       (vm_address_t) src, (vm_address_t) src + nbytes,
00127       NULL, (sighandler_t) &throw,
00128     };
00129   struct hurd_signal_preemptor dest_preemptor =
00130     {
00131       sigmask (SIGBUS) | sigmask (SIGSEGV),
00132       (vm_address_t) dest, (vm_address_t) dest + nbytes,
00133       NULL, (sighandler_t) &throw,
00134       &src_preemptor
00135     };
00136 
00137   struct hurd_sigstate *const ss = _hurd_self_sigstate ();
00138   error_t error;
00139 
00140   /* This returns again with nonzero value when we preempt a signal.  */
00141   error = setjmp (buf);
00142 
00143   if (error == 0)
00144     {
00145       /* Install a signal preemptor for the thread.  */
00146       __spin_lock (&ss->lock);
00147       src_preemptor.next = ss->preemptors;
00148       ss->preemptors = &dest_preemptor;
00149       __spin_unlock (&ss->lock);
00150 
00151       /* Do the copy; it might fault.  */
00152       memmove (dest, src, nbytes);
00153     }
00154 
00155   /* Either memmove completed happily and ERROR is still zero, or it hit
00156      an expected signal and `throw' made setjmp return the signal error
00157      code in ERROR.  Now we can remove the preemptor and return.  */
00158 
00159   __spin_lock (&ss->lock);
00160   assert (ss->preemptors == &dest_preemptor);
00161   ss->preemptors = src_preemptor.next;
00162   __spin_unlock (&ss->lock);
00163 
00164   return error;
00165 }