PFUNC  1.0
pfunc/event.hpp
Go to the documentation of this file.
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