|
Rapicorn - Experimental UI Toolkit - Source Code 10.08.1
|
00001 /* Rapicorn 00002 * Copyright (C) 2006 Tim Janik 00003 * 00004 * This library is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU Lesser General Public 00006 * License as published by the Free Software Foundation; either 00007 * version 2.1 of the License, or (at your option) any later version. 00008 * 00009 * This library is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 * Lesser General Public License for more details. 00013 * 00014 * A copy of the GNU Lesser General Public License should ship along 00015 * with this library; if not, see http://www.gnu.org/copyleft/. 00016 */ 00017 #ifndef __RAPICORN_THREAD_XX_HH__ 00018 #define __RAPICORN_THREAD_XX_HH__ 00019 00020 #include <rcore/utilities.hh> 00021 00022 namespace Rapicorn { 00023 00024 class Thread; 00025 00026 template<class Value> inline bool once_enter (volatile Value *value_location); 00027 template<class Value> inline void once_leave (volatile Value *value_location, 00028 Value initialization_value); 00029 00030 class Mutex : protected NonCopyable { 00031 RapicornMutex mutex; 00032 friend class Cond; 00033 public: 00034 explicit Mutex (); 00035 void lock (); 00036 void unlock (); 00037 bool trylock (); // TRUE indicates success 00038 /*Des*/ ~Mutex (); 00039 }; 00040 00041 class RecMutex : protected NonCopyable { 00042 RapicornRecMutex rmutex; 00043 public: 00044 explicit RecMutex (); 00045 void lock (); 00046 void unlock (); 00047 bool trylock (); 00048 /*Des*/ ~RecMutex (); 00049 }; 00050 00051 class Cond : protected NonCopyable { 00052 RapicornCond cond; 00053 public: 00054 explicit Cond (); 00055 void signal (); 00056 void broadcast (); 00057 void wait (Mutex &m); 00058 void wait_timed (Mutex &m, int64 max_usecs); 00059 /*Des*/ ~Cond (); 00060 }; 00061 00062 class SpinLock { 00063 volatile union { 00064 Mutex *fallback; // union needs pointer alignment 00065 char chars[RAPICORN_SIZEOF_PTHREADH_SPINLOCK]; // char may_alias any type 00066 } spinspace; 00067 public: 00068 explicit SpinLock (); 00069 void lock (); 00070 void unlock (); 00071 bool trylock (); 00072 /*Des*/ ~SpinLock (); 00073 }; 00074 00075 namespace Atomic { 00076 inline void read_barrier (void) { __sync_synchronize(); } 00077 inline void write_barrier (void) { __sync_synchronize(); } 00078 inline void full_barrier (void) { __sync_synchronize(); } 00079 /* atomic values */ 00080 template<class V> inline void value_set (volatile V *value_addr, V n) { while (!__sync_bool_compare_and_swap (value_addr, *value_addr, n)); } 00081 template<class V> inline V value_get (volatile V *value_addr) { return __sync_fetch_and_add (value_addr, 0); } 00082 template<class V> inline bool value_cas (volatile V *value_addr, V o, V n) { return __sync_bool_compare_and_swap (value_addr, o, n); } 00083 template<class V> inline V value_add (volatile V *value_addr, V diff) { return __sync_fetch_and_add (value_addr, diff); } 00084 /* atomic numeric operations */ 00085 #define RAPICORN_ATOMIC_OPS(type) \ 00086 inline void set (volatile type *p, type v) { return value_set (p, v); } \ 00087 inline int get (volatile type *p) { return value_get (p); } \ 00088 inline bool cas (volatile type *p, type o, type n) { return value_cas (p, o, n); } \ 00089 inline int add (volatile type *p, type d) { return value_add (p, d); } 00090 RAPICORN_ATOMIC_OPS (int); 00091 RAPICORN_ATOMIC_OPS (uint); 00092 RAPICORN_ATOMIC_OPS (int64); 00093 RAPICORN_ATOMIC_OPS (uint64); 00094 /* atomic pointer operations */ 00095 template<class V> inline void ptr_set (V* volatile *ptr_addr, V *n) { while (!__sync_bool_compare_and_swap (ptr_addr, *ptr_addr, n)); } 00096 template<class V> inline V* ptr_get (V* volatile *ptr_addr) { return __sync_fetch_and_add (ptr_addr, 0); } 00097 template<class V> inline V* ptr_get (V* volatile const *ptr_addr) { return __sync_fetch_and_add (ptr_addr, 0); } 00098 template<class V> inline bool ptr_cas (V* volatile *ptr_adr, V *o, V *n) { return __sync_bool_compare_and_swap (ptr_adr, o, n); } 00099 } // Atomic 00100 00101 class OwnedMutex : protected NonCopyable { 00102 RecMutex m_rec_mutex; 00103 Thread * volatile m_owner; 00104 uint volatile m_count; 00105 public: 00106 explicit OwnedMutex (); 00107 inline void lock (); 00108 inline bool trylock (); 00109 inline void unlock (); 00110 inline Thread* owner (); 00111 inline bool mine (); 00112 /*Des*/ ~OwnedMutex (); 00113 }; 00114 00115 class Thread : public virtual BaseObject { 00116 protected: 00117 explicit Thread (const String &name); 00118 virtual void run () = 0; 00119 virtual ~Thread (); 00120 public: 00121 void start (); 00122 int pid () const; 00123 String name () const; 00124 void queue_abort (); 00125 void abort (); 00126 bool aborted (); 00127 void wakeup (); 00128 bool running (); 00129 void wait_for_exit (); 00130 int last_affinity () const; 00131 int affinity (int cpu = -1); 00132 /* event loop */ 00133 void exec_loop (); 00134 void quit_loop (); 00135 /* global methods */ 00136 static void emit_wakeups (uint64 stamp); 00137 static Thread& self (); 00138 static int online_cpus (); 00139 /* Self thread */ 00140 struct Self { 00141 static String name (); 00142 static void name (const String &name); 00143 static bool sleep (long max_useconds); 00144 static bool aborted (); 00145 static int affinity (int cpu = -1); 00146 static int pid (); 00147 static void awake_after (uint64 stamp); 00148 static void set_wakeup (RapicornThreadWakeup wakeup_func, 00149 void *wakeup_data, 00150 void (*destroy_data) (void*)); 00151 static OwnedMutex& owned_mutex (); 00152 static void yield (); 00153 static void exit (void *retval = NULL) RAPICORN_NORETURN; 00154 }; 00155 /* DataListContainer API */ 00156 template<typename Type> inline void set_data (DataKey<Type> *key, 00157 Type data) { thread_lock(); data_list.set (key, data); thread_unlock(); } 00158 template<typename Type> inline Type get_data (DataKey<Type> *key) { thread_lock(); Type d = data_list.get (key); thread_unlock(); return d; } 00159 template<typename Type> inline Type swap_data (DataKey<Type> *key) { thread_lock(); Type d = data_list.swap (key); thread_unlock(); return d; } 00160 template<typename Type> inline Type swap_data (DataKey<Type> *key, 00161 Type data) { thread_lock(); Type d = data_list.swap (key, data); thread_unlock(); return d; } 00162 template<typename Type> inline void delete_data (DataKey<Type> *key) { thread_lock(); data_list.del (key); thread_unlock(); } 00163 /* implementaiton details */ 00164 private: 00165 DataList data_list; 00166 RapicornThread *bthread; 00167 OwnedMutex m_omutex; 00168 int last_cpu; 00169 explicit Thread (RapicornThread *thread); 00170 void thread_lock () { m_omutex.lock(); } 00171 bool thread_trylock () { return m_omutex.trylock(); } 00172 void thread_unlock () { m_omutex.unlock(); } 00173 protected: 00174 class ThreadWrapperInternal; 00175 static void threadxx_wrap (RapicornThread *cthread); 00176 static void threadxx_delete (void *cxxthread); 00177 }; 00178 00179 enum LockState { BALANCED = 0, AUTOLOCK = 1 }; 00180 00189 template<class MUTEX> 00190 class ScopedLock : protected NonCopyable { 00191 MUTEX &m_mutex; 00192 volatile int m_count; 00193 public: 00194 inline ~ScopedLock () { while (m_count < 0) lock(); while (m_count > 0) unlock(); } 00195 inline void lock () { m_mutex.lock(); m_count++; } 00196 inline void unlock () { m_count--; m_mutex.unlock(); } 00197 inline ScopedLock (MUTEX &mutex, LockState lockstate = AUTOLOCK) : 00198 m_mutex (mutex), m_count (0) 00199 { if (lockstate == AUTOLOCK) lock(); } 00200 }; 00201 00202 namespace Atomic { 00203 00204 template<typename T> 00205 class RingBuffer : protected NonCopyable { 00206 const uint m_size; 00207 T *m_buffer; 00208 volatile uint m_wmark, m_rmark; 00209 public: 00210 explicit 00211 RingBuffer (uint bsize) : 00212 m_size (bsize + 1), m_wmark (0), m_rmark (bsize) 00213 { 00214 m_buffer = new T[m_size]; 00215 Atomic::set (&m_wmark, 0); 00216 Atomic::set (&m_rmark, 0); 00217 } 00218 ~RingBuffer() 00219 { 00220 // Atomic::set (&m_size, 0); 00221 Atomic::set (&m_rmark, 0); 00222 Atomic::set (&m_wmark, 0); 00223 delete[] m_buffer; 00224 } 00225 uint 00226 n_writable() 00227 { 00228 const uint rm = Atomic::get (&m_rmark); 00229 const uint wm = Atomic::get (&m_wmark); 00230 uint space = (m_size - 1 + rm - wm) % m_size; 00231 return space; 00232 } 00233 uint 00234 write (uint length, 00235 const T *data, 00236 bool partial = true) 00237 { 00238 const uint orig_length = length; 00239 const uint rm = Atomic::get (&m_rmark); 00240 uint wm = Atomic::get (&m_wmark); 00241 uint space = (m_size - 1 + rm - wm) % m_size; 00242 if (!partial && length > space) 00243 return 0; 00244 while (length) 00245 { 00246 if (rm <= wm) 00247 space = m_size - wm + (rm == 0 ? -1 : 0); 00248 else 00249 space = rm - wm -1; 00250 if (!space) 00251 break; 00252 space = MIN (space, length); 00253 std::copy (data, &data[space], &m_buffer[wm]); 00254 wm = (wm + space) % m_size; 00255 data += space; 00256 length -= space; 00257 } 00258 Atomic::write_barrier(); 00259 /* the write barrier ensures m_buffer writes are made visible before the m_wmark update */ 00260 Atomic::set (&m_wmark, wm); 00261 return orig_length - length; 00262 } 00263 uint 00264 n_readable() 00265 { 00266 const uint wm = Atomic::get (&m_wmark); 00267 const uint rm = Atomic::get (&m_rmark); 00268 uint space = (m_size + wm - rm) % m_size; 00269 return space; 00270 } 00271 uint 00272 read (uint length, 00273 T *data, 00274 bool partial = true) 00275 { 00276 const uint orig_length = length; 00277 Atomic::read_barrier(); 00278 /* the read barrier ensures m_buffer writes are seen before m_wmark updates */ 00279 const uint wm = Atomic::get (&m_wmark); 00280 uint rm = Atomic::get (&m_rmark); 00281 uint space = (m_size + wm - rm) % m_size; 00282 if (!partial && length > space) 00283 return 0; 00284 while (length) 00285 { 00286 if (wm < rm) 00287 space = m_size - rm; 00288 else 00289 space = wm - rm; 00290 if (!space) 00291 break; 00292 space = MIN (space, length); 00293 std::copy (&m_buffer[rm], &m_buffer[rm + space], data); 00294 rm = (rm + space) % m_size; 00295 data += space; 00296 length -= space; 00297 } 00298 Atomic::set (&m_rmark, rm); 00299 return orig_length - length; 00300 } 00301 }; 00302 00303 } // Atomic 00304 00305 /* --- implementation --- */ 00306 inline void 00307 OwnedMutex::lock () 00308 { 00309 m_rec_mutex.lock(); 00310 Atomic::ptr_set (&m_owner, &Thread::self()); 00311 m_count++; 00312 } 00313 00314 inline bool 00315 OwnedMutex::trylock () 00316 { 00317 if (m_rec_mutex.trylock()) 00318 { 00319 Atomic::ptr_set (&m_owner, &Thread::self()); 00320 m_count++; 00321 return true; /* TRUE indicates success */ 00322 } 00323 else 00324 return false; 00325 } 00326 00327 inline void 00328 OwnedMutex::unlock () 00329 { 00330 if (--m_count == 0) 00331 Atomic::ptr_set (&m_owner, (Thread*) 0); 00332 m_rec_mutex.unlock(); 00333 } 00334 00335 inline Thread* 00336 OwnedMutex::owner () 00337 { 00338 return Atomic::ptr_get (&m_owner); 00339 } 00340 00341 inline bool 00342 OwnedMutex::mine () 00343 { 00344 return Atomic::ptr_get (&m_owner) == &Thread::self(); 00345 } 00346 00347 void once_list_enter (); 00348 bool once_list_bounce (volatile void *ptr); 00349 bool once_list_leave (volatile void *ptr); 00350 00351 template<class Value> inline bool 00352 once_enter (volatile Value *value_location) 00353 { 00354 if (RAPICORN_LIKELY (Atomic::value_get (value_location) != 0)) 00355 return false; 00356 else 00357 { 00358 once_list_enter(); 00359 const bool initialized = Atomic::value_get (value_location) != 0; 00360 const bool needs_init = once_list_bounce (initialized ? NULL : value_location); 00361 return needs_init; 00362 } 00363 } 00364 00365 template<class Value> inline void 00366 once_leave (volatile Value *value_location, 00367 Value initialization_value) 00368 { 00369 RAPICORN_RETURN_IF_FAIL (Atomic::value_get (value_location) == 0); 00370 RAPICORN_RETURN_IF_FAIL (initialization_value != 0); 00371 00372 Atomic::value_set (value_location, initialization_value); 00373 const bool found_and_removed = once_list_leave (value_location); 00374 RAPICORN_RETURN_IF_FAIL (found_and_removed == true); 00375 } 00376 00377 } // Rapicorn 00378 00379 #endif /* __RAPICORN_THREAD_XX_HH__ */ 00380 00381 /* vim:set ts=8 sts=2 sw=2: */
1.7.4