Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/thread/src/tss_hooks.cpp @ 29

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

updated boost from 1_33_1 to 1_34_1

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