OSDN Git Service

Replace FSF snail mail address with URLs
[uclinux-h8/uClibc.git] / libpthread / nptl / sysdeps / pthread / unwind-forcedunwind.c
1 /* Copyright (C) 2003, 2005, 2006, 2009 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Jakub Jelinek <jakub@redhat.com>.
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 License as
7    published by the Free Software Foundation; either version 2.1 of the
8    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; see the file COPYING.LIB.  If
17    not, see <http://www.gnu.org/licenses/>.  */
18
19 #include <dlfcn.h>
20 #include <stdio.h>
21 #include <unwind.h>
22 #include <pthreadP.h>
23 #include <sysdep.h>
24 #include <libgcc_s.h>
25
26 #define __libc_dlopen(x)        dlopen(x, (RTLD_LOCAL | RTLD_LAZY))
27 #define __libc_dlsym            dlsym
28 #define __libc_dlclose          dlclose
29
30 static void *libgcc_s_handle;
31 static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
32 static _Unwind_Reason_Code (*libgcc_s_personality)
33   (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
34    struct _Unwind_Context *);
35 static _Unwind_Reason_Code (*libgcc_s_forcedunwind)
36   (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *);
37 static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *);
38
39 void
40 __attribute_noinline__
41 pthread_cancel_init (void)
42 {
43   void *resume;
44   void *personality;
45   void *forcedunwind;
46   void *getcfa;
47   void *handle;
48
49   if (__builtin_expect (libgcc_s_handle != NULL, 1))
50     {
51       /* Force gcc to reload all values.  */
52       __asm__ __volatile__ ("" ::: "memory");
53       return;
54     }
55
56   handle = __libc_dlopen (LIBGCC_S_SO);
57
58   if (handle == NULL
59       || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL
60       || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL
61       || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind"))
62          == NULL
63       || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL
64 #ifdef ARCH_CANCEL_INIT
65       || ARCH_CANCEL_INIT (handle)
66 #endif
67       )
68   {
69     printf (LIBGCC_S_SO " must be installed for pthread_cancel to work\n");
70     abort();
71   }
72
73   PTR_MANGLE (resume);
74   libgcc_s_resume = resume;
75   PTR_MANGLE (personality);
76   libgcc_s_personality = personality;
77   PTR_MANGLE (forcedunwind);
78   libgcc_s_forcedunwind = forcedunwind;
79   PTR_MANGLE (getcfa);
80   libgcc_s_getcfa = getcfa;
81   /* Make sure libgcc_s_handle is written last.  Otherwise,
82      pthread_cancel_init might return early even when the pointer the
83      caller is interested in is not initialized yet.  */
84   atomic_write_barrier ();
85   libgcc_s_handle = handle;
86 }
87
88 void
89 __libc_freeres_fn_section
90 __unwind_freeres (void)
91 {
92   void *handle = libgcc_s_handle;
93   if (handle != NULL)
94     {
95       libgcc_s_handle = NULL;
96       __libc_dlclose (handle);
97     }
98 }
99
100 void
101 _Unwind_Resume (struct _Unwind_Exception *exc)
102 {
103   if (__builtin_expect (libgcc_s_handle == NULL, 0))
104     pthread_cancel_init ();
105
106   void (*resume) (struct _Unwind_Exception *exc) = libgcc_s_resume;
107   PTR_DEMANGLE (resume);
108   resume (exc);
109 }
110
111 _Unwind_Reason_Code
112 __gcc_personality_v0 (int version, _Unwind_Action actions,
113                       _Unwind_Exception_Class exception_class,
114                       struct _Unwind_Exception *ue_header,
115                       struct _Unwind_Context *context);
116 _Unwind_Reason_Code
117 __gcc_personality_v0 (int version, _Unwind_Action actions,
118                       _Unwind_Exception_Class exception_class,
119                       struct _Unwind_Exception *ue_header,
120                       struct _Unwind_Context *context)
121 {
122   if (__builtin_expect (libgcc_s_handle == NULL, 0))
123     pthread_cancel_init ();
124
125   _Unwind_Reason_Code (*personality)
126     (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
127      struct _Unwind_Context *) = libgcc_s_personality;
128   PTR_DEMANGLE (personality);
129   return personality (version, actions, exception_class, ue_header, context);
130 }
131
132 _Unwind_Reason_Code
133 _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop,
134                       void *stop_argument)
135 {
136   if (__builtin_expect (libgcc_s_handle == NULL, 0))
137     pthread_cancel_init ();
138
139   _Unwind_Reason_Code (*forcedunwind)
140     (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *)
141     = libgcc_s_forcedunwind;
142   PTR_DEMANGLE (forcedunwind);
143   return forcedunwind (exc, stop, stop_argument);
144 }
145
146 _Unwind_Word
147 _Unwind_GetCFA (struct _Unwind_Context *context)
148 {
149   if (__builtin_expect (libgcc_s_handle == NULL, 0))
150     pthread_cancel_init ();
151
152   _Unwind_Word (*getcfa) (struct _Unwind_Context *) = libgcc_s_getcfa;
153   PTR_DEMANGLE (getcfa);
154   return getcfa (context);
155 }