Scopira 20080306

thread_pthreads.h

00001 
00002 /*
00003  *  Copyright (c) 2002-2004    National Research Council
00004  *
00005  *  All rights reserved.
00006  *
00007  *  This material is confidential and proprietary information of
00008  *  National Research Council Canada ("Confidential Information").
00009  *  This Confidential Information may only be used and reproduced
00010  *  in accordance with the terms of the license agreement.
00011  *
00012  */
00013 
00014 #ifndef __INCLUDED_SCOPIRA_TOOL_THREAD_PTHREADS_H__
00015 #define __INCLUDED_SCOPIRA_TOOL_THREAD_PTHREADS_H__
00016 
00017 #include <scopira/tool/platform.h>
00018 #include <scopira/tool/export.h>
00019 
00020 #include <pthread.h>
00021 #include <errno.h>
00022 
00023 #include <scopira/tool/object.h>
00024 
00025 namespace scopira
00026 {
00027   namespace tool
00028   {
00029     class runnable_i;
00030     class job_i;
00031 
00034     typedef void* (*runfunc_t)(void*);
00035     class thread;
00036 
00037     class condition;
00038 
00039     class rwlock;
00040     class read_locker;
00041     class write_locker;
00042 
00049     SCOPIRA_EXPORT int num_system_cpus(void);
00050 
00051     template <class T> class shared_area;
00052     template <class T> class event_area;
00053     template <class T> class rw_area;
00054 
00055     template <class T> class area_ptr;
00056     template <class T> class const_area_ptr;
00057     template <class T> class locker_ptr;
00058     template <class T> class event_ptr;
00059     template <class T> class read_locker_ptr;
00060     template <class T> class write_locker_ptr;
00061   }
00062 }
00063 
00069 class scopira::tool::runnable_i
00070 {
00071   public:
00076     SCOPIRA_EXPORT virtual void run(void) = 0;
00077 
00078   protected:
00079     virtual ~runnable_i() { }
00080 };
00081 
00087 class scopira::tool::job_i : public virtual scopira::tool::object
00088 {
00089   public:
00091     SCOPIRA_EXPORT virtual void start(void) = 0;
00092 
00094     SCOPIRA_EXPORT virtual void notify_stop(void) = 0;
00095 
00097     SCOPIRA_EXPORT virtual void wait_stop(void) = 0;
00098 
00100     SCOPIRA_EXPORT virtual bool is_running(void) const = 0;
00101 };
00102 
00108 class scopira::tool::thread : public virtual scopira::tool::job_i,
00109   public virtual scopira::tool::runnable_i
00110 {
00111   public:
00112     typedef pthread_key_t tlskey_t;
00113 
00114   protected:
00115     runnable_i *dm_target;
00116     runfunc_t dm_runfunc;
00117     void *dm_runfunc_arg;
00118     volatile bool dm_running;
00119 
00120     pthread_t dm_thread;
00121 
00122   public:
00135     SCOPIRA_EXPORT thread(runnable_i* target);
00146     SCOPIRA_EXPORT thread(runfunc_t func, void *arg);
00147 
00149     SCOPIRA_EXPORT virtual ~thread();
00150 
00152     SCOPIRA_EXPORT virtual void run(void);
00153 
00155     SCOPIRA_EXPORT virtual void start(void);
00158     SCOPIRA_EXPORT virtual void notify_stop(void);
00160     SCOPIRA_EXPORT virtual void wait_stop(void);
00162     SCOPIRA_EXPORT virtual bool is_running(void) const { return dm_running; }
00163 
00170     SCOPIRA_EXPORT static void sleep(int msec);
00171 
00181     SCOPIRA_EXPORT static void open_tls(tlskey_t &outkey);
00187     SCOPIRA_EXPORT static void close_tls(tlskey_t k);
00188 
00196     SCOPIRA_EXPORT static void set_tls(tlskey_t k, const void *val);
00204     SCOPIRA_EXPORT static void * get_tls(tlskey_t k);
00205 
00206   protected:
00207     SCOPIRA_EXPORT static void * voidrun(void *arg);
00208 };
00209 
00220 class scopira::tool::condition
00221 {
00222   protected:
00223     pthread_cond_t dm_con;
00224 
00225   public:
00229     SCOPIRA_EXPORT condition(void);
00231     SCOPIRA_EXPORT ~condition();
00232 
00238     SCOPIRA_EXPORT void notify(void);
00244     SCOPIRA_EXPORT void notify_all(void);
00253     SCOPIRA_EXPORT void wait(mutex &mut);
00265     SCOPIRA_EXPORT bool wait(mutex &mut, int msec);
00266 };
00267 
00273 class scopira::tool::rwlock
00274 {
00275   private:
00276     pthread_rwlock_t dm_rw;
00277 
00278   public:
00280     SCOPIRA_EXPORT rwlock(void);
00282     SCOPIRA_EXPORT ~rwlock();
00283 
00285     SCOPIRA_EXPORT void write_lock(void);
00287     SCOPIRA_EXPORT bool try_write_lock(void);
00289     SCOPIRA_EXPORT void read_lock(void);
00291     SCOPIRA_EXPORT bool try_read_lock(void);
00293     SCOPIRA_EXPORT void unlock(void);
00294 };
00295 
00301 class scopira::tool::read_locker
00302 {
00303   private:
00304     scopira::tool::rwlock &dm_rw;
00305   public:
00307     read_locker(rwlock &rw) : dm_rw(rw) { dm_rw.read_lock(); }
00309     ~read_locker() { dm_rw.unlock(); }
00310 };
00311 
00317 class scopira::tool::write_locker
00318 {
00319   private:
00320     scopira::tool::rwlock &dm_rw;
00321 
00322   public:
00324     write_locker(rwlock &rw) : dm_rw(rw) { dm_rw.write_lock(); }
00326     ~write_locker() { dm_rw.unlock(); }
00327 };
00328 
00336 template <class T> class scopira::tool::shared_area
00337 {
00338   public:
00339     volatile T pm_data; 
00340     mutable scopira::tool::mutex      pm_mutex;
00341 };
00342 
00349 template <class T> class scopira::tool::event_area : public scopira::tool::shared_area<T>
00350 {
00351   public:
00352     mutable scopira::tool::condition  pm_condition;
00353 };
00354 
00361 template <class T> class scopira::tool::rw_area
00362 {
00363   public:
00364     volatile T pm_data; 
00365     mutable scopira::tool::rwlock      pm_rwlock;
00366 };
00367 
00381 template <class T> class scopira::tool::area_ptr
00382 {
00383   protected:
00384     T* dm_ptr;
00385 
00386   public:
00391     area_ptr(const shared_area<T>& ref) : dm_ptr(const_cast<T*>(&ref.pm_data)) { }
00396     area_ptr(const rw_area<T>& ref) : dm_ptr(const_cast<T*>(&ref.pm_data)) { }
00397 
00398   protected:
00403     area_ptr(const volatile T& ref) : dm_ptr(const_cast<T*>(&ref)) { }
00404 
00405   public:
00407     T* get(void) { return dm_ptr; }
00409     T& operator*(void) { return *dm_ptr; }
00411     T* operator->(void) { return dm_ptr; }
00412 
00419     void reset(void) { dm_ptr = const_cast<T*>(const_cast<volatile T*>(dm_ptr)); }  // this is whacky :)
00420 };
00421 
00434 template <class T> class scopira::tool::const_area_ptr
00435 {
00436   protected:
00437     const T* dm_ptr;
00438 
00439   public:
00444     const_area_ptr(const shared_area<T>& ref) : dm_ptr(const_cast<const T*>(&ref.pm_data)) { }
00449     const_area_ptr(const rw_area<T>& ref) : dm_ptr(const_cast<const T*>(&ref.pm_data)) { }
00450 
00451   protected:
00456     const_area_ptr(const volatile T& ref) : dm_ptr(const_cast<T*>(&ref)) { }
00457 
00458   public:
00460     const T* get(void) { return dm_ptr; }
00462     const T& operator*(void) { return *dm_ptr; }
00464     const T* operator->(void) { return dm_ptr; }
00465 
00472     void reset(void) { dm_ptr = const_cast<const T*>(const_cast<volatile T*>(dm_ptr)); }  // this is whacky :)
00473 };
00474 
00483 template <class T> class scopira::tool::locker_ptr : public scopira::tool::area_ptr<T>
00484 {
00485   protected:
00486     scopira::tool::mutex & dm_mut;
00487 
00488   public:
00490     locker_ptr(const shared_area<T>& ref) : area_ptr<T>(ref.pm_data), dm_mut(ref.pm_mutex) { dm_mut.lock(); }
00491 
00493     ~locker_ptr() { dm_mut.unlock(); }
00494   private:
00495 };
00496 
00502 template <class T> class scopira::tool::event_ptr : public scopira::tool::locker_ptr<T>
00503 {
00504   protected:
00505     scopira::tool::condition & dm_cond;
00506 
00507   public:
00509     event_ptr(const event_area<T>& ref) : locker_ptr<T>(ref), dm_cond(ref.pm_condition) { }
00510 
00518     void notify(void) { dm_cond.notify(); }
00526     void notify_all(void) { dm_cond.notify_all(); }
00535     void wait(void) { dm_cond.wait(locker_ptr<T>::dm_mut); }
00545     bool wait(int msec) { return dm_cond.wait(locker_ptr<T>::dm_mut, msec); }
00546 };
00547 
00553 template <class T> class scopira::tool::read_locker_ptr : public scopira::tool::const_area_ptr<T>
00554 {
00555   protected:
00556     scopira::tool::rwlock & dm_rw;
00557 
00558   public:
00560     read_locker_ptr(const rw_area<T>& ref) : const_area_ptr<T>(ref.pm_data), dm_rw(ref.pm_rwlock) { dm_rw.read_lock(); }
00561 
00563     ~read_locker_ptr() { dm_rw.unlock(); }
00564 };
00565 
00571 template <class T> class scopira::tool::write_locker_ptr : public scopira::tool::area_ptr<T>
00572 {
00573   protected:
00574     scopira::tool::rwlock & dm_rw;
00575 
00576   public:
00578     write_locker_ptr(const rw_area<T>& ref) : area_ptr<T>(ref.pm_data), dm_rw(ref.pm_rwlock) { dm_rw.write_lock(); }
00579 
00581     ~write_locker_ptr() { dm_rw.unlock(); }
00582 };
00583 
00584 #endif
00585 
00586