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