1 /* This file is part of Jellyfish. 2 3 This work is dual-licensed under 3-Clause BSD License or GPL 3.0. 4 You can choose between one of them if you use this work. 5 6 `SPDX-License-Identifier: BSD-3-Clause OR GPL-3.0` 7 */ 8 9 10 #ifndef __JELLYFISH_LOCKS_PTHREAD_HPP__ 11 #define __JELLYFISH_LOCKS_PTHREAD_HPP__ 12 13 #include <time.h> 14 #include <sys/time.h> 15 #include <pthread.h> 16 #ifdef HAVE_CONFIG_H 17 #include <config.h> 18 #endif 19 20 namespace jellyfish { namespace locks{ namespace pthread { 21 class cond 22 { 23 pthread_mutex_t _mutex; 24 pthread_cond_t _cond; 25 26 public: cond()27 cond() { 28 pthread_mutex_init(&_mutex, NULL); 29 pthread_cond_init(&_cond, NULL); 30 } 31 ~cond()32 ~cond() { 33 pthread_cond_destroy(&_cond); 34 pthread_mutex_destroy(&_mutex); 35 } 36 lock()37 inline void lock() { pthread_mutex_lock(&_mutex); } unlock()38 inline void unlock() { pthread_mutex_unlock(&_mutex); } wait()39 inline void wait() { pthread_cond_wait(&_cond, &_mutex); } signal()40 inline void signal() { pthread_cond_signal(&_cond); } broadcast()41 inline void broadcast() { pthread_cond_broadcast(&_cond); } timedwait(struct timespec * abstime)42 inline int timedwait(struct timespec *abstime) { 43 return pthread_cond_timedwait(&_cond, &_mutex, abstime); 44 } timedwait(time_t seconds)45 inline int timedwait(time_t seconds) { 46 struct timespec curtime; 47 #ifdef HAVE_CLOCK_GETTIME 48 clock_gettime(CLOCK_REALTIME, &curtime); 49 #else 50 struct timeval timeofday; 51 gettimeofday(&timeofday, 0); 52 curtime.tv_sec = timeofday.tv_sec; 53 curtime.tv_nsec = timeofday.tv_usec * 1000; 54 #endif 55 curtime.tv_sec += seconds; 56 return timedwait(&curtime); 57 } 58 }; 59 60 class mutex { 61 pthread_mutex_t _mutex; 62 63 public: mutex(int type=PTHREAD_MUTEX_DEFAULT)64 mutex(int type = PTHREAD_MUTEX_DEFAULT) { 65 pthread_mutexattr_t attr; 66 pthread_mutexattr_init(&attr); 67 pthread_mutexattr_settype(&attr, type); 68 pthread_mutex_init(&_mutex, &attr); 69 } 70 ~mutex()71 ~mutex() { 72 pthread_mutex_destroy(&_mutex); 73 } 74 lock()75 inline void lock() { pthread_mutex_lock(&_mutex); } unlock()76 inline void unlock() { pthread_mutex_unlock(&_mutex); } try_lock()77 inline bool try_lock() { return !pthread_mutex_trylock(&_mutex); } 78 }; 79 80 class mutex_recursive : public mutex { 81 public: mutex_recursive()82 mutex_recursive() : mutex(PTHREAD_MUTEX_RECURSIVE) { } 83 }; 84 85 class mutex_lock { 86 mutex& m_; 87 public: mutex_lock(mutex & m)88 explicit mutex_lock(mutex& m) : m_(m) { m_.lock(); } ~mutex_lock()89 ~mutex_lock() { m_.unlock(); } 90 }; 91 92 class Semaphore { 93 int _value, _wakeups; 94 cond _cv; 95 public: Semaphore(int value)96 explicit Semaphore(int value) : 97 _value(value), 98 _wakeups(0) 99 { 100 // nothing to do 101 } 102 ~Semaphore()103 ~Semaphore() {} 104 wait()105 inline void wait() { 106 _cv.lock(); 107 _value--; 108 if (_value < 0) { 109 do { 110 _cv.wait(); 111 } while(_wakeups < 1); 112 _wakeups--; 113 } 114 _cv.unlock(); 115 } 116 signal()117 inline void signal() { 118 _cv.lock(); 119 _value++; 120 if(_value <= 0) { 121 _wakeups++; 122 _cv.signal(); 123 } 124 _cv.unlock(); 125 } 126 }; 127 128 #if defined(_POSIX_BARRIERS) && (_POSIX_BARRIERS - 20012L) >= 0 129 class barrier 130 { 131 pthread_barrier_t _barrier; 132 133 public: barrier(unsigned count)134 explicit barrier(unsigned count) { 135 136 pthread_barrier_init(&_barrier, NULL, count); 137 } 138 ~barrier()139 ~barrier() { 140 pthread_barrier_destroy(&_barrier); 141 } 142 143 /// Return true if serial thread. wait()144 inline bool wait() { 145 return pthread_barrier_wait(&_barrier) == PTHREAD_BARRIER_SERIAL_THREAD; 146 } 147 }; 148 149 #else 150 // # ifndef PTHREAD_BARRIER_SERIAL_THREAD 151 // # define PTHREAD_BARRIER_SERIAL_THREAD 1 152 // # endif 153 154 class barrier 155 { 156 int count; // required # of threads 157 int current; // current # of threads that have passed thru 158 mutex barlock; // protect current 159 Semaphore barrier1; // implement the barrier 160 Semaphore barrier2; 161 162 public: barrier(unsigned cnt)163 explicit barrier(unsigned cnt) 164 : count(cnt), current(0), barrier1(0), barrier2(0) { 165 } 166 ~barrier()167 ~barrier() {} 168 wait()169 inline bool wait() { 170 bool ret = false; 171 barlock.lock(); 172 current += 1; 173 if(current == count) { 174 ret = true; 175 for(int i=0; i<count;i++) { 176 barrier1.signal(); 177 } 178 } 179 barlock.unlock(); 180 barrier1.wait(); // wait for n threads to arrive 181 182 barlock.lock(); 183 current -= 1; 184 if(current == 0) { 185 for(int i=0;i<count;i++) { 186 barrier2.signal(); 187 } 188 } 189 barlock.unlock(); 190 barrier2.wait(); 191 return ret; 192 } 193 }; 194 195 #endif 196 } //namespace pthread { 197 198 typedef pthread::cond cond; 199 typedef pthread::mutex mutex; 200 typedef pthread::barrier barrier; 201 } } // namespace jellyfish { namespace { locks 202 203 #endif /* __JELLYFISH_LOCKS_PTHREAD_HPP__ */ 204