Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_33_1/libs/thread/src/tss_hooks.cpp @ 12

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

added boost

File size: 5.2 KB
Line 
1// (C) Copyright Michael Glassford 2004.
2// Use, modification and distribution are subject to the
3// Boost Software License, Version 1.0. (See accompanying file
4// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6#include <boost/thread/detail/config.hpp>
7
8#if defined(BOOST_HAS_WINTHREADS)
9
10    #include <boost/thread/detail/tss_hooks.hpp>
11
12    #include <boost/assert.hpp>
13    #include <boost/thread/mutex.hpp>
14    #include <boost/thread/once.hpp>
15
16    #include <list>
17
18    #define WIN32_LEAN_AND_MEAN
19    #include <windows.h>
20
21    namespace
22    {
23        typedef std::list<thread_exit_handler> thread_exit_handlers;
24
25        boost::once_flag once_init_threadmon_mutex = BOOST_ONCE_INIT;
26        boost::mutex* threadmon_mutex;
27        void init_threadmon_mutex(void)
28        {
29            threadmon_mutex = new boost::mutex;
30            if (!threadmon_mutex)
31                throw boost::thread_resource_error();
32        }
33
34        const DWORD invalid_tls_key = TLS_OUT_OF_INDEXES;
35        DWORD tls_key = invalid_tls_key;
36
37        unsigned long attached_thread_count = 0;
38    }
39
40    /*
41    Calls to DllMain() and tls_callback() are serialized by the OS;
42    however, calls to at_thread_exit are not, so it must be protected
43    by a mutex. Since we already need a mutex for at_thread_exit(),
44    and since there is no guarantee that on_process_enter(),
45    on_process_exit(), on_thread_enter(), and on_thread_exit()
46    will be called only from DllMain() or tls_callback(), it makes
47    sense to protect those, too.
48    */
49
50    extern "C" BOOST_THREAD_DECL int at_thread_exit(
51        thread_exit_handler exit_handler
52        )
53    {
54        boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
55        boost::mutex::scoped_lock lock(*threadmon_mutex);
56
57        //Allocate a tls slot if necessary.
58
59        if (tls_key == invalid_tls_key)
60            tls_key = TlsAlloc();
61
62        if (tls_key == invalid_tls_key)
63            return -1;
64
65        //Get the exit handlers list for the current thread from tls.
66
67        thread_exit_handlers* exit_handlers =
68            static_cast<thread_exit_handlers*>(TlsGetValue(tls_key));
69
70        if (!exit_handlers)
71        {
72            //No exit handlers list was created yet.
73
74            try
75            {
76                //Attempt to create a new exit handlers list.
77
78                exit_handlers = new thread_exit_handlers;
79                if (!exit_handlers)
80                    return -1;
81
82                //Attempt to store the list pointer in tls.
83
84                if (TlsSetValue(tls_key, exit_handlers))
85                    ++attached_thread_count;
86                else
87                {
88                    delete exit_handlers;
89                    return -1;
90                }
91            }
92            catch (...)
93            {
94                return -1;
95            }
96        }
97
98        //Like the C runtime library atexit() function,
99        //functions should be called in the reverse of
100        //the order they are added, so push them on the
101        //front of the list.
102
103        try
104        {
105            exit_handlers->push_front(exit_handler);
106        }
107        catch (...)
108        {
109            return -1;
110        }
111
112        //Like the atexit() function, a result of zero
113        //indicates success.
114
115        return 0;
116    }
117
118    extern "C" BOOST_THREAD_DECL void on_process_enter(void)
119    {
120        boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
121        boost::mutex::scoped_lock lock(*threadmon_mutex);
122
123        BOOST_ASSERT(attached_thread_count == 0);
124    }
125
126    extern "C" BOOST_THREAD_DECL void on_process_exit(void)
127    {
128        boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
129        boost::mutex::scoped_lock lock(*threadmon_mutex);
130
131        BOOST_ASSERT(attached_thread_count == 0);
132
133        //Free the tls slot if one was allocated.
134
135        if (tls_key != invalid_tls_key)
136        {
137            TlsFree(tls_key);
138            tls_key = invalid_tls_key;
139        }
140    }
141
142    extern "C" BOOST_THREAD_DECL void on_thread_enter(void)
143    {
144        //boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
145        //boost::mutex::scoped_lock lock(*threadmon_mutex);
146    }
147
148    extern "C" BOOST_THREAD_DECL void on_thread_exit(void)
149    {
150        boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
151        boost::mutex::scoped_lock lock(*threadmon_mutex);
152
153        //Get the exit handlers list for the current thread from tls.
154
155        if (tls_key == invalid_tls_key)
156            return;
157
158        thread_exit_handlers* exit_handlers =
159            static_cast<thread_exit_handlers*>(TlsGetValue(tls_key));
160
161        //If a handlers list was found, use it.
162
163        if (exit_handlers && TlsSetValue(tls_key, 0))
164        {
165            BOOST_ASSERT(attached_thread_count > 0);
166            --attached_thread_count;
167
168            lock.unlock();
169
170            //Call each handler and remove it from the list
171
172            while (!exit_handlers->empty())
173            {
174                if (thread_exit_handler exit_handler = *exit_handlers->begin())
175                    (*exit_handler)();
176                exit_handlers->pop_front();
177            }
178
179            delete exit_handlers;
180            exit_handlers = 0;
181        }
182    }
183
184#endif //defined(BOOST_HAS_WINTHREADS)
Note: See TracBrowser for help on using the repository browser.