Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5134 serge 1
// Copyright (C) 2012-2013 Free Software Foundation, Inc.
2
//
3
// This file is part of GCC.
4
//
5
// GCC is free software; you can redistribute it and/or modify
6
// it under the terms of the GNU General Public License as published by
7
// the Free Software Foundation; either version 3, or (at your option)
8
// any later version.
9
 
10
// GCC 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
13
// GNU General Public License for more details.
14
 
15
// Under Section 7 of GPL version 3, you are granted additional
16
// permissions described in the GCC Runtime Library Exception, version
17
// 3.1, as published by the Free Software Foundation.
18
 
19
// You should have received a copy of the GNU General Public License and
20
// a copy of the GCC Runtime Library Exception along with this program;
21
// see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
22
// .
23
 
24
#include 
25
#include 
26
#include 
27
#include "bits/gthr.h"
28
 
29
#if HAVE___CXA_THREAD_ATEXIT_IMPL
30
 
31
extern "C" int __cxa_thread_atexit_impl (void (*func) (void *),
32
					 void *arg, void *d);
33
extern "C" int
34
__cxxabiv1::__cxa_thread_atexit (void (*dtor)(void *),
35
				 void *obj, void *dso_handle)
36
  _GLIBCXX_NOTHROW
37
{
38
  return __cxa_thread_atexit_impl (dtor, obj, dso_handle);
39
}
40
 
41
#else /* HAVE___CXA_THREAD_ATEXIT_IMPL */
42
 
43
namespace {
44
  // One element in a singly-linked stack of cleanups.
45
  struct elt
46
  {
47
    void (*destructor)(void *);
48
    void *object;
49
    elt *next;
50
  };
51
 
52
  // Keep a per-thread list of cleanups in gthread_key storage.
53
  __gthread_key_t key;
54
  // But also support non-threaded mode.
55
  elt *single_thread;
56
 
57
  // Run the specified stack of cleanups.
58
  void run (void *p)
59
  {
60
    elt *e = static_cast(p);
61
    while (e)
62
      {
63
	elt *old_e = e;
64
	e->destructor (e->object);
65
	e = e->next;
66
	delete (old_e);
67
      }
68
  }
69
 
70
  // Run the stack of cleanups for the current thread.
71
  void run ()
72
  {
73
    void *e;
74
    if (__gthread_active_p ())
75
      {
76
	e = __gthread_getspecific (key);
77
	__gthread_setspecific (key, NULL);
78
      }
79
    else
80
      {
81
	e = single_thread;
82
	single_thread = NULL;
83
      }
84
    run (e);
85
  }
86
 
87
  // Initialize the key for the cleanup stack.  We use a static local for
88
  // key init/delete rather than atexit so that delete is run on dlclose.
89
  void key_init() {
90
    struct key_s {
91
      key_s() { __gthread_key_create (&key, run); }
92
      ~key_s() { __gthread_key_delete (key); }
93
    };
94
    static key_s ks;
95
    // Also make sure the destructors are run by std::exit.
96
    // FIXME TLS cleanups should run before static cleanups and atexit
97
    // cleanups.
98
    std::atexit (run);
99
  }
100
}
101
 
102
extern "C" int
103
__cxxabiv1::__cxa_thread_atexit (void (*dtor)(void *), void *obj, void */*dso_handle*/)
104
  _GLIBCXX_NOTHROW
105
{
106
  // Do this initialization once.
107
  if (__gthread_active_p ())
108
    {
109
      // When threads are active use __gthread_once.
110
      static __gthread_once_t once = __GTHREAD_ONCE_INIT;
111
      __gthread_once (&once, key_init);
112
    }
113
  else
114
    {
115
      // And when threads aren't active use a static local guard.
116
      static bool queued;
117
      if (!queued)
118
	{
119
	  queued = true;
120
	  std::atexit (run);
121
	}
122
    }
123
 
124
  elt *first;
125
  if (__gthread_active_p ())
126
    first = static_cast(__gthread_getspecific (key));
127
  else
128
    first = single_thread;
129
 
130
  elt *new_elt = new (std::nothrow) elt;
131
  if (!new_elt)
132
    return -1;
133
  new_elt->destructor = dtor;
134
  new_elt->object = obj;
135
  new_elt->next = first;
136
 
137
  if (__gthread_active_p ())
138
    __gthread_setspecific (key, new_elt);
139
  else
140
    single_thread = new_elt;
141
 
142
  return 0;
143
}
144
 
145
#endif /* HAVE___CXA_THREAD_ATEXIT_IMPL */