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