PFUNC
1.0
|
00001 #ifndef PFUNC_EVENT_HPP 00002 #define PFUNC_EVENT_HPP 00003 00009 #include <pfunc/config.h> 00010 #include <pfunc/environ.hpp> 00011 #include <pfunc/pfunc_common.h> 00012 #include <pfunc/no_copy.hpp> 00013 #include <pfunc/exception.hpp> 00014 #include <pfunc/pfunc_atomics.h> 00015 00016 #if PFUNC_HAVE_LIMITS_H == 1 00017 #include <limits.h> 00018 #else 00019 #define INT_MAX 0x0FFFFFFF 00020 #endif 00021 00022 #if PFUNC_HAVE_FUTEX == 1 00023 #include <pfunc/futex.h> 00024 #elif PFUNC_HAVE_PTHREADS == 1 || PFUNC_WINDOWS == 1 00025 #include <pfunc/mutex.hpp> 00026 #include <pfunc/cond.hpp> 00027 #else 00028 #error "Futexes, pthreads or windows threads are required" 00029 #endif 00030 00031 namespace pfunc { namespace detail { 00032 00033 static const int PFUNC_INACTIVE = 0; 00034 static const int PFUNC_ACTIVE_INCOMPLETE = 1; 00035 static const int PFUNC_ACTIVE_COMPLETE = 2; 00037 struct event_type {}; 00038 struct testable_event : public event_type {} ; 00039 struct waitable_event : public event_type {} ; 00040 00041 struct event_base : public no_copy { 00042 protected: 00043 ALIGN64 int event_state; 00044 ALIGN64 int num_waiters; 00046 public: 00050 event_base () :event_state (PFUNC_INACTIVE), num_waiters (1) {} 00051 00055 ~event_base () { } 00056 00063 bool test () { 00064 if (event_state == PFUNC_ACTIVE_INCOMPLETE) return false; 00065 else if (event_state == PFUNC_INACTIVE) return true; 00066 else { 00067 if (1 == pfunc_fetch_and_add_32 (&num_waiters, -1)) 00068 event_state = PFUNC_INACTIVE; 00069 return true; 00070 } 00071 } 00072 00078 void reset (const unsigned int& nwait) { 00079 num_waiters = nwait; 00080 event_state = PFUNC_ACTIVE_INCOMPLETE; 00081 } 00082 }; 00083 00084 template<typename EventType> 00085 struct event: public event_base { }; 00086 00087 #if PFUNC_HAVE_FUTEX == 1 00088 00089 template<> 00090 struct event<waitable_event>: public event_base { 00094 void wait () { 00095 if (event_state == PFUNC_ACTIVE_INCOMPLETE) 00096 futex_wait (&event_state, PFUNC_ACTIVE_INCOMPLETE); 00097 /* After wake up */ 00098 if (0 == pfunc_fetch_and_add_32 (&num_waiters, -1)) 00099 event_state = PFUNC_INACTIVE; 00100 } 00101 00105 void notify () { 00106 pfunc_mem_fence (); 00107 pfunc_fetch_and_store_32 (&event_state, PFUNC_ACTIVE_COMPLETE); 00108 futex_wake (&event_state, INT_MAX); 00109 } 00110 }; /* waitable event */ 00111 00112 #elif PFUNC_HAVE_PTHREADS == 1 || PFUNC_WINDOWS == 1 00113 00114 template<> 00115 struct event<waitable_event>: public event_base { 00116 mutex lck; 00117 cond cnd; 00118 PFUNC_DEFINE_EXCEPT_PTR() 00121 event () PFUNC_CONSTRUCTOR_TRY_BLOCK() : 00122 event_base () PFUNC_EXCEPT_PTR_INIT() { } 00123 PFUNC_CATCH_AND_RETHROW(event,event) 00124 00125 00126 ~event () { PFUNC_EXCEPT_PTR_CLEAR() } 00127 00131 void wait () { 00132 PFUNC_START_TRY_BLOCK() 00133 if (event_state == PFUNC_ACTIVE_INCOMPLETE) 00134 lck.lock (); 00135 if (PFUNC_ACTIVE_INCOMPLETE == event_state) 00136 cnd.wait (lck); 00137 lck.unlock (); 00138 /* After wake up */ 00139 if (0 == pfunc_fetch_and_add_32 (&num_waiters, -1)) 00140 event_state = PFUNC_INACTIVE; 00141 PFUNC_END_TRY_BLOCK() 00142 PFUNC_CATCH_AND_RETHROW(event,wait) 00143 } 00144 00148 void notify () { 00149 PFUNC_START_TRY_BLOCK() 00150 pfunc_fetch_and_store_32 (&event_state, PFUNC_ACTIVE_COMPLETE); 00151 lck.lock (); 00152 cnd.broadcast (); 00153 lck.unlock (); 00154 PFUNC_END_TRY_BLOCK() 00155 PFUNC_CATCH_AND_RETHROW(event,wait) 00156 } 00157 }; /* waitable event */ 00158 00159 #else 00160 #error "Futexes, Windows or pthreads are required" 00161 #endif 00162 00166 template<> 00167 struct event<testable_event>: public event_base { 00171 void notify () { 00172 pfunc_mem_fence (); 00173 event_state = PFUNC_ACTIVE_COMPLETE; 00174 } 00175 }; /* testable event */ 00176 } /* namespace detail */ } /* namespace pfunc */ 00177 00178 #endif // PFUNC_EVENT_HPP