Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

added boost

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