1 /* _longjmp_unwind -- Clean up stack frames unwound by longjmp.  Hurd version.
2    Copyright (C) 1995-2022 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, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <jmpbuf-unwind.h>
20 #include <hurd/userlink.h>
21 #include <hurd/signal.h>
22 #include <hurd/sigpreempt.h>
23 #include <assert.h>
24 #include <stdint.h>
25 
26 
27 #ifndef _JMPBUF_UNWINDS
28 #error "<jmpbuf-unwind.h> fails to define _JMPBUF_UNWINDS"
29 #endif
30 
31 static inline uintptr_t
demangle_ptr(uintptr_t x)32 demangle_ptr (uintptr_t x)
33 {
34 # ifdef PTR_DEMANGLE
35   PTR_DEMANGLE (x);
36 # endif
37   return x;
38 }
39 
40 /* This function is called by `longjmp' (with its arguments) to restore
41    active resources to a sane state before the frames code using them are
42    jumped out of.  */
43 
44 void
_longjmp_unwind(jmp_buf env,int val)45 _longjmp_unwind (jmp_buf env, int val)
46 {
47   struct hurd_sigstate *ss = _hurd_self_sigstate ();
48   struct hurd_userlink *link;
49 
50   /* All access to SS->active_resources must take place inside a critical
51      section where signal handlers cannot run.  */
52   __spin_lock (&ss->lock);
53   assert (! __spin_lock_locked (&ss->critical_section_lock));
54   __spin_lock (&ss->critical_section_lock);
55 
56   /* Remove local signal preemptors being unwound past.  */
57   while (ss->preemptors
58 	 && _JMPBUF_UNWINDS (env[0].__jmpbuf, ss->preemptors, demangle_ptr))
59     ss->preemptors = ss->preemptors->next;
60 
61   __spin_unlock (&ss->lock);
62 
63   /* Iterate over the current thread's list of active resources.
64      Process the head portion of the list whose links reside
65      in stack frames being unwound by this jump.  */
66 
67   for (link = ss->active_resources;
68        link && _JMPBUF_UNWINDS (env[0].__jmpbuf, link, demangle_ptr);
69        link = link->thread.next)
70     /* Remove this link from the resource's users list,
71        since the frame using the resource is being unwound.
72        This call returns nonzero if that was the last user.  */
73     if (_hurd_userlink_unlink (link))
74       /* One of the frames being unwound by the longjmp was the last user
75 	 of its resource.  Call the cleanup function to deallocate it.  */
76       (*link->cleanup) (link->cleanup_data, env, val);
77 
78   _hurd_critical_section_unlock (ss);
79 }
80