Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/thread/src/tss.cpp @ 45

Last change on this file since 45 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 6.4 KB
Line 
1// Copyright (C) 2001-2003 William E. Kempf
2// Copyright (C) 2006 Roland Schwarz
3//
4//  Distributed under the Boost Software License, Version 1.0. (See accompanying
5//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6
7#include <boost/thread/detail/config.hpp>
8
9#include <boost/thread/tss.hpp>
10#ifndef BOOST_THREAD_NO_TSS_CLEANUP
11
12#include <boost/thread/once.hpp>
13#include <boost/thread/mutex.hpp>
14#include <boost/thread/exceptions.hpp>
15#include <vector>
16#include <string>
17#include <stdexcept>
18#include <cassert>
19
20#if defined(BOOST_HAS_WINTHREADS)
21#   include <windows.h>
22#   include <boost/thread/detail/tss_hooks.hpp>
23#endif
24
25namespace {
26
27typedef std::vector<void*> tss_slots;
28typedef std::vector<boost::function1<void, void*>*> tss_data_cleanup_handlers_type;
29
30boost::once_flag tss_data_once = BOOST_ONCE_INIT;
31boost::mutex* tss_data_mutex = 0;
32tss_data_cleanup_handlers_type* tss_data_cleanup_handlers = 0;
33#if defined(BOOST_HAS_WINTHREADS)
34    DWORD tss_data_native_key=TLS_OUT_OF_INDEXES;
35#elif defined(BOOST_HAS_PTHREADS)
36    pthread_key_t tss_data_native_key;
37#elif defined(BOOST_HAS_MPTASKS)
38    TaskStorageIndex tss_data_native_key;
39#endif
40int tss_data_use = 0;
41
42void tss_data_inc_use(boost::mutex::scoped_lock& lk)
43{
44    ++tss_data_use;
45}
46
47void tss_data_dec_use(boost::mutex::scoped_lock& lk)
48{
49    if (0 == --tss_data_use)
50    {
51        tss_data_cleanup_handlers_type::size_type i;
52        for (i = 0; i < tss_data_cleanup_handlers->size(); ++i)
53        {
54            delete (*tss_data_cleanup_handlers)[i];
55        }
56        delete tss_data_cleanup_handlers;
57        tss_data_cleanup_handlers = 0;
58        lk.unlock();
59        delete tss_data_mutex;
60        tss_data_mutex = 0;
61#if defined(BOOST_HAS_WINTHREADS)
62        TlsFree(tss_data_native_key);
63        tss_data_native_key=TLS_OUT_OF_INDEXES;
64#elif defined(BOOST_HAS_PTHREADS)
65        pthread_key_delete(tss_data_native_key);
66#elif defined(BOOST_HAS_MPTASKS)
67        // Don't know what to put here.
68        // But MPTASKS isn't currently maintained anyways...
69#endif
70    }
71}
72
73extern "C" void cleanup_slots(void* p)
74{
75    tss_slots* slots = static_cast<tss_slots*>(p);
76    boost::mutex::scoped_lock lock(*tss_data_mutex);
77    for (tss_slots::size_type i = 0; i < slots->size(); ++i)
78    {
79        (*(*tss_data_cleanup_handlers)[i])((*slots)[i]);
80        (*slots)[i] = 0;
81    }
82#if defined(BOOST_HAS_WINTHREADS)
83    TlsSetValue(tss_data_native_key,0);
84#endif
85    tss_data_dec_use(lock);
86    delete slots;
87}
88
89void init_tss_data()
90{
91    std::auto_ptr<tss_data_cleanup_handlers_type> 
92        temp(new tss_data_cleanup_handlers_type);
93
94    std::auto_ptr<boost::mutex> temp_mutex(new boost::mutex);
95    if (temp_mutex.get() == 0)
96        throw boost::thread_resource_error();
97
98#if defined(BOOST_HAS_WINTHREADS)
99    //Force the cleanup implementation library to be linked in
100    tss_cleanup_implemented();
101
102    //Allocate tls slot
103    tss_data_native_key = TlsAlloc();
104    if (tss_data_native_key == TLS_OUT_OF_INDEXES)
105        return;
106#elif defined(BOOST_HAS_PTHREADS)
107    int res = pthread_key_create(&tss_data_native_key, &cleanup_slots);
108    if (res != 0)
109        return;
110#elif defined(BOOST_HAS_MPTASKS)
111    OSStatus status = MPAllocateTaskStorageIndex(&tss_data_native_key);
112    if (status != noErr)
113        return;
114#endif
115
116    // The life time of cleanup handlers and mutex is beeing
117    // managed by a reference counting technique.
118    // This avoids a memory leak by releasing the global data
119    // after last use only, since the execution order of cleanup
120    // handlers is unspecified on any platform with regards to
121    // C++ destructor ordering rules.
122    tss_data_cleanup_handlers = temp.release();
123    tss_data_mutex = temp_mutex.release();
124}
125
126#if defined(BOOST_HAS_WINTHREADS)
127tss_slots* get_slots(bool alloc);
128
129void __cdecl tss_thread_exit()
130{
131    tss_slots* slots = get_slots(false);
132    if (slots)
133        cleanup_slots(slots);
134}
135#endif
136
137tss_slots* get_slots(bool alloc)
138{
139    tss_slots* slots = 0;
140
141#if defined(BOOST_HAS_WINTHREADS)
142    slots = static_cast<tss_slots*>(
143        TlsGetValue(tss_data_native_key));
144#elif defined(BOOST_HAS_PTHREADS)
145    slots = static_cast<tss_slots*>(
146        pthread_getspecific(tss_data_native_key));
147#elif defined(BOOST_HAS_MPTASKS)
148    slots = static_cast<tss_slots*>(
149        MPGetTaskStorageValue(tss_data_native_key));
150#endif
151
152    if (slots == 0 && alloc)
153    {
154        std::auto_ptr<tss_slots> temp(new tss_slots);
155
156#if defined(BOOST_HAS_WINTHREADS)
157        if (at_thread_exit(&tss_thread_exit) == -1)
158            return 0;
159        if (!TlsSetValue(tss_data_native_key, temp.get()))
160            return 0;
161#elif defined(BOOST_HAS_PTHREADS)
162        if (pthread_setspecific(tss_data_native_key, temp.get()) != 0)
163            return 0;
164#elif defined(BOOST_HAS_MPTASKS)
165        if (MPSetTaskStorageValue(tss_data_native_key, temp.get()) != noErr)
166            return 0;
167#endif
168        {
169            boost::mutex::scoped_lock lock(*tss_data_mutex);
170            tss_data_inc_use(lock);
171        }
172        slots = temp.release();
173    }
174
175    return slots;
176}
177
178} // namespace
179
180namespace boost {
181
182namespace detail {
183void tss::init(boost::function1<void, void*>* pcleanup)
184{
185    boost::call_once(&init_tss_data, tss_data_once);
186    if (tss_data_cleanup_handlers == 0)
187        throw thread_resource_error();
188    boost::mutex::scoped_lock lock(*tss_data_mutex);
189    try
190    {
191        tss_data_cleanup_handlers->push_back(pcleanup);
192        m_slot = tss_data_cleanup_handlers->size() - 1;
193        tss_data_inc_use(lock);
194    }
195    catch (...)
196    {
197        throw thread_resource_error();
198    }
199}
200
201tss::~tss()
202{
203    boost::mutex::scoped_lock lock(*tss_data_mutex);
204    tss_data_dec_use(lock);
205}
206
207void* tss::get() const
208{
209    tss_slots* slots = get_slots(false);
210
211    if (!slots)
212        return 0;
213
214    if (m_slot >= slots->size())
215        return 0;
216
217    return (*slots)[m_slot];
218}
219
220void tss::set(void* value)
221{
222    tss_slots* slots = get_slots(true);
223
224    if (!slots)
225        throw boost::thread_resource_error();
226
227    if (m_slot >= slots->size())
228    {
229        try
230        {
231            slots->resize(m_slot + 1);
232        }
233        catch (...)
234        {
235            throw boost::thread_resource_error();
236        }
237    }
238
239    (*slots)[m_slot] = value;
240}
241
242void tss::cleanup(void* value)
243{
244    boost::mutex::scoped_lock lock(*tss_data_mutex);
245    (*(*tss_data_cleanup_handlers)[m_slot])(value);
246}
247
248} // namespace detail
249} // namespace boost
250
251#endif //BOOST_THREAD_NO_TSS_CLEANUP
Note: See TracBrowser for help on using the repository browser.