PFUNC
1.0
|
00001 #ifndef PFUNC_MUTEX_HPP 00002 #define PFUNC_MUTEX_HPP 00003 00010 #include <pfunc/config.h> 00011 #include <pfunc/pfunc_common.h> 00012 #include <pfunc/no_copy.hpp> 00013 #include <pfunc/exception.hpp> 00014 #include <pfunc/pfunc_atomics.h> 00015 #include <pfunc/environ.hpp> 00016 00017 #if PFUNC_HAVE_ERRNO_H == 1 00018 #include <errno.h> 00019 #endif 00020 00021 #if PFUNC_HAVE_FUTEX == 1 00022 #include <pfunc/futex.h> 00023 00024 /* 00025 * TODO: There is an assumption here that int is 32-bits. Need to change this 00026 */ 00027 00028 namespace pfunc { 00029 struct mutex : public detail::no_copy { 00030 private: 00031 ALIGN64 int val; 00032 static const int PFUNC_MUTEX_FREE = 0x0; 00033 static const int PFUNC_MUTEX_LOCKED = 0x1; 00034 static const int PFUNC_MUTEX_LOCKED_WITH_WAITERS = 0x2; 00035 static const int PFUNC_MAX_RELAXATIONS = 2*1024*1024; /* 2M */ 00036 00037 public: 00038 mutex () : val (PFUNC_MUTEX_FREE) {} 00039 00040 void lock () { 00041 if (PFUNC_MUTEX_FREE != pfunc_compare_and_swap_32 (&val, 00042 PFUNC_MUTEX_LOCKED, 00043 PFUNC_MUTEX_FREE)) { 00044 do { 00045 int oldval = pfunc_compare_and_swap_32 (&val, 00046 PFUNC_MUTEX_LOCKED_WITH_WAITERS, 00047 PFUNC_MUTEX_LOCKED); 00048 if (PFUNC_MUTEX_FREE != oldval) { 00050 for (int i = 0; i < PFUNC_MAX_RELAXATIONS; i++) { 00051 if (PFUNC_MUTEX_LOCKED_WITH_WAITERS == val) cpu_relax (); 00052 else break; 00053 } 00055 futex_wait (reinterpret_cast<int*>(&val), 00056 PFUNC_MUTEX_LOCKED_WITH_WAITERS); 00057 } 00058 } while (PFUNC_MUTEX_FREE != pfunc_compare_and_swap_32 (&val, 00059 PFUNC_MUTEX_LOCKED_WITH_WAITERS, 00060 PFUNC_MUTEX_FREE)); 00061 } 00062 } 00063 00064 bool trylock () { 00065 if (PFUNC_MUTEX_FREE != pfunc_compare_and_swap_32 (&val, 00066 PFUNC_MUTEX_LOCKED, 00067 PFUNC_MUTEX_FREE)) return true; 00068 else return false; 00069 } 00070 00071 void unlock () { 00072 int oldval = pfunc_fetch_and_store_32 (&val, PFUNC_MUTEX_FREE); 00073 if (oldval <= PFUNC_MUTEX_LOCKED) return; 00074 else futex_wake (&val, PFUNC_MUTEX_LOCKED); 00075 } 00076 }; 00077 } /* namespace pfunc */ 00078 00079 #elif PFUNC_HAVE_PTHREADS == 1 00080 00081 namespace pfunc { 00082 struct mutex : public detail::no_copy { 00083 typedef pthread_mutex_t mutex_type; /*< Mutex type */ 00084 mutex_type mtx; 00089 mutex () { 00090 PFUNC_CAPTURE_RETURN_VALUE(error) pthread_mutex_init (&mtx, NULL); 00091 #if PFUNC_USE_EXCEPTIONS == 1 00092 if (error) 00093 throw exception_generic_impl 00094 ("pfunc::detail::mutex::mutex::pthread_mutex_init at " FILE_AND_LINE(), 00095 "Error initializing the mutex", 00096 error); 00097 #endif 00098 } 00099 00103 ~mutex () { 00104 PFUNC_CAPTURE_RETURN_VALUE(error) pthread_mutex_destroy (&mtx); 00105 #if PFUNC_USE_EXCEPTIONS == 1 00106 if (error) 00107 throw exception_generic_impl 00108 ("pfunc::detail::mutex::mutex::pthread_mutex_destroy at " FILE_AND_LINE(), 00109 "Error destroying the mutex", 00110 error); 00111 #endif 00112 } 00113 00117 void lock () { 00118 PFUNC_CAPTURE_RETURN_VALUE(error) pthread_mutex_lock (&mtx); 00119 #if PFUNC_USE_EXCEPTIONS == 1 00120 if (error) 00121 throw exception_generic_impl 00122 ("pfunc::detail::mutex::mutex::pthread_mutex_lock at " FILE_AND_LINE(), 00123 "Error locking the mutex", 00124 error); 00125 #endif 00126 } 00127 00134 bool trylock () { 00135 error_code_type error = pthread_mutex_lock (&mtx); 00136 bool ret_val = false; 00137 if (0 == error) ret_val = true; 00139 #if PFUNC_HAVE_ERRNO_H == 1 00140 else if (EBUSY == error) return false; 00141 #if PFUNC_USE_EXCEPTIONS == 1 00142 else 00143 throw exception_generic_impl 00144 ("pfunc::detail::mutex::mutex::pthread_mutex_trylock at " FILE_AND_LINE(), 00145 "Error trying to lock the mutex", 00146 error); 00147 #endif 00148 #endif 00149 return ret_val; 00150 } 00151 00155 void unlock () { 00156 PFUNC_CAPTURE_RETURN_VALUE(error) pthread_mutex_unlock (&mtx); 00157 #if PFUNC_USE_EXCEPTIONS == 1 00158 if (error) 00159 throw exception_generic_impl 00160 ("pfunc::detail::mutex::mutex::pthread_mutex_unlock at " FILE_AND_LINE(), 00161 "Error unlocking the mutex", 00162 error); 00163 #endif 00164 } 00165 00171 mutex_type& get_internal_mutex () { return mtx; } 00172 }; 00173 00174 } /* namespace pfunc */ 00175 00176 #elif PFUNC_HAVE_WINDOWS_THREADS == 1 00177 00178 namespace pfunc { 00179 struct mutex : public detail::no_copy { 00180 typedef HANDLE mutex_type; /*< Mutex type */ 00181 mutex_type mtx; 00186 mutex () { 00187 mtx = CreateMutex (NULL, /* No security */ 00188 FALSE,/* Unowned */ 00189 NULL);/* Unnamed */ 00190 #if PFUNC_USE_EXCEPTIONS == 1 00191 if (NULL == mtx) 00192 throw exception_generic_impl 00193 ("pfunc::detail::mutex::mutex::CreateMutex at " FILE_AND_LINE(), 00194 "Error initializing the mutex", 00195 GetLastError()); 00196 #endif 00197 } 00198 00202 ~mutex () { 00203 BOOL ret_val = CloseHandle(mtx); 00204 #if PFUNC_USE_EXCEPTIONS == 1 00205 if (FALSE == ret_val) 00206 throw exception_generic_impl 00207 ("pfunc::detail::mutex::mutex::CloseHandle at " FILE_AND_LINE(), 00208 "Error destroying the mutex", 00209 GetLastError()); 00210 #endif 00211 } 00212 00216 void lock () { 00217 error_code_type error = WaitForSingleObject (mtx, INFINITE); 00218 #if PFUNC_USE_EXCEPTIONS == 1 00219 if (WAIT_OBJECT_0 != error) 00220 throw exception_generic_impl 00221 ("pfunc::detail::mutex::lock::WaitForSingleObject at " FILE_AND_LINE(), 00222 "Error locking the mutex", 00223 GetLastError()); 00224 #endif 00225 } 00226 00233 bool trylock () { 00234 DWORD ret_val = WaitForSingleObject (mtx, 0); 00235 if (ret_val == WAIT_OBJECT_0) return true; 00236 else if (ret_val == WAIT_TIMEOUT) return false; 00237 else { 00238 #if PFUNC_USE_EXCEPTIONS == 1 00239 00240 throw exception_generic_impl 00241 ("pfunc::detail::mutex::lock::WaitForSingleObject at " FILE_AND_LINE(), 00242 "Error locking the mutex", 00243 GetLastError()); 00244 #else 00245 00246 return false; 00247 #endif 00248 } 00249 } 00250 00254 void unlock () { 00255 BOOL ret_val = ReleaseMutex (mtx); 00256 #if PFUNC_USE_EXCEPTIONS == 1 00257 if (FALSE == ret_val) 00258 throw exception_generic_impl 00259 ("pfunc::detail::mutex::lock::ReleaseMutex at " FILE_AND_LINE(), 00260 "Error unlocking the mutex", 00261 GetLastError()); 00262 #endif 00263 } 00264 00268 mutex_type& get_internal_mutex () { return mtx; } 00269 }; 00270 } /* namespace pfunc */ 00271 #else 00272 #error "pthreads, windows threads or futexes are required" 00273 #endif 00274 00275 #endif // PFUNC_MUTEX_HPP