1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/vm/PosixNSPR.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,360 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- 1.5 + * vim: set ts=8 sts=4 et sw=4 tw=99: 1.6 + * This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +#include "vm/PosixNSPR.h" 1.11 + 1.12 +#include "js/Utility.h" 1.13 + 1.14 +#ifdef JS_POSIX_NSPR 1.15 + 1.16 +#include <errno.h> 1.17 +#include <sys/time.h> 1.18 +#include <time.h> 1.19 + 1.20 +#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) 1.21 +#include <pthread_np.h> 1.22 +#endif 1.23 + 1.24 +class nspr::Thread 1.25 +{ 1.26 + pthread_t pthread_; 1.27 + void (*start)(void *arg); 1.28 + void *arg; 1.29 + bool joinable; 1.30 + 1.31 + public: 1.32 + Thread(void (*start)(void *arg), void *arg, bool joinable) 1.33 + : start(start), arg(arg), joinable(joinable) {} 1.34 + 1.35 + static void *ThreadRoutine(void *arg); 1.36 + 1.37 + pthread_t &pthread() { return pthread_; } 1.38 +}; 1.39 + 1.40 +static pthread_key_t gSelfThreadIndex; 1.41 +static nspr::Thread gMainThread(nullptr, nullptr, false); 1.42 + 1.43 +void * 1.44 +nspr::Thread::ThreadRoutine(void *arg) 1.45 +{ 1.46 + Thread *self = static_cast<Thread *>(arg); 1.47 + pthread_setspecific(gSelfThreadIndex, self); 1.48 + self->start(self->arg); 1.49 + if (!self->joinable) 1.50 + js_delete(self); 1.51 + return nullptr; 1.52 +} 1.53 + 1.54 +static bool gInitialized; 1.55 + 1.56 +void 1.57 +DummyDestructor(void *) 1.58 +{ 1.59 +} 1.60 + 1.61 +/* Should be called from the main thread. */ 1.62 +static void 1.63 +Initialize() 1.64 +{ 1.65 + gInitialized = true; 1.66 + 1.67 + if (pthread_key_create(&gSelfThreadIndex, DummyDestructor)) { 1.68 + MOZ_CRASH(); 1.69 + return; 1.70 + } 1.71 + 1.72 + pthread_setspecific(gSelfThreadIndex, &gMainThread); 1.73 +} 1.74 + 1.75 +PRThread * 1.76 +PR_CreateThread(PRThreadType type, 1.77 + void (*start)(void *arg), 1.78 + void *arg, 1.79 + PRThreadPriority priority, 1.80 + PRThreadScope scope, 1.81 + PRThreadState state, 1.82 + uint32_t stackSize) 1.83 +{ 1.84 + JS_ASSERT(type == PR_USER_THREAD); 1.85 + JS_ASSERT(priority == PR_PRIORITY_NORMAL); 1.86 + 1.87 + if (!gInitialized) { 1.88 + /* 1.89 + * We assume that the first call to PR_CreateThread happens on the main 1.90 + * thread. 1.91 + */ 1.92 + Initialize(); 1.93 + } 1.94 + 1.95 + pthread_attr_t attr; 1.96 + if (pthread_attr_init(&attr)) 1.97 + return nullptr; 1.98 + 1.99 + if (stackSize && pthread_attr_setstacksize(&attr, stackSize)) { 1.100 + pthread_attr_destroy(&attr); 1.101 + return nullptr; 1.102 + } 1.103 + 1.104 + nspr::Thread *t = js_new<nspr::Thread>(start, arg, 1.105 + state != PR_UNJOINABLE_THREAD); 1.106 + if (!t) { 1.107 + pthread_attr_destroy(&attr); 1.108 + return nullptr; 1.109 + } 1.110 + 1.111 + if (pthread_create(&t->pthread(), &attr, &nspr::Thread::ThreadRoutine, t)) { 1.112 + pthread_attr_destroy(&attr); 1.113 + js_delete(t); 1.114 + return nullptr; 1.115 + } 1.116 + 1.117 + if (state == PR_UNJOINABLE_THREAD) { 1.118 + if (pthread_detach(t->pthread())) { 1.119 + pthread_attr_destroy(&attr); 1.120 + js_delete(t); 1.121 + return nullptr; 1.122 + } 1.123 + } 1.124 + 1.125 + pthread_attr_destroy(&attr); 1.126 + 1.127 + return t; 1.128 +} 1.129 + 1.130 +PRStatus 1.131 +PR_JoinThread(PRThread *thread) 1.132 +{ 1.133 + if (pthread_join(thread->pthread(), nullptr)) 1.134 + return PR_FAILURE; 1.135 + 1.136 + js_delete(thread); 1.137 + 1.138 + return PR_SUCCESS; 1.139 +} 1.140 + 1.141 +PRThread * 1.142 +PR_GetCurrentThread() 1.143 +{ 1.144 + if (!gInitialized) 1.145 + Initialize(); 1.146 + 1.147 + return (PRThread *)pthread_getspecific(gSelfThreadIndex); 1.148 +} 1.149 + 1.150 +PRStatus 1.151 +PR_SetCurrentThreadName(const char *name) 1.152 +{ 1.153 + int result; 1.154 +#ifdef XP_MACOSX 1.155 + result = pthread_setname_np(name); 1.156 +#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) 1.157 + pthread_set_name_np(pthread_self(), name); 1.158 + result = 0; 1.159 +#elif defined(__NetBSD__) 1.160 + result = pthread_setname_np(pthread_self(), "%s", (void *)name); 1.161 +#else 1.162 + result = pthread_setname_np(pthread_self(), name); 1.163 +#endif 1.164 + if (result) 1.165 + return PR_FAILURE; 1.166 + return PR_SUCCESS; 1.167 +} 1.168 + 1.169 +static const size_t MaxTLSKeyCount = 32; 1.170 +static size_t gTLSKeyCount; 1.171 +static pthread_key_t gTLSKeys[MaxTLSKeyCount]; 1.172 + 1.173 +PRStatus 1.174 +PR_NewThreadPrivateIndex(unsigned *newIndex, PRThreadPrivateDTOR destructor) 1.175 +{ 1.176 + /* 1.177 + * We only call PR_NewThreadPrivateIndex from the main thread, so there's no 1.178 + * need to lock the table of TLS keys. 1.179 + */ 1.180 + JS_ASSERT(PR_GetCurrentThread() == &gMainThread); 1.181 + 1.182 + pthread_key_t key; 1.183 + if (pthread_key_create(&key, destructor)) 1.184 + return PR_FAILURE; 1.185 + 1.186 + JS_ASSERT(gTLSKeyCount + 1 < MaxTLSKeyCount); 1.187 + 1.188 + gTLSKeys[gTLSKeyCount] = key; 1.189 + *newIndex = gTLSKeyCount; 1.190 + gTLSKeyCount++; 1.191 + 1.192 + return PR_SUCCESS; 1.193 +} 1.194 + 1.195 +PRStatus 1.196 +PR_SetThreadPrivate(unsigned index, void *priv) 1.197 +{ 1.198 + if (index >= gTLSKeyCount) 1.199 + return PR_FAILURE; 1.200 + if (pthread_setspecific(gTLSKeys[index], priv)) 1.201 + return PR_FAILURE; 1.202 + return PR_SUCCESS; 1.203 +} 1.204 + 1.205 +void * 1.206 +PR_GetThreadPrivate(unsigned index) 1.207 +{ 1.208 + if (index >= gTLSKeyCount) 1.209 + return nullptr; 1.210 + return pthread_getspecific(gTLSKeys[index]); 1.211 +} 1.212 + 1.213 +PRStatus 1.214 +PR_CallOnce(PRCallOnceType *once, PRCallOnceFN func) 1.215 +{ 1.216 + MOZ_ASSUME_UNREACHABLE("PR_CallOnce unimplemented"); 1.217 +} 1.218 + 1.219 +PRStatus 1.220 +PR_CallOnceWithArg(PRCallOnceType *once, PRCallOnceWithArgFN func, void *arg) 1.221 +{ 1.222 + MOZ_ASSUME_UNREACHABLE("PR_CallOnceWithArg unimplemented"); 1.223 +} 1.224 + 1.225 +class nspr::Lock 1.226 +{ 1.227 + pthread_mutex_t mutex_; 1.228 + 1.229 + public: 1.230 + Lock() {} 1.231 + pthread_mutex_t &mutex() { return mutex_; } 1.232 +}; 1.233 + 1.234 +PRLock * 1.235 +PR_NewLock() 1.236 +{ 1.237 + nspr::Lock *lock = js_new<nspr::Lock>(); 1.238 + if (!lock) 1.239 + return nullptr; 1.240 + 1.241 + if (pthread_mutex_init(&lock->mutex(), nullptr)) { 1.242 + js_delete(lock); 1.243 + return nullptr; 1.244 + } 1.245 + 1.246 + return lock; 1.247 +} 1.248 + 1.249 +void 1.250 +PR_DestroyLock(PRLock *lock) 1.251 +{ 1.252 + pthread_mutex_destroy(&lock->mutex()); 1.253 + js_delete(lock); 1.254 +} 1.255 + 1.256 +void 1.257 +PR_Lock(PRLock *lock) 1.258 +{ 1.259 + pthread_mutex_lock(&lock->mutex()); 1.260 +} 1.261 + 1.262 +PRStatus 1.263 +PR_Unlock(PRLock *lock) 1.264 +{ 1.265 + if (pthread_mutex_unlock(&lock->mutex())) 1.266 + return PR_FAILURE; 1.267 + return PR_SUCCESS; 1.268 +} 1.269 + 1.270 +class nspr::CondVar 1.271 +{ 1.272 + pthread_cond_t cond_; 1.273 + nspr::Lock *lock_; 1.274 + 1.275 + public: 1.276 + CondVar(nspr::Lock *lock) : lock_(lock) {} 1.277 + pthread_cond_t &cond() { return cond_; } 1.278 + nspr::Lock *lock() { return lock_; } 1.279 +}; 1.280 + 1.281 +PRCondVar * 1.282 +PR_NewCondVar(PRLock *lock) 1.283 +{ 1.284 + nspr::CondVar *cvar = js_new<nspr::CondVar>(lock); 1.285 + if (!cvar) 1.286 + return nullptr; 1.287 + 1.288 + if (pthread_cond_init(&cvar->cond(), nullptr)) { 1.289 + js_delete(cvar); 1.290 + return nullptr; 1.291 + } 1.292 + 1.293 + return cvar; 1.294 +} 1.295 + 1.296 +void 1.297 +PR_DestroyCondVar(PRCondVar *cvar) 1.298 +{ 1.299 + pthread_cond_destroy(&cvar->cond()); 1.300 + js_delete(cvar); 1.301 +} 1.302 + 1.303 +PRStatus 1.304 +PR_NotifyCondVar(PRCondVar *cvar) 1.305 +{ 1.306 + if (pthread_cond_signal(&cvar->cond())) 1.307 + return PR_FAILURE; 1.308 + return PR_SUCCESS; 1.309 +} 1.310 + 1.311 +PRStatus 1.312 +PR_NotifyAllCondVar(PRCondVar *cvar) 1.313 +{ 1.314 + if (pthread_cond_broadcast(&cvar->cond())) 1.315 + return PR_FAILURE; 1.316 + return PR_SUCCESS; 1.317 +} 1.318 + 1.319 +uint32_t 1.320 +PR_MillisecondsToInterval(uint32_t milli) 1.321 +{ 1.322 + return milli; 1.323 +} 1.324 + 1.325 +static const uint64_t TicksPerSecond = 1000; 1.326 +static const uint64_t NanoSecondsInSeconds = 1000000000; 1.327 +static const uint64_t MicroSecondsInSeconds = 1000000; 1.328 + 1.329 +uint32_t 1.330 +PR_TicksPerSecond() 1.331 +{ 1.332 + return TicksPerSecond; 1.333 +} 1.334 + 1.335 +PRStatus 1.336 +PR_WaitCondVar(PRCondVar *cvar, uint32_t timeout) 1.337 +{ 1.338 + if (timeout == PR_INTERVAL_NO_TIMEOUT) { 1.339 + if (pthread_cond_wait(&cvar->cond(), &cvar->lock()->mutex())) 1.340 + return PR_FAILURE; 1.341 + return PR_SUCCESS; 1.342 + } else { 1.343 + struct timespec ts; 1.344 + struct timeval tv; 1.345 + 1.346 + gettimeofday(&tv, nullptr); 1.347 + ts.tv_sec = tv.tv_sec; 1.348 + ts.tv_nsec = tv.tv_usec * (NanoSecondsInSeconds / MicroSecondsInSeconds); 1.349 + 1.350 + ts.tv_nsec += timeout * (NanoSecondsInSeconds / TicksPerSecond); 1.351 + while (uint64_t(ts.tv_nsec) >= NanoSecondsInSeconds) { 1.352 + ts.tv_nsec -= NanoSecondsInSeconds; 1.353 + ts.tv_sec++; 1.354 + } 1.355 + 1.356 + int result = pthread_cond_timedwait(&cvar->cond(), &cvar->lock()->mutex(), &ts); 1.357 + if (result == 0 || result == ETIMEDOUT) 1.358 + return PR_SUCCESS; 1.359 + return PR_FAILURE; 1.360 + } 1.361 +} 1.362 + 1.363 +#endif /* JS_POSIX_NSPR */