summaryrefslogtreecommitdiffstats
path: root/src/common/std_condition_variable.h
blob: ad2022f5ac8e751b44103f9ef7f868e6e27597ea (plain) (blame)
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168

#pragma once

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

#ifndef __has_include
#define __has_include(s) 0
#endif

#if GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__ 

// GCC 4.4 provides <condition_variable>
#include <condition_variable>

#elif __has_include(<condition_variable>) && !ANDROID

// clang and libc++ provide <condition_variable> on OSX. However, the version
// of libc++ bundled with OSX 10.7 and 10.8 is buggy: it uses _ as a variable.
//
// We work around this issue by undefining and redefining _.

#undef _
#include <condition_variable>
#define _(s) wxGetTranslation((s))

#else

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

#include "common/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