Blame sysdeps/mach/hurd/jmp-unwind.c

Packit 6c4009
/* _longjmp_unwind -- Clean up stack frames unwound by longjmp.  Hurd version.
Packit 6c4009
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <jmpbuf-unwind.h>
Packit 6c4009
#include <hurd/userlink.h>
Packit 6c4009
#include <hurd/signal.h>
Packit 6c4009
#include <hurd/sigpreempt.h>
Packit 6c4009
#include <assert.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifndef _JMPBUF_UNWINDS
Packit 6c4009
#error "<jmpbuf-unwind.h> fails to define _JMPBUF_UNWINDS"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
static inline uintptr_t
Packit 6c4009
demangle_ptr (uintptr_t x)
Packit 6c4009
{
Packit 6c4009
# ifdef PTR_DEMANGLE
Packit 6c4009
  PTR_DEMANGLE (x);
Packit 6c4009
# endif
Packit 6c4009
  return x;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* This function is called by `longjmp' (with its arguments) to restore
Packit 6c4009
   active resources to a sane state before the frames code using them are
Packit 6c4009
   jumped out of.  */
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_longjmp_unwind (jmp_buf env, int val)
Packit 6c4009
{
Packit 6c4009
  struct hurd_sigstate *ss = _hurd_self_sigstate ();
Packit 6c4009
  struct hurd_userlink *link;
Packit 6c4009
Packit 6c4009
  /* All access to SS->active_resources must take place inside a critical
Packit 6c4009
     section where signal handlers cannot run.  */
Packit 6c4009
  __spin_lock (&ss->lock);
Packit 6c4009
  assert (! __spin_lock_locked (&ss->critical_section_lock));
Packit 6c4009
  __spin_lock (&ss->critical_section_lock);
Packit 6c4009
Packit 6c4009
  /* Remove local signal preemptors being unwound past.  */
Packit 6c4009
  while (ss->preemptors &&
Packit 6c4009
	 _JMPBUF_UNWINDS (env[0].__jmpbuf, ss->preemptors, demangle_ptr))
Packit 6c4009
    ss->preemptors = ss->preemptors->next;
Packit 6c4009
Packit 6c4009
  __spin_unlock (&ss->lock);
Packit 6c4009
Packit 6c4009
  /* Iterate over the current thread's list of active resources.
Packit 6c4009
     Process the head portion of the list whose links reside
Packit 6c4009
     in stack frames being unwound by this jump.  */
Packit 6c4009
Packit 6c4009
  for (link = ss->active_resources;
Packit 6c4009
       link && _JMPBUF_UNWINDS (env[0].__jmpbuf, link, demangle_ptr);
Packit 6c4009
       link = link->thread.next)
Packit 6c4009
    /* Remove this link from the resource's users list,
Packit 6c4009
       since the frame using the resource is being unwound.
Packit 6c4009
       This call returns nonzero if that was the last user.  */
Packit 6c4009
    if (_hurd_userlink_unlink (link))
Packit 6c4009
      /* One of the frames being unwound by the longjmp was the last user
Packit 6c4009
	 of its resource.  Call the cleanup function to deallocate it.  */
Packit 6c4009
      (*link->cleanup) (link->cleanup_data, env, val);
Packit 6c4009
Packit 6c4009
  _hurd_critical_section_unlock (ss);
Packit 6c4009
}