Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/thread/src/thread.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: 9.8 KB
Line 
1// Copyright (C) 2001-2003
2// William E. Kempf
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/thread.hpp>
10#include <boost/thread/xtime.hpp>
11#include <boost/thread/condition.hpp>
12#include <cassert>
13
14#if defined(BOOST_HAS_WINTHREADS)
15#   include <windows.h>
16#   if !defined(BOOST_NO_THREADEX)
17#      include <process.h>
18#   endif
19#elif defined(BOOST_HAS_MPTASKS)
20#   include <DriverServices.h>
21
22#   include "init.hpp"
23#   include "safe.hpp"
24#   include <boost/thread/tss.hpp>
25#endif
26
27#include "timeconv.inl"
28
29#if defined(BOOST_HAS_WINTHREADS)
30#   include "boost/thread/detail/tss_hooks.hpp"
31#endif
32
33namespace {
34
35#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_NO_THREADEX)
36// Windows CE doesn't define _beginthreadex
37
38struct ThreadProxyData
39{
40    typedef unsigned (__stdcall* func)(void*);
41    func start_address_;
42    void* arglist_;
43    ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {}
44};
45
46DWORD WINAPI ThreadProxy(LPVOID args)
47{
48    ThreadProxyData* data=reinterpret_cast<ThreadProxyData*>(args);
49    DWORD ret=data->start_address_(data->arglist_);
50    delete data;
51    return ret;
52}
53
54inline unsigned _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
55void* arglist, unsigned initflag,unsigned* thrdaddr)
56{
57    DWORD threadID;
58    HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
59        new ThreadProxyData(start_address,arglist),initflag,&threadID);
60    if (hthread!=0)
61        *thrdaddr=threadID;
62    return reinterpret_cast<unsigned>(hthread);
63}
64#endif
65
66class thread_param
67{
68public:
69    thread_param(const boost::function0<void>& threadfunc)
70        : m_threadfunc(threadfunc), m_started(false)
71    {
72    }
73    void wait()
74    {
75        boost::mutex::scoped_lock scoped_lock(m_mutex);
76        while (!m_started)
77            m_condition.wait(scoped_lock);
78    }
79    void started()
80    {
81        boost::mutex::scoped_lock scoped_lock(m_mutex);
82        m_started = true;
83        m_condition.notify_one();
84    }
85
86    boost::mutex m_mutex;
87    boost::condition m_condition;
88    const boost::function0<void>& m_threadfunc;
89    bool m_started;
90};
91
92} // unnamed namespace
93
94extern "C" {
95#if defined(BOOST_HAS_WINTHREADS)
96    unsigned __stdcall thread_proxy(void* param)
97#elif defined(BOOST_HAS_PTHREADS)
98        static void* thread_proxy(void* param)
99#elif defined(BOOST_HAS_MPTASKS)
100        static OSStatus thread_proxy(void* param)
101#endif
102    {
103        //try
104        //{
105            thread_param* p = static_cast<thread_param*>(param);
106            boost::function0<void> threadfunc = p->m_threadfunc;
107            p->started();
108            threadfunc();
109#if defined(BOOST_HAS_WINTHREADS)
110            on_thread_exit();
111#endif
112        //}
113        //catch (...)
114        //{
115#if defined(BOOST_HAS_WINTHREADS)
116        //    on_thread_exit();
117#endif
118        //}
119#if defined(BOOST_HAS_MPTASKS)
120        ::boost::detail::thread_cleanup();
121#endif
122        return 0;
123    }
124
125}
126
127namespace boost {
128
129thread::thread()
130    : m_joinable(false)
131{
132#if defined(BOOST_HAS_WINTHREADS)
133    m_thread = reinterpret_cast<void*>(GetCurrentThread());
134    m_id = GetCurrentThreadId();
135#elif defined(BOOST_HAS_PTHREADS)
136    m_thread = pthread_self();
137#elif defined(BOOST_HAS_MPTASKS)
138    threads::mac::detail::thread_init();
139    threads::mac::detail::create_singletons();
140    m_pTaskID = MPCurrentTaskID();
141    m_pJoinQueueID = kInvalidID;
142#endif
143}
144
145thread::thread(const function0<void>& threadfunc)
146    : m_joinable(true)
147{
148    thread_param param(threadfunc);
149#if defined(BOOST_HAS_WINTHREADS)
150    m_thread = reinterpret_cast<void*>(_beginthreadex(0, 0, &thread_proxy,
151                                           &param, 0, &m_id));
152    if (!m_thread)
153        throw thread_resource_error();
154#elif defined(BOOST_HAS_PTHREADS)
155    int res = 0;
156    res = pthread_create(&m_thread, 0, &thread_proxy, &param);
157    if (res != 0)
158        throw thread_resource_error();
159#elif defined(BOOST_HAS_MPTASKS)
160    threads::mac::detail::thread_init();
161    threads::mac::detail::create_singletons();
162    OSStatus lStatus = noErr;
163
164    m_pJoinQueueID = kInvalidID;
165    m_pTaskID = kInvalidID;
166
167    lStatus = MPCreateQueue(&m_pJoinQueueID);
168    if (lStatus != noErr) throw thread_resource_error();
169
170    lStatus = MPCreateTask(&thread_proxy, &param, 0UL, m_pJoinQueueID, NULL,
171        NULL, 0UL, &m_pTaskID);
172    if (lStatus != noErr)
173    {
174        lStatus = MPDeleteQueue(m_pJoinQueueID);
175        assert(lStatus == noErr);
176        throw thread_resource_error();
177    }
178#endif
179    param.wait();
180}
181
182thread::~thread()
183{
184    if (m_joinable)
185    {
186#if defined(BOOST_HAS_WINTHREADS)
187        int res = 0;
188        res = CloseHandle(reinterpret_cast<HANDLE>(m_thread));
189        assert(res);
190#elif defined(BOOST_HAS_PTHREADS)
191        pthread_detach(m_thread);
192#elif defined(BOOST_HAS_MPTASKS)
193        assert(m_pJoinQueueID != kInvalidID);
194        OSStatus lStatus = MPDeleteQueue(m_pJoinQueueID);
195        assert(lStatus == noErr);
196#endif
197    }
198}
199
200bool thread::operator==(const thread& other) const
201{
202#if defined(BOOST_HAS_WINTHREADS)
203    return other.m_id == m_id;
204#elif defined(BOOST_HAS_PTHREADS)
205    return pthread_equal(m_thread, other.m_thread) != 0;
206#elif defined(BOOST_HAS_MPTASKS)
207    return other.m_pTaskID == m_pTaskID;
208#endif
209}
210
211bool thread::operator!=(const thread& other) const
212{
213    return !operator==(other);
214}
215
216void thread::join()
217{
218    assert(m_joinable); //See race condition comment below
219    int res = 0;
220#if defined(BOOST_HAS_WINTHREADS)
221    res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_thread), INFINITE);
222    assert(res == WAIT_OBJECT_0);
223    res = CloseHandle(reinterpret_cast<HANDLE>(m_thread));
224    assert(res);
225#elif defined(BOOST_HAS_PTHREADS)
226    res = pthread_join(m_thread, 0);
227    assert(res == 0);
228#elif defined(BOOST_HAS_MPTASKS)
229    OSStatus lStatus = threads::mac::detail::safe_wait_on_queue(
230        m_pJoinQueueID, NULL, NULL, NULL, kDurationForever);
231    assert(lStatus == noErr);
232#endif
233    // This isn't a race condition since any race that could occur would
234    // have us in undefined behavior territory any way.
235    m_joinable = false;
236}
237
238void thread::sleep(const xtime& xt)
239{
240    for (int foo=0; foo < 5; ++foo)
241    {
242#if defined(BOOST_HAS_WINTHREADS)
243        int milliseconds;
244        to_duration(xt, milliseconds);
245        Sleep(milliseconds);
246#elif defined(BOOST_HAS_PTHREADS)
247#   if defined(BOOST_HAS_PTHREAD_DELAY_NP)
248        timespec ts;
249        to_timespec_duration(xt, ts);
250        int res = 0;
251        res = pthread_delay_np(&ts);
252        assert(res == 0);
253#   elif defined(BOOST_HAS_NANOSLEEP)
254        timespec ts;
255        to_timespec_duration(xt, ts);
256
257        //  nanosleep takes a timespec that is an offset, not
258        //  an absolute time.
259        nanosleep(&ts, 0);
260#   else
261        mutex mx;
262        mutex::scoped_lock lock(mx);
263        condition cond;
264        cond.timed_wait(lock, xt);
265#   endif
266#elif defined(BOOST_HAS_MPTASKS)
267        int microseconds;
268        to_microduration(xt, microseconds);
269        Duration lMicroseconds(kDurationMicrosecond * microseconds);
270        AbsoluteTime sWakeTime(DurationToAbsolute(lMicroseconds));
271        threads::mac::detail::safe_delay_until(&sWakeTime);
272#endif
273        xtime cur;
274        xtime_get(&cur, TIME_UTC);
275        if (xtime_cmp(xt, cur) <= 0)
276            return;
277    }
278}
279
280void thread::yield()
281{
282#if defined(BOOST_HAS_WINTHREADS)
283    Sleep(0);
284#elif defined(BOOST_HAS_PTHREADS)
285#   if defined(BOOST_HAS_SCHED_YIELD)
286    int res = 0;
287    res = sched_yield();
288    assert(res == 0);
289#   elif defined(BOOST_HAS_PTHREAD_YIELD)
290    int res = 0;
291    res = pthread_yield();
292    assert(res == 0);
293#   else
294    xtime xt;
295    xtime_get(&xt, TIME_UTC);
296    sleep(xt);
297#   endif
298#elif defined(BOOST_HAS_MPTASKS)
299    MPYield();
300#endif
301}
302
303thread_group::thread_group()
304{
305}
306
307thread_group::~thread_group()
308{
309    // We shouldn't have to scoped_lock here, since referencing this object
310    // from another thread while we're deleting it in the current thread is
311    // going to lead to undefined behavior any way.
312    for (std::list<thread*>::iterator it = m_threads.begin();
313         it != m_threads.end(); ++it)
314    {
315        delete (*it);
316    }
317}
318
319thread* thread_group::create_thread(const function0<void>& threadfunc)
320{
321    // No scoped_lock required here since the only "shared data" that's
322    // modified here occurs inside add_thread which does scoped_lock.
323    std::auto_ptr<thread> thrd(new thread(threadfunc));
324    add_thread(thrd.get());
325    return thrd.release();
326}
327
328void thread_group::add_thread(thread* thrd)
329{
330    mutex::scoped_lock scoped_lock(m_mutex);
331
332    // For now we'll simply ignore requests to add a thread object multiple
333    // times. Should we consider this an error and either throw or return an
334    // error value?
335    std::list<thread*>::iterator it = std::find(m_threads.begin(),
336        m_threads.end(), thrd);
337    assert(it == m_threads.end());
338    if (it == m_threads.end())
339        m_threads.push_back(thrd);
340}
341
342void thread_group::remove_thread(thread* thrd)
343{
344    mutex::scoped_lock scoped_lock(m_mutex);
345
346    // For now we'll simply ignore requests to remove a thread object that's
347    // not in the group. Should we consider this an error and either throw or
348    // return an error value?
349    std::list<thread*>::iterator it = std::find(m_threads.begin(),
350        m_threads.end(), thrd);
351    assert(it != m_threads.end());
352    if (it != m_threads.end())
353        m_threads.erase(it);
354}
355
356void thread_group::join_all()
357{
358    mutex::scoped_lock scoped_lock(m_mutex);
359    for (std::list<thread*>::iterator it = m_threads.begin();
360         it != m_threads.end(); ++it)
361    {
362        (*it)->join();
363    }
364}
365
366int thread_group::size()
367{
368        return m_threads.size();
369}
370
371} // namespace boost
Note: See TracBrowser for help on using the repository browser.