Back to index

glibc  2.9
unwind-forcedunwind.c
Go to the documentation of this file.
00001 /* Copyright (C) 2005, 2006 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 License as
00006    published by the Free Software Foundation; either version 2.1 of the
00007    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; see the file COPYING.LIB.  If not,
00016    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017    Boston, MA 02111-1307, USA.  */
00018 
00019 #include <dlfcn.h>
00020 #include <stdio.h>
00021 #include <unwind.h>
00022 #include <pthreadP.h>
00023 
00024 #define LIBGCC_S_SO "libgcc_s.so.4"
00025 
00026 static void (*libgcc_s_resume) (struct _Unwind_Exception *exc);
00027 static _Unwind_Reason_Code (*libgcc_s_personality)
00028   (int, _Unwind_Action, _Unwind_Exception_Class, struct _Unwind_Exception *,
00029    struct _Unwind_Context *);
00030 static _Unwind_Reason_Code (*libgcc_s_forcedunwind)
00031   (struct _Unwind_Exception *, _Unwind_Stop_Fn, void *);
00032 static _Unwind_Word (*libgcc_s_getcfa) (struct _Unwind_Context *);
00033 
00034 #ifndef LIBGCC_S_SO
00035 #define LIBGCC_S_SO "libgcc_s.so.1"
00036 #endif
00037 
00038 void
00039 __attribute_noinline__
00040 pthread_cancel_init (void)
00041 {
00042   void *resume, *personality, *forcedunwind, *getcfa;
00043   void *handle;
00044 
00045   if (__builtin_expect (libgcc_s_getcfa != NULL, 1))
00046     {
00047       /* Force gcc to reload all values.  */
00048       asm volatile ("" ::: "memory");
00049       return;
00050     }
00051 
00052   handle = __libc_dlopen (LIBGCC_S_SO);
00053 
00054   if (handle == NULL
00055       || (resume = __libc_dlsym (handle, "_Unwind_Resume")) == NULL
00056       || (personality = __libc_dlsym (handle, "__gcc_personality_v0")) == NULL
00057       || (forcedunwind = __libc_dlsym (handle, "_Unwind_ForcedUnwind"))
00058         == NULL
00059       || (getcfa = __libc_dlsym (handle, "_Unwind_GetCFA")) == NULL
00060 #ifdef ARCH_CANCEL_INIT
00061       || ARCH_CANCEL_INIT (handle)
00062 #endif
00063       )
00064     __libc_fatal ("libgcc_s.so must be installed for pthread_cancel to work\n");
00065 
00066   libgcc_s_resume = resume;
00067   libgcc_s_personality = personality;
00068   libgcc_s_forcedunwind = forcedunwind;
00069   /* Make sure libgcc_s_getcfa is written last.  Otherwise,
00070      pthread_cancel_init might return early even when the pointer the
00071      caller is interested in is not initialized yet.  */
00072   atomic_write_barrier ();
00073   libgcc_s_getcfa = getcfa;
00074 }
00075 
00076 void
00077 _Unwind_Resume (struct _Unwind_Exception *exc)
00078 {
00079   if (__builtin_expect (libgcc_s_resume == NULL, 0))
00080     pthread_cancel_init ();
00081 
00082   libgcc_s_resume (exc);
00083 }
00084 
00085 _Unwind_Reason_Code
00086 __gcc_personality_v0 (int version, _Unwind_Action actions,
00087                     _Unwind_Exception_Class exception_class,
00088                       struct _Unwind_Exception *ue_header,
00089                       struct _Unwind_Context *context)
00090 {
00091   if (__builtin_expect (libgcc_s_personality == NULL, 0))
00092     pthread_cancel_init ();
00093 
00094   return libgcc_s_personality (version, actions, exception_class,
00095                             ue_header, context);
00096 }
00097 
00098 _Unwind_Reason_Code
00099 _Unwind_ForcedUnwind (struct _Unwind_Exception *exc, _Unwind_Stop_Fn stop,
00100                     void *stop_argument)
00101 {
00102   if (__builtin_expect (libgcc_s_forcedunwind == NULL, 0))
00103     pthread_cancel_init ();
00104 
00105   return libgcc_s_forcedunwind (exc, stop, stop_argument);
00106 }
00107 
00108 _Unwind_Word
00109 _Unwind_GetCFA (struct _Unwind_Context *context)
00110 {
00111   if (__builtin_expect (libgcc_s_getcfa == NULL, 0))
00112     pthread_cancel_init ();
00113 
00114   return libgcc_s_getcfa (context);
00115 }