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
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* 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_notify(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 notify().
enum NotifyReason {
NotifyExplicit, // Being asked to wake up by another thread
NotifyForJSInterrupt // 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.
MOZ_MUST_USE bool wait(JSContext* cx, js::UniqueLock<js::Mutex>& locked,
mozilla::Maybe<mozilla::TimeDuration>& timeout, WaitResult* result);
// Notify 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.notify()
// 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 NotifyExplicit then the wait() call will return
// with Woken.
//
// If the thread is waiting in a call to wait() and the
// reason is NotifyForJSInterrupt then the wait() will return
// with WaitingNotifiedForInterrupt; in the latter case the caller
// of wait() must handle the interrupt.
void notify(NotifyReason 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.notify
};
// 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 */
|