Back to index

glibc  2.9
sigreturn.c
Go to the documentation of this file.
00001 /* Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <hurd.h>
00020 #include <hurd/signal.h>
00021 #include <hurd/threadvar.h>
00022 #include <stdlib.h>
00023 #include <mach/mips/mips_instruction.h>
00024 
00025 int
00026 __sigreturn (struct sigcontext *scp)
00027 {
00028   struct hurd_sigstate *ss;
00029   struct hurd_userlink *link = (void *) &scp[1];
00030   mach_port_t *reply_port;
00031 
00032   if (scp == NULL || (scp->sc_mask & _SIG_CANT_MASK))
00033     {
00034       errno = EINVAL;
00035       return -1;
00036     }
00037 
00038   ss = _hurd_self_sigstate ();
00039   __spin_lock (&ss->lock);
00040 
00041   /* Remove the link on the `active resources' chain added by
00042      _hurd_setup_sighandler.  Its purpose was to make sure
00043      that we got called; now we have, it is done.  */
00044   _hurd_userlink_unlink (link);
00045 
00046   /* Restore the set of blocked signals, and the intr_port slot.  */
00047   ss->blocked = scp->sc_mask;
00048   ss->intr_port = scp->sc_intr_port;
00049 
00050   /* Check for pending signals that were blocked by the old set.  */
00051   if (ss->pending & ~ss->blocked)
00052     {
00053       /* There are pending signals that just became unblocked.  Wake up the
00054         signal thread to deliver them.  But first, squirrel away SCP where
00055         the signal thread will notice it if it runs another handler, and
00056         arrange to have us called over again in the new reality.  */
00057       ss->context = scp;
00058       __spin_unlock (&ss->lock);
00059       __msg_sig_post (_hurd_msgport, 0, 0, __mach_task_self ());
00060       /* If a pending signal was handled, sig_post never returned.  */
00061       __spin_lock (&ss->lock);
00062       ss->context = NULL;
00063     }
00064 
00065   if (scp->sc_onstack)
00066     {
00067       ss->sigaltstack.ss_flags &= ~SS_ONSTACK; /* XXX threadvars */
00068       /* XXX cannot unlock until off sigstack */
00069       abort ();
00070     }
00071   else
00072     __spin_unlock (&ss->lock);
00073 
00074   /* Destroy the MiG reply port used by the signal handler, and restore the
00075      reply port in use by the thread when interrupted.  */
00076   reply_port =
00077     (mach_port_t *) __hurd_threadvar_location (_HURD_THREADVAR_MIG_REPLY);
00078   if (*reply_port)
00079     {
00080       mach_port_t port = *reply_port;
00081 
00082       /* Assigning MACH_PORT_DEAD here tells libc's mig_get_reply_port not to
00083         get another reply port, but avoids mig_dealloc_reply_port trying to
00084         deallocate it after the receive fails (which it will, because the
00085         reply port will be bogus, whether we do this or not).  */
00086       *reply_port = MACH_PORT_DEAD;
00087 
00088       __mach_port_destroy (__mach_task_self (), port);
00089     }
00090   *reply_port = scp->sc_reply_port;
00091 
00092   if (scp->sc_coproc_used & SC_COPROC_USE_FPU)
00093     {
00094       /* Restore FPU state.  */
00095 #define restore_fpr(n) \
00096   asm volatile ("l.d $f" #n ",%0" : : "m" (scp->sc_fpr[n]))
00097 
00098       /* Restore floating-point registers. */
00099 #ifdef __mips64
00100       restore_fpr (0);
00101       restore_fpr (1);
00102       restore_fpr (2);
00103       restore_fpr (3);
00104       restore_fpr (4);
00105       restore_fpr (5);
00106       restore_fpr (6);
00107       restore_fpr (7);
00108       restore_fpr (8);
00109       restore_fpr (9);
00110       restore_fpr (10);
00111       restore_fpr (11);
00112       restore_fpr (12);
00113       restore_fpr (13);
00114       restore_fpr (14);
00115       restore_fpr (15);
00116       restore_fpr (16);
00117       restore_fpr (17);
00118       restore_fpr (18);
00119       restore_fpr (19);
00120       restore_fpr (20);
00121       restore_fpr (21);
00122       restore_fpr (22);
00123       restore_fpr (23);
00124       restore_fpr (24);
00125       restore_fpr (25);
00126       restore_fpr (26);
00127       restore_fpr (27);
00128       restore_fpr (28);
00129       restore_fpr (29);
00130       restore_fpr (30);
00131       restore_fpr (31);
00132 #else
00133       restore_fpr (0);
00134       restore_fpr (2);
00135       restore_fpr (4);
00136       restore_fpr (6);
00137       restore_fpr (8);
00138       restore_fpr (10);
00139       restore_fpr (12);
00140       restore_fpr (14);
00141       restore_fpr (16);
00142       restore_fpr (18);
00143       restore_fpr (20);
00144       restore_fpr (22);
00145       restore_fpr (24);
00146       restore_fpr (26);
00147       restore_fpr (28);
00148       restore_fpr (30);
00149 #endif
00150 
00151       /* Restore the floating-point control/status register ($f31).  */
00152       asm volatile ("ctc1 %0,$f31" : : "r" (scp->sc_fpcsr));
00153     }
00154 
00155   /* Load all the registers from the sigcontext.  */
00156 #ifdef __mips64
00157 #define restore_gpr(n) \
00158   asm volatile ("ld $" #n ",%0" : : "m" (scpreg->sc_gpr[n - 1]))
00159 #else
00160 #define restore_gpr(n) \
00161   asm volatile ("lw $" #n ",%0" : : "m" (scpreg->sc_gpr[n - 1]))
00162 #endif
00163 
00164   {
00165     register const struct sigcontext *const scpreg asm ("$1") = scp;
00166     register int *at asm ("$1");
00167 
00168     /* First restore the multiplication result registers.  The compiler
00169        will use some temporary registers, so we do this before restoring
00170        the general registers.  */
00171     asm volatile ("mtlo %0" : : "r" (scpreg->sc_mdlo));
00172     asm volatile ("mthi %0" : : "r" (scpreg->sc_mdhi));
00173 
00174     /* In the word after the saved PC, store the saved $1 value.  */
00175     (&scpreg->sc_pc)[1] = scpreg->sc_gpr[0];
00176 
00177     asm volatile (".set noreorder; .set noat;");
00178 
00179     /* Restore the normal registers.  */
00180     restore_gpr (2);
00181     restore_gpr (3);
00182     restore_gpr (4);
00183     restore_gpr (5);
00184     restore_gpr (6);
00185     restore_gpr (7);
00186     restore_gpr (8);
00187     restore_gpr (9);
00188     restore_gpr (10);
00189     restore_gpr (11);
00190     restore_gpr (12);
00191     restore_gpr (13);
00192     restore_gpr (14);
00193     restore_gpr (15);
00194     restore_gpr (16);
00195     restore_gpr (17);
00196     restore_gpr (18);
00197     restore_gpr (19);
00198     restore_gpr (20);
00199     restore_gpr (21);
00200     restore_gpr (22);
00201     restore_gpr (23);
00202     restore_gpr (24);
00203     restore_gpr (25);
00204     /* Registers 26-27 are kernel-only.  */
00205     restore_gpr (28);
00206     restore_gpr (29);              /* Stack pointer.  */
00207     restore_gpr (30);              /* Frame pointer.  */
00208     restore_gpr (31);              /* Return address.  */
00209 
00210     at = &scpreg->sc_pc;
00211     /* This is an emulated instruction that will find at the address in $1
00212        two words: the PC value to restore, and the $1 value to restore.  */
00213     asm volatile (".word %0" : : "i" (op_sigreturn));
00214     asm volatile (".set reorder; .set at;");
00215     /* NOTREACHED */
00216     return at;              /* To prevent optimization.  */
00217   }
00218 
00219   /* NOTREACHED */
00220   return -1;
00221 }
00222 
00223 weak_alias (__sigreturn, sigreturn)