summaryrefslogblamecommitdiffstats
path: root/src/common/std_condition_variable.h
blob: ad2022f5ac8e751b44103f9ef7f868e6e27597ea (plain) (tree)
1
2
3
4
 
            
 
                                                         

























                                                                              
                             
















                                                                                       
                                           
                     
                               
     
                                       




                 
                                           
     
                                            

      

                        
                                                       
                                               
                     
                                                         
     
                                           
      
     
 

                         
                                                        
                              
                      
                                        
      
     
 

                                                                          
 

                     
                                                       
                                         
                     
                           
     
                                       
      
     
 

                     
                                                       
                                            
                     

                           
     
                                          
      
     
 

                                       
             









                                                                                         
     
                                                                    
      




























                                                               
                 
                        
     
                         
      
     

        
                         




      

#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