1 #pragma once
2 
3 
4 #include <memory>
5 #include <string>
6 #include <type_traits>
7 #include <utility>
8 #include <uv.h>
9 #include "loop.hpp"
10 #include "underlying_type.hpp"
11 
12 
13 namespace uvw {
14 
15 
16 class Thread;
17 class ThreadLocalStorage;
18 class Once;
19 class Mutex;
20 class RWLock;
21 class Semaphore;
22 class Condition;
23 class Barrier;
24 
25 
26 class Thread final: public UnderlyingType<Thread, uv_thread_t> {
27     using InternalTask = std::function<void(std::shared_ptr<void>)>;
28 
createCallback(void * arg)29     static void createCallback(void *arg) {
30         Thread &thread = *(static_cast<Thread*>(arg));
31         thread.task(thread.data);
32     }
33 
34 public:
35     using Task = InternalTask;
36     using Type = uv_thread_t;
37 
Thread(ConstructorAccess ca,std::shared_ptr<Loop> ref,InternalTask t,std::shared_ptr<void> d=nullptr)38     explicit Thread(ConstructorAccess ca, std::shared_ptr<Loop> ref, InternalTask t, std::shared_ptr<void> d = nullptr) noexcept
39         : UnderlyingType{ca, std::move(ref)}, data{std::move(d)}, task{std::move(t)}
40     {}
41 
self()42     static Type self() noexcept {
43         return uv_thread_self();
44     }
45 
equal(const Thread & tl,const Thread & tr)46     static bool equal(const Thread &tl, const Thread &tr) noexcept {
47         return !(0 == uv_thread_equal(tl.get(), tr.get()));
48     }
49 
~Thread()50     ~Thread() noexcept {
51         join();
52     }
53 
run()54     bool run() noexcept {
55         return (0 == uv_thread_create(get(), &createCallback, this));
56     }
57 
join()58     bool join() noexcept {
59         return (0 == uv_thread_join(get()));
60     }
61 
62 private:
63     std::shared_ptr<void> data;
64     Task task;
65 };
66 
67 
68 class ThreadLocalStorage final: public UnderlyingType<ThreadLocalStorage, uv_key_t> {
69 public:
ThreadLocalStorage(ConstructorAccess ca,std::shared_ptr<Loop> ref)70     explicit ThreadLocalStorage(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
71         : UnderlyingType{ca, std::move(ref)}
72     {
73         uv_key_create(UnderlyingType::get());
74     }
75 
~ThreadLocalStorage()76     ~ThreadLocalStorage() noexcept {
77         uv_key_delete(UnderlyingType::get());
78     }
79 
80     template<typename T>
get()81     T* get() noexcept {
82         return static_cast<T*>(uv_key_get(UnderlyingType::get()));
83     }
84 
85     template<typename T>
set(T * value)86     void set(T *value) noexcept {
87         return uv_key_set(UnderlyingType::get(), value);
88     }
89 };
90 
91 
92 // `Once` is an odd one as it doesn't use a `libuv` structure per object.
93 class Once final: public UnderlyingType<Once, uv_once_t> {
guard()94     static uv_once_t* guard() noexcept {
95         static uv_once_t once = UV_ONCE_INIT;
96         return &once;
97     }
98 
99 public:
100     using UnderlyingType::UnderlyingType;
101 
102     template<typename F>
once(F && f)103     static void once(F &&f) noexcept {
104         using CallbackType = void (*)(void);
105         static_assert(std::is_convertible<F, CallbackType>::value, "!");
106         CallbackType cb = f;
107         uv_once(guard(), cb);
108     }
109 };
110 
111 
112 class Mutex final: public UnderlyingType<Mutex, uv_mutex_t> {
113     friend class Condition;
114 
115 public:
Mutex(ConstructorAccess ca,std::shared_ptr<Loop> ref,bool recursive=false)116     explicit Mutex(ConstructorAccess ca, std::shared_ptr<Loop> ref, bool recursive = false) noexcept
117         : UnderlyingType{ca, std::move(ref)}
118     {
119         if(recursive) {
120             uv_mutex_init_recursive(get());
121         } else {
122             uv_mutex_init(get());
123         }
124     }
125 
~Mutex()126     ~Mutex() noexcept {
127         uv_mutex_destroy(get());
128     }
129 
lock()130     void lock() noexcept {
131         uv_mutex_lock(get());
132     }
133 
tryLock()134     bool tryLock() noexcept {
135         return (0 == uv_mutex_trylock(get()));
136     }
137 
unlock()138     void unlock() noexcept {
139         uv_mutex_unlock(get());
140     }
141 };
142 
143 
144 class RWLock final: public UnderlyingType<RWLock, uv_rwlock_t> {
145 public:
RWLock(ConstructorAccess ca,std::shared_ptr<Loop> ref)146     explicit RWLock(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
147         : UnderlyingType{ca, std::move(ref)}
148     {
149         uv_rwlock_init(get());
150     }
151 
~RWLock()152     ~RWLock() noexcept {
153         uv_rwlock_destroy(get());
154     }
155 
rdLock()156     void rdLock() noexcept {
157         uv_rwlock_rdlock(get());
158     }
159 
tryRdLock()160     bool tryRdLock() noexcept {
161         return (0 == uv_rwlock_tryrdlock(get()));
162     }
163 
rdUnlock()164     void rdUnlock() noexcept {
165         uv_rwlock_rdunlock(get());
166     }
167 
wrLock()168     void wrLock() noexcept {
169         uv_rwlock_wrlock(get());
170     }
171 
tryWrLock()172     bool tryWrLock() noexcept {
173         return (0 == uv_rwlock_trywrlock(get()));
174     }
175 
wrUnlock()176     void wrUnlock() noexcept {
177         uv_rwlock_wrunlock(get());
178     }
179 };
180 
181 
182 class Semaphore final: public UnderlyingType<Semaphore, uv_sem_t> {
183 public:
Semaphore(ConstructorAccess ca,std::shared_ptr<Loop> ref,unsigned int value)184     explicit Semaphore(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int value) noexcept
185         : UnderlyingType{ca, std::move(ref)}
186     {
187         uv_sem_init(get(), value);
188     }
189 
~Semaphore()190     ~Semaphore() noexcept {
191         uv_sem_destroy(get());
192     }
193 
post()194     void post() noexcept {
195         uv_sem_post(get());
196     }
197 
wait()198     void wait() noexcept {
199         uv_sem_wait(get());
200     }
201 
tryWait()202     bool tryWait() noexcept {
203         return (0 == uv_sem_trywait(get()));
204     }
205 };
206 
207 
208 class Condition final: public UnderlyingType<Condition, uv_cond_t> {
209 public:
Condition(ConstructorAccess ca,std::shared_ptr<Loop> ref)210     explicit Condition(ConstructorAccess ca, std::shared_ptr<Loop> ref) noexcept
211         : UnderlyingType{ca, std::move(ref)}
212     {
213         uv_cond_init(get());
214     }
215 
~Condition()216     ~Condition() noexcept {
217         uv_cond_destroy(get());
218     }
219 
signal()220     void signal() noexcept {
221         uv_cond_signal(get());
222     }
223 
broadcast()224     void broadcast() noexcept {
225         uv_cond_broadcast(get());
226     }
227 
wait(Mutex & mutex)228     void wait(Mutex &mutex) noexcept {
229         uv_cond_wait(get(), mutex.get());
230     }
231 
timedWait(Mutex & mutex,uint64_t timeout)232     bool timedWait(Mutex &mutex, uint64_t timeout) noexcept {
233         return (0 == uv_cond_timedwait(get(), mutex.get(), timeout));
234     }
235 };
236 
237 
238 class Barrier final: public UnderlyingType<Barrier, uv_barrier_t> {
239 public:
Barrier(ConstructorAccess ca,std::shared_ptr<Loop> ref,unsigned int count)240     explicit Barrier(ConstructorAccess ca, std::shared_ptr<Loop> ref, unsigned int count) noexcept
241         : UnderlyingType{ca, std::move(ref)}
242     {
243         uv_barrier_init(get(), count);
244     }
245 
~Barrier()246     ~Barrier() noexcept {
247         uv_barrier_destroy(get());
248     }
249 
wait()250     bool wait() noexcept {
251         return (0 == uv_barrier_wait(get()));
252     }
253 };
254 
255 
256 }
257