Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2
* vim: set ts=8 sts=2 et sw=2 tw=80:
3
* This Source Code Form is subject to the terms of the Mozilla Public
4
* License, v. 2.0. If a copy of the MPL was not distributed with this
5
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#ifndef builtin_AtomicsObject_h
8
#define builtin_AtomicsObject_h
9
10
#include "mozilla/Maybe.h"
11
#include "mozilla/TimeStamp.h"
12
13
#include "threading/ConditionVariable.h"
14
#include "threading/ProtectedData.h" // js::ThreadData
15
#include "vm/JSObject.h"
16
#include "vm/MutexIDs.h"
17
#include "vm/NativeObject.h"
18
19
namespace js {
20
21
class GlobalObject;
22
class SharedArrayRawBuffer;
23
24
class AtomicsObject : public NativeObject {
25
public:
26
static const JSClass class_;
27
static JSObject* initClass(JSContext* cx, Handle<GlobalObject*> global);
28
static MOZ_MUST_USE bool toString(JSContext* cx, unsigned int argc,
29
Value* vp);
30
};
31
32
MOZ_MUST_USE bool atomics_compareExchange(JSContext* cx, unsigned argc,
33
Value* vp);
34
MOZ_MUST_USE bool atomics_exchange(JSContext* cx, unsigned argc, Value* vp);
35
MOZ_MUST_USE bool atomics_load(JSContext* cx, unsigned argc, Value* vp);
36
MOZ_MUST_USE bool atomics_store(JSContext* cx, unsigned argc, Value* vp);
37
MOZ_MUST_USE bool atomics_add(JSContext* cx, unsigned argc, Value* vp);
38
MOZ_MUST_USE bool atomics_sub(JSContext* cx, unsigned argc, Value* vp);
39
MOZ_MUST_USE bool atomics_and(JSContext* cx, unsigned argc, Value* vp);
40
MOZ_MUST_USE bool atomics_or(JSContext* cx, unsigned argc, Value* vp);
41
MOZ_MUST_USE bool atomics_xor(JSContext* cx, unsigned argc, Value* vp);
42
MOZ_MUST_USE bool atomics_isLockFree(JSContext* cx, unsigned argc, Value* vp);
43
MOZ_MUST_USE bool atomics_wait(JSContext* cx, unsigned argc, Value* vp);
44
MOZ_MUST_USE bool atomics_notify(JSContext* cx, unsigned argc, Value* vp);
45
46
class FutexThread {
47
friend class AutoLockFutexAPI;
48
49
public:
50
static MOZ_MUST_USE bool initialize();
51
static void destroy();
52
53
static void lock();
54
static void unlock();
55
56
FutexThread();
57
MOZ_MUST_USE bool initInstance();
58
void destroyInstance();
59
60
// Parameters to notify().
61
enum NotifyReason {
62
NotifyExplicit, // Being asked to wake up by another thread
63
NotifyForJSInterrupt // Interrupt requested
64
};
65
66
// Result codes from wait() and atomics_wait_impl().
67
enum class WaitResult {
68
Error, // Error has been reported, just propagate error signal
69
NotEqual, // Did not wait because the values differed
70
OK, // Waited and was woken
71
TimedOut // Waited and timed out
72
};
73
74
// Block the calling thread and wait.
75
//
76
// The futex lock must be held around this call.
77
//
78
// The timeout is the number of milliseconds, with fractional
79
// times allowed; specify mozilla::Nothing() for an indefinite
80
// wait.
81
//
82
// wait() will not wake up spuriously.
83
MOZ_MUST_USE WaitResult
84
wait(JSContext* cx, js::UniqueLock<js::Mutex>& locked,
85
const mozilla::Maybe<mozilla::TimeDuration>& timeout);
86
87
// Notify the thread this is associated with.
88
//
89
// The futex lock must be held around this call. (The sleeping
90
// thread will not wake up until the caller of Atomics.notify()
91
// releases the lock.)
92
//
93
// If the thread is not waiting then this method does nothing.
94
//
95
// If the thread is waiting in a call to wait() and the
96
// reason is NotifyExplicit then the wait() call will return
97
// with Woken.
98
//
99
// If the thread is waiting in a call to wait() and the
100
// reason is NotifyForJSInterrupt then the wait() will return
101
// with WaitingNotifiedForInterrupt; in the latter case the caller
102
// of wait() must handle the interrupt.
103
void notify(NotifyReason reason);
104
105
bool isWaiting();
106
107
// If canWait() returns false (the default) then wait() is disabled
108
// on the thread to which the FutexThread belongs.
109
bool canWait() { return canWait_; }
110
111
void setCanWait(bool flag) { canWait_ = flag; }
112
113
private:
114
enum FutexState {
115
Idle, // We are not waiting or woken
116
Waiting, // We are waiting, nothing has happened yet
117
WaitingNotifiedForInterrupt, // We are waiting, but have been interrupted,
118
// and have not yet started running the
119
// interrupt handler
120
WaitingInterrupted, // We are waiting, but have been interrupted
121
// and are running the interrupt handler
122
Woken // Woken by a script call to Atomics.notify
123
};
124
125
// Condition variable that this runtime will wait on.
126
js::ConditionVariable* cond_;
127
128
// Current futex state for this runtime. When not in a wait this
129
// is Idle; when in a wait it is Waiting or the reason the futex
130
// is about to wake up.
131
FutexState state_;
132
133
// Shared futex lock for all runtimes. We can perhaps do better,
134
// but any lock will need to be per-domain (consider SharedWorker)
135
// or coarser.
136
static mozilla::Atomic<js::Mutex*, mozilla::SequentiallyConsistent,
137
mozilla::recordreplay::Behavior::DontPreserve>
138
lock_;
139
140
// A flag that controls whether waiting is allowed.
141
ThreadData<bool> canWait_;
142
};
143
144
JSObject* InitAtomicsClass(JSContext* cx, Handle<GlobalObject*> global);
145
146
// Go to sleep if the int32_t value at the given address equals `value`.
147
MOZ_MUST_USE FutexThread::WaitResult atomics_wait_impl(
148
JSContext* cx, SharedArrayRawBuffer* sarb, uint32_t byteOffset,
149
int32_t value, const mozilla::Maybe<mozilla::TimeDuration>& timeout);
150
151
// Go to sleep if the int64_t value at the given address equals `value`.
152
MOZ_MUST_USE FutexThread::WaitResult atomics_wait_impl(
153
JSContext* cx, SharedArrayRawBuffer* sarb, uint32_t byteOffset,
154
int64_t value, const mozilla::Maybe<mozilla::TimeDuration>& timeout);
155
156
// Notify some waiters on the given address. If `count` is negative then notify
157
// all. The return value is nonnegative and is the number of waiters woken. If
158
// the number of waiters woken exceeds INT64_MAX then this never returns. If
159
// `count` is nonnegative then the return value is never greater than `count`.
160
MOZ_MUST_USE int64_t atomics_notify_impl(SharedArrayRawBuffer* sarb,
161
uint32_t byteOffset, int64_t count);
162
163
} /* namespace js */
164
165
#endif /* builtin_AtomicsObject_h */