summaryrefslogtreecommitdiff
path: root/js/src/builtin/AtomicsObject.h
blob: adb6fb986ae9d79656fd843b9665f8e06f74731d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * vim: set ts=8 sts=4 et sw=4 tw=99:
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef builtin_AtomicsObject_h
#define builtin_AtomicsObject_h

#include "mozilla/Maybe.h"
#include "mozilla/TimeStamp.h"

#include "jsobj.h"

#include "threading/ConditionVariable.h"
#include "vm/MutexIDs.h"

namespace js {

class AtomicsObject : public JSObject
{
  public:
    static const Class class_;
    static JSObject* initClass(JSContext* cx, Handle<GlobalObject*> global);
    static MOZ_MUST_USE bool toString(JSContext* cx, unsigned int argc, Value* vp);
};

MOZ_MUST_USE bool atomics_compareExchange(JSContext* cx, unsigned argc, Value* vp);
MOZ_MUST_USE bool atomics_exchange(JSContext* cx, unsigned argc, Value* vp);
MOZ_MUST_USE bool atomics_load(JSContext* cx, unsigned argc, Value* vp);
MOZ_MUST_USE bool atomics_store(JSContext* cx, unsigned argc, Value* vp);
MOZ_MUST_USE bool atomics_add(JSContext* cx, unsigned argc, Value* vp);
MOZ_MUST_USE bool atomics_sub(JSContext* cx, unsigned argc, Value* vp);
MOZ_MUST_USE bool atomics_and(JSContext* cx, unsigned argc, Value* vp);
MOZ_MUST_USE bool atomics_or(JSContext* cx, unsigned argc, Value* vp);
MOZ_MUST_USE bool atomics_xor(JSContext* cx, unsigned argc, Value* vp);
MOZ_MUST_USE bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp);
MOZ_MUST_USE bool atomics_wait(JSContext* cx, unsigned argc, Value* vp);
MOZ_MUST_USE bool atomics_wake(JSContext* cx, unsigned argc, Value* vp);

/* asm.js callouts */
namespace wasm { class Instance; }
int32_t atomics_add_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
int32_t atomics_sub_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
int32_t atomics_and_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
int32_t atomics_or_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
int32_t atomics_xor_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);
int32_t atomics_cmpxchg_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t oldval, int32_t newval);
int32_t atomics_xchg_asm_callout(wasm::Instance* i, int32_t vt, int32_t offset, int32_t value);

class FutexRuntime
{
    friend class AutoLockFutexAPI;

public:
    static MOZ_MUST_USE bool initialize();
    static void destroy();

    static void lock();
    static void unlock();

    FutexRuntime();
    MOZ_MUST_USE bool initInstance();
    void destroyInstance();

    // Parameters to wake().
    enum WakeReason {
        WakeExplicit,           // Being asked to wake up by another thread
        WakeForJSInterrupt      // Interrupt requested
    };

    // Result code from wait().
    enum WaitResult {
        FutexOK,
        FutexTimedOut
    };

    // Block the calling thread and wait.
    //
    // The futex lock must be held around this call.
    //
    // The timeout is the number of milliseconds, with fractional
    // times allowed; specify mozilla::Nothing() for an indefinite
    // wait.
    //
    // wait() will not wake up spuriously.  It will return true and
    // set *result to a return code appropriate for
    // Atomics.wait() on success, and return false on error.
    MOZ_MUST_USE bool wait(JSContext* cx, js::UniqueLock<js::Mutex>& locked,
                           mozilla::Maybe<mozilla::TimeDuration>& timeout, WaitResult* result);

    // Wake the thread represented by this Runtime.
    //
    // The futex lock must be held around this call.  (The sleeping
    // thread will not wake up until the caller of Atomics.wake()
    // releases the lock.)
    //
    // If the thread is not waiting then this method does nothing.
    //
    // If the thread is waiting in a call to wait() and the
    // reason is WakeExplicit then the wait() call will return
    // with Woken.
    //
    // If the thread is waiting in a call to wait() and the
    // reason is WakeForJSInterrupt then the wait() will return
    // with WaitingNotifiedForInterrupt; in the latter case the caller
    // of wait() must handle the interrupt.
    void wake(WakeReason reason);

    bool isWaiting();

    // If canWait() returns false (the default) then wait() is disabled
    // on the runtime to which the FutexRuntime belongs.
    bool canWait() {
        return canWait_;
    }

    void setCanWait(bool flag) {
        canWait_ = flag;
    }

  private:
    enum FutexState {
        Idle,                        // We are not waiting or woken
        Waiting,                     // We are waiting, nothing has happened yet
        WaitingNotifiedForInterrupt, // We are waiting, but have been interrupted,
                                     //   and have not yet started running the
                                     //   interrupt handler
        WaitingInterrupted,          // We are waiting, but have been interrupted
                                     //   and are running the interrupt handler
        Woken                        // Woken by a script call to Atomics.wake
    };

    // Condition variable that this runtime will wait on.
    js::ConditionVariable* cond_;

    // Current futex state for this runtime.  When not in a wait this
    // is Idle; when in a wait it is Waiting or the reason the futex
    // is about to wake up.
    FutexState state_;

    // Shared futex lock for all runtimes.  We can perhaps do better,
    // but any lock will need to be per-domain (consider SharedWorker)
    // or coarser.
    static mozilla::Atomic<js::Mutex*> lock_;

    // A flag that controls whether waiting is allowed.
    bool canWait_;
};

JSObject*
InitAtomicsClass(JSContext* cx, HandleObject obj);

}  /* namespace js */

#endif /* builtin_AtomicsObject_h */