mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			166 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			166 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
// Copyright (C) 2012-2014 Free Software Foundation, Inc.
 | 
						|
//
 | 
						|
// This file is part of GCC.
 | 
						|
//
 | 
						|
// GCC is free software; you can redistribute it and/or modify
 | 
						|
// it under the terms of the GNU General Public License as published by
 | 
						|
// the Free Software Foundation; either version 3, or (at your option)
 | 
						|
// any later version.
 | 
						|
 | 
						|
// GCC is distributed in the hope that it will be useful,
 | 
						|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
// GNU General Public License for more details.
 | 
						|
 | 
						|
// Under Section 7 of GPL version 3, you are granted additional
 | 
						|
// permissions described in the GCC Runtime Library Exception, version
 | 
						|
// 3.1, as published by the Free Software Foundation.
 | 
						|
 | 
						|
// You should have received a copy of the GNU General Public License and
 | 
						|
// a copy of the GCC Runtime Library Exception along with this program;
 | 
						|
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 | 
						|
// <http://www.gnu.org/licenses/>.
 | 
						|
 | 
						|
#include <cxxabi.h>
 | 
						|
#include <cstdlib>
 | 
						|
#include <new>
 | 
						|
#include "bits/gthr.h"
 | 
						|
#ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
 | 
						|
#define WIN32_LEAN_AND_MEAN
 | 
						|
#include <windows.h>
 | 
						|
#endif
 | 
						|
 | 
						|
#if _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL
 | 
						|
 | 
						|
extern "C" int __cxa_thread_atexit_impl (void (*func) (void *),
 | 
						|
					 void *arg, void *d);
 | 
						|
extern "C" int
 | 
						|
__cxxabiv1::__cxa_thread_atexit (void (*dtor)(void *),
 | 
						|
				 void *obj, void *dso_handle)
 | 
						|
  _GLIBCXX_NOTHROW
 | 
						|
{
 | 
						|
  return __cxa_thread_atexit_impl (dtor, obj, dso_handle);
 | 
						|
}
 | 
						|
 | 
						|
#else /* _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL */
 | 
						|
 | 
						|
namespace {
 | 
						|
  // One element in a singly-linked stack of cleanups.
 | 
						|
  struct elt
 | 
						|
  {
 | 
						|
    void (*destructor)(void *);
 | 
						|
    void *object;
 | 
						|
    elt *next;
 | 
						|
#ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
 | 
						|
    HMODULE dll;
 | 
						|
#endif
 | 
						|
  };
 | 
						|
 | 
						|
  // Keep a per-thread list of cleanups in gthread_key storage.
 | 
						|
  __gthread_key_t key;
 | 
						|
  // But also support non-threaded mode.
 | 
						|
  elt *single_thread;
 | 
						|
 | 
						|
  // Run the specified stack of cleanups.
 | 
						|
  void run (void *p)
 | 
						|
  {
 | 
						|
    elt *e = static_cast<elt*>(p);
 | 
						|
    while (e)
 | 
						|
      {
 | 
						|
	elt *old_e = e;
 | 
						|
	e->destructor (e->object);
 | 
						|
#ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
 | 
						|
	/* Decrement DLL count */
 | 
						|
	if (e->dll)
 | 
						|
	  FreeLibrary (e->dll);
 | 
						|
#endif
 | 
						|
	e = e->next;
 | 
						|
	delete (old_e);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  // Run the stack of cleanups for the current thread.
 | 
						|
  void run ()
 | 
						|
  {
 | 
						|
    void *e;
 | 
						|
    if (__gthread_active_p ())
 | 
						|
      {
 | 
						|
	e = __gthread_getspecific (key);
 | 
						|
	__gthread_setspecific (key, NULL);
 | 
						|
      }
 | 
						|
    else
 | 
						|
      {
 | 
						|
	e = single_thread;
 | 
						|
	single_thread = NULL;
 | 
						|
      }
 | 
						|
    run (e);
 | 
						|
  }
 | 
						|
 | 
						|
  // Initialize the key for the cleanup stack.  We use a static local for
 | 
						|
  // key init/delete rather than atexit so that delete is run on dlclose.
 | 
						|
  void key_init() {
 | 
						|
    struct key_s {
 | 
						|
      key_s() { __gthread_key_create (&key, run); }
 | 
						|
      ~key_s() { __gthread_key_delete (key); }
 | 
						|
    };
 | 
						|
    static key_s ks;
 | 
						|
    // Also make sure the destructors are run by std::exit.
 | 
						|
    // FIXME TLS cleanups should run before static cleanups and atexit
 | 
						|
    // cleanups.
 | 
						|
    std::atexit (run);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
extern "C" int
 | 
						|
__cxxabiv1::__cxa_thread_atexit (void (*dtor)(void *), void *obj, void */*dso_handle*/)
 | 
						|
  _GLIBCXX_NOTHROW
 | 
						|
{
 | 
						|
  // Do this initialization once.
 | 
						|
  if (__gthread_active_p ())
 | 
						|
    {
 | 
						|
      // When threads are active use __gthread_once.
 | 
						|
      static __gthread_once_t once = __GTHREAD_ONCE_INIT;
 | 
						|
      __gthread_once (&once, key_init);
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      // And when threads aren't active use a static local guard.
 | 
						|
      static bool queued;
 | 
						|
      if (!queued)
 | 
						|
	{
 | 
						|
	  queued = true;
 | 
						|
	  std::atexit (run);
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  elt *first;
 | 
						|
  if (__gthread_active_p ())
 | 
						|
    first = static_cast<elt*>(__gthread_getspecific (key));
 | 
						|
  else
 | 
						|
    first = single_thread;
 | 
						|
 | 
						|
  elt *new_elt = new (std::nothrow) elt;
 | 
						|
  if (!new_elt)
 | 
						|
    return -1;
 | 
						|
  new_elt->destructor = dtor;
 | 
						|
  new_elt->object = obj;
 | 
						|
  new_elt->next = first;
 | 
						|
#ifdef _GLIBCXX_THREAD_ATEXIT_WIN32
 | 
						|
  /* Store the DLL address for a later call to FreeLibrary in new_elt and
 | 
						|
     increment DLL load count.  This blocks the unloading of the DLL
 | 
						|
     before the thread-local dtors have been called.  This does NOT help
 | 
						|
     if FreeLibrary/dlclose is called in excess. */
 | 
						|
  GetModuleHandleExW (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
 | 
						|
		      (LPCWSTR) dtor, &new_elt->dll);
 | 
						|
#endif
 | 
						|
 | 
						|
  if (__gthread_active_p ())
 | 
						|
    __gthread_setspecific (key, new_elt);
 | 
						|
  else
 | 
						|
    single_thread = new_elt;
 | 
						|
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
#endif /* _GLIBCXX_HAVE___CXA_THREAD_ATEXIT_IMPL */
 |