Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/libs/thread/src/tss.cpp @ 13

Last change on this file since 13 was 12, checked in by landauf, 18 years ago

added boost

File size: 5.0 KB
Line 
1// Copyright (C) 2001-2003
2// William E. Kempf
3//
4// Permission to use, copy, modify, distribute and sell this software
5// and its documentation for any purpose is hereby granted without fee,
6// provided that the above copyright notice appear in all copies and
7// that both that copyright notice and this permission notice appear
8// in supporting documentation.  William E. Kempf makes no representations
9// about the suitability of this software for any purpose.
10// It is provided "as is" without express or implied warranty.
11
12#include <boost/thread/detail/config.hpp>
13
14#include <boost/thread/tss.hpp>
15#ifndef BOOST_THREAD_NO_TSS_CLEANUP
16
17#include <boost/thread/once.hpp>
18#include <boost/thread/mutex.hpp>
19#include <boost/thread/exceptions.hpp>
20#include <vector>
21#include <string>
22#include <stdexcept>
23#include <cassert>
24
25#if defined(BOOST_HAS_WINTHREADS)
26#   include <windows.h>
27#   include <boost/thread/detail/tss_hooks.hpp>
28#endif
29
30namespace {
31
32typedef std::vector<void*> tss_slots;
33
34struct tss_data_t
35{
36    boost::mutex mutex;
37    std::vector<boost::function1<void, void*>*> cleanup_handlers;
38#if defined(BOOST_HAS_WINTHREADS)
39    DWORD native_key;
40#elif defined(BOOST_HAS_PTHREADS)
41    pthread_key_t native_key;
42#elif defined(BOOST_HAS_MPTASKS)
43    TaskStorageIndex native_key;
44#endif
45};
46
47tss_data_t* tss_data = 0;
48boost::once_flag tss_data_once = BOOST_ONCE_INIT;
49
50extern "C" void cleanup_slots(void* p)
51{
52    tss_slots* slots = static_cast<tss_slots*>(p);
53    for (tss_slots::size_type i = 0; i < slots->size(); ++i)
54    {
55        boost::mutex::scoped_lock lock(tss_data->mutex);
56        (*tss_data->cleanup_handlers[i])((*slots)[i]);
57        (*slots)[i] = 0;
58    }
59}
60
61void init_tss_data()
62{
63    std::auto_ptr<tss_data_t> temp(new tss_data_t);
64
65#if defined(BOOST_HAS_WINTHREADS)
66    //Force the cleanup implementation library to be linked in
67    tss_cleanup_implemented();
68
69    //Allocate tls slot
70    temp->native_key = TlsAlloc();
71    if (temp->native_key == 0xFFFFFFFF)
72        return;
73#elif defined(BOOST_HAS_PTHREADS)
74    int res = pthread_key_create(&temp->native_key, &cleanup_slots);
75    if (res != 0)
76        return;
77#elif defined(BOOST_HAS_MPTASKS)
78    OSStatus status = MPAllocateTaskStorageIndex(&temp->native_key);
79    if (status != noErr)
80        return;
81#endif
82
83    // Intentional memory "leak"
84    // This is the only way to ensure the mutex in the global data
85    // structure is available when cleanup handlers are run, since the
86    // execution order of cleanup handlers is unspecified on any platform
87    // with regards to C++ destructor ordering rules.
88    tss_data = temp.release();
89}
90
91#if defined(BOOST_HAS_WINTHREADS)
92tss_slots* get_slots(bool alloc);
93
94void __cdecl tss_thread_exit()
95{
96    tss_slots* slots = get_slots(false);
97    if (slots)
98        cleanup_slots(slots);
99}
100#endif
101
102tss_slots* get_slots(bool alloc)
103{
104    tss_slots* slots = 0;
105
106#if defined(BOOST_HAS_WINTHREADS)
107    slots = static_cast<tss_slots*>(
108        TlsGetValue(tss_data->native_key));
109#elif defined(BOOST_HAS_PTHREADS)
110    slots = static_cast<tss_slots*>(
111        pthread_getspecific(tss_data->native_key));
112#elif defined(BOOST_HAS_MPTASKS)
113    slots = static_cast<tss_slots*>(
114        MPGetTaskStorageValue(tss_data->native_key));
115#endif
116
117    if (slots == 0 && alloc)
118    {
119        std::auto_ptr<tss_slots> temp(new tss_slots);
120
121#if defined(BOOST_HAS_WINTHREADS)
122        if (at_thread_exit(&tss_thread_exit) == -1)
123            return 0;
124        if (!TlsSetValue(tss_data->native_key, temp.get()))
125            return 0;
126#elif defined(BOOST_HAS_PTHREADS)
127        if (pthread_setspecific(tss_data->native_key, temp.get()) != 0)
128            return 0;
129#elif defined(BOOST_HAS_MPTASKS)
130        if (MPSetTaskStorageValue(tss_data->native_key, temp.get()) != noErr)
131            return 0;
132#endif
133
134        slots = temp.release();
135    }
136
137    return slots;
138}
139
140} // namespace
141
142namespace boost {
143
144namespace detail {
145void tss::init(boost::function1<void, void*>* pcleanup)
146{
147    boost::call_once(&init_tss_data, tss_data_once);
148    if (tss_data == 0)
149        throw thread_resource_error();
150    boost::mutex::scoped_lock lock(tss_data->mutex);
151    try
152    {
153        tss_data->cleanup_handlers.push_back(pcleanup);
154        m_slot = tss_data->cleanup_handlers.size() - 1;
155    }
156    catch (...)
157    {
158        throw thread_resource_error();
159    }
160}
161
162void* tss::get() const
163{
164    tss_slots* slots = get_slots(false);
165
166    if (!slots)
167        return 0;
168
169    if (m_slot >= slots->size())
170        return 0;
171
172    return (*slots)[m_slot];
173}
174
175void tss::set(void* value)
176{
177    tss_slots* slots = get_slots(true);
178
179    if (!slots)
180        throw boost::thread_resource_error();
181
182    if (m_slot >= slots->size())
183    {
184        try
185        {
186            slots->resize(m_slot + 1);
187        }
188        catch (...)
189        {
190            throw boost::thread_resource_error();
191        }
192    }
193
194    (*slots)[m_slot] = value;
195}
196
197void tss::cleanup(void* value)
198{
199    boost::mutex::scoped_lock lock(tss_data->mutex);
200    (*tss_data->cleanup_handlers[m_slot])(value);
201}
202
203} // namespace detail
204} // namespace boost
205
206#endif //BOOST_THREAD_NO_TSS_CLEANUP
Note: See TracBrowser for help on using the repository browser.