aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/common/src/std_condition_variable.h
blob: e7088725c95bc8564afe21950087c23cdec1a0ca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#ifndef CONDITION_VARIABLE_H_
#define CONDITION_VARIABLE_H_

#define GCC_VER(x,y,z)	((x) * 10000 + (y) * 100 + (z))
#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)

#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__
// GCC 4.4 provides <condition_variable>
#include <condition_variable>
#else

// partial std::condition_variable implementation for win32/pthread

#include "std_mutex.h"

#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__)
#define USE_RVALUE_REFERENCES
#endif

#if defined(_WIN32) && defined(_M_X64)
#define USE_CONDITION_VARIABLES
#elif defined(_WIN32)
#define USE_EVENTS
#endif

namespace std
{

class condition_variable
{
#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
    typedef CONDITION_VARIABLE native_type;
#elif defined(_WIN32)
    typedef HANDLE native_type;
#else
    typedef pthread_cond_t native_type;
#endif

public:

#ifdef USE_EVENTS
    typedef native_type native_handle_type;
#else
    typedef native_type* native_handle_type;
#endif

    condition_variable()
    {
#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
        InitializeConditionVariable(&m_handle);
#elif defined(_WIN32)
        m_handle = CreateEvent(NULL, false, false, NULL);
#else
        pthread_cond_init(&m_handle, NULL);
#endif
    }

    ~condition_variable()
    {
#if defined(_WIN32) && !defined(USE_CONDITION_VARIABLES)
        CloseHandle(m_handle);
#elif !defined(_WIN32)
        pthread_cond_destroy(&m_handle);
#endif
    }

    condition_variable(const condition_variable&) /*= delete*/;
    condition_variable& operator=(const condition_variable&) /*= delete*/;

    void notify_one()
    {
#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
        WakeConditionVariable(&m_handle);
#elif defined(_WIN32)
        SetEvent(m_handle);
#else
        pthread_cond_signal(&m_handle);
#endif
    }

    void notify_all()
    {
#if defined(_WIN32) && defined(USE_CONDITION_VARIABLES)
        WakeAllConditionVariable(&m_handle);
#elif defined(_WIN32)
        // TODO: broken
        SetEvent(m_handle);
#else
        pthread_cond_broadcast(&m_handle);
#endif
    }

    void wait(unique_lock<mutex>& lock)
    {
#ifdef _WIN32
#ifdef USE_SRWLOCKS
        SleepConditionVariableSRW(&m_handle, lock.mutex()->native_handle(), INFINITE, 0);
#elif defined(USE_CONDITION_VARIABLES)
        SleepConditionVariableCS(&m_handle, lock.mutex()->native_handle(), INFINITE);
#else
        // TODO: broken, the unlock and wait need to be atomic
        lock.unlock();
        WaitForSingleObject(m_handle, INFINITE);
        lock.lock();
#endif
#else
        pthread_cond_wait(&m_handle, lock.mutex()->native_handle());
#endif
    }

    template <class Predicate>
    void wait(unique_lock<mutex>& lock, Predicate pred)
    {
        while (!pred())
            wait(lock);
    }

    //template <class Clock, class Duration>
    //cv_status wait_until(unique_lock<mutex>& lock,
    //	const chrono::time_point<Clock, Duration>& abs_time);

    //template <class Clock, class Duration, class Predicate>
    //	bool wait_until(unique_lock<mutex>& lock,
    //	const chrono::time_point<Clock, Duration>& abs_time,
    //	Predicate pred);

    //template <class Rep, class Period>
    //cv_status wait_for(unique_lock<mutex>& lock,
    //	const chrono::duration<Rep, Period>& rel_time);

    //template <class Rep, class Period, class Predicate>
    //	bool wait_for(unique_lock<mutex>& lock,
    //	const chrono::duration<Rep, Period>& rel_time,
    //	Predicate pred);

    native_handle_type native_handle()
    {
#ifdef USE_EVENTS
        return m_handle;
#else
        return &m_handle;
#endif
    }

private:
    native_type m_handle;
};

}

#endif
#endif