(linenum→info "unix/slp.c:2238")

glibc/2.7/hurd/sigunwind.c

    1: /* longjmp cleanup function for unwinding past signal handlers.
    2:    Copyright (C) 1995,1996,1997,1998,2005,2006 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.h>
   21: #include <thread_state.h>
   22: #include <jmpbuf-unwind.h>
   23: #include <assert.h>
   24: #include <stdint.h>
   25: 
   26: 
   27: /* _hurd_setup_sighandler puts a link on the `active resources' chain so that
   28:    _longjmp_unwind will call this function with the `struct sigcontext *'
   29:    describing the context interrupted by the signal, when `longjmp' is jumping
   30:    to an environment that unwinds past the interrupted frame.  */
   31: 
   32: void
   33: _hurdsig_longjmp_from_handler (void *data, jmp_buf env, int val)
   34: {
   35:   struct sigcontext *scp = data;
   36:   struct hurd_sigstate *ss = _hurd_self_sigstate ();
   37:   int onstack;
   38:   inline void cleanup (void)
   39:     {
   40:       /* Destroy the MiG reply port used by the signal handler, and restore
   41:          the reply port in use by the thread when interrupted.  */
   42:       mach_port_t *reply_port =
   43:         (mach_port_t *) __hurd_threadvar_location (_HURD_THREADVAR_MIG_REPLY);
   44:       if (*reply_port)
   45:         {
   46:           mach_port_t port = *reply_port;
   47:           /* Assigning MACH_PORT_DEAD here tells libc's mig_get_reply_port
   48:              not to get another reply port, but avoids mig_dealloc_reply_port
   49:              trying to deallocate it after the receive fails (which it will,
   50:              because the reply port will be bogus, regardless).  */
   51:           *reply_port = MACH_PORT_DEAD;
   52:           __mach_port_destroy (__mach_task_self (), port);
   53:         }
   54:       *reply_port = scp->sc_reply_port;
   55:     }
   56: 
   57:   __spin_lock (&ss->lock);
   58:   /* We should only ever be called from _longjmp_unwind (in jmp-unwind.c),
   59:      which calls us inside a critical section.  */
   60:   assert (__spin_lock_locked (&ss->critical_section_lock));
   61:   /* Are we on the alternate signal stack now?  */
   62:   onstack = (ss->sigaltstack.ss_flags & SS_ONSTACK);
   63:   __spin_unlock (&ss->lock);
   64: 
   65:   if (onstack && ! scp->sc_onstack)
   66:     {
   67:       /* We are unwinding off the signal stack.  We must use sigreturn to
   68:          do it robustly.  Mutate the sigcontext so that when sigreturn
   69:          resumes from that context, it will be as if `__longjmp (ENV, VAL)'
   70:          were done.  */
   71: 
   72:       struct hurd_userlink *link;
   73: 
   74:       inline uintptr_t demangle_ptr (uintptr_t x)
   75:         {
   76: # ifdef PTR_DEMANGLE
   77:           PTR_DEMANGLE (x);
   78: # endif
   79:           return x;
   80:         }
   81: 
   82:       /* Continue _longjmp_unwind's job of running the unwind
   83:          forms for frames being unwound, since we will not
   84:          return to its loop like this one, which called us.  */
   85:       for (link = ss->active_resources;
   86:            link && _JMPBUF_UNWINDS (env[0].__jmpbuf, link, demangle_ptr);
   87:            link = link->thread.next)
   88:         if (_hurd_userlink_unlink (link))
   89:           {
   90:             if (link->cleanup == &_hurdsig_longjmp_from_handler)
   91:               {
   92:                 /* We are unwinding past another signal handler invocation.
   93:                    Just finish the cleanup for this (inner) one, and then
   94:                    swap SCP to restore to the outer context.  */
   95:                 cleanup ();
   96:                 scp = link->cleanup_data;
   97:               }
   98:             else
   99:               (*link->cleanup) (link->cleanup_data, env, val);
  100:           }
  101: 
  102: #define sc_machine_thread_state paste(sc_,machine_thread_state)
  103: #define paste(a,b)      paste1(a,b)
  104: #define paste1(a,b)     a##b
  105: 
  106:       /* There are no more unwind forms to be run!
  107:          Now we can just have the sigreturn do the longjmp for us.  */
  108:       _hurd_longjmp_thread_state
  109:         ((struct machine_thread_state *) &scp->sc_machine_thread_state,
  110:          env, val);
  111: 
  112:       /* Restore to the same current signal mask.  If sigsetjmp saved the
  113:          mask, longjmp has already restored it as desired; if not, we
  114:          should leave it as it is.  */
  115:       scp->sc_mask = ss->blocked;
  116: 
  117:       /* sigreturn expects the link added by _hurd_setup_sighandler
  118:          to still be there, but _longjmp_unwind removed it just before
  119:          calling us.  Put it back now so sigreturn can find it.  */
  120:       link = (void *) &scp[1];
  121:       assert (! link->resource.next && ! link->resource.prevp);
  122:       assert (link->thread.next == ss->active_resources);
  123:       assert (link->thread.prevp == &ss->active_resources);
  124:       if (link->thread.next)
  125:         link->thread.next->thread.prevp = &link->thread.next;
  126:       ss->active_resources = link;
  127: 
  128:       /* We must momentarily exit the critical section so that sigreturn
  129:          does not get upset with us.  But we don't want signal handlers
  130:          running right now, because we are presently in the bogus state of
  131:          having run all the unwind forms back to ENV's frame, but our SP is
  132:          still inside those unwound frames.  */
  133:       __spin_lock (&ss->lock);
  134:       __spin_unlock (&ss->critical_section_lock);
  135:       ss->blocked = ~(sigset_t) 0 & ~_SIG_CANT_MASK;
  136:       __spin_unlock (&ss->lock);
  137: 
  138:       /* Restore to the modified signal context that now
  139:          performs `longjmp (ENV, VAL)'.  */
  140:       __sigreturn (scp);
  141:       assert (! "sigreturn returned!");
  142:     }
  143: 
  144:   /* We are not unwinding off the alternate signal stack.  So nothing
  145:      really funny is going on here.  We can just clean up this handler
  146:      frame and let _longjmp_unwind continue unwinding.  */
  147:   cleanup ();
  148:   ss->intr_port = scp->sc_intr_port;
  149: }
Syntax (Markdown)