js/src/vm/PosixNSPR.cpp

changeset 0
6474c204b198
     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 */

mercurial