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/. */
7 #ifndef builtin_AtomicsObject_h
8 #define builtin_AtomicsObject_h
10 #include "mozilla/Maybe.h"
11 #include "mozilla/TimeStamp.h"
13 #include "threading/ConditionVariable.h"
14 #include "threading/ProtectedData.h" // js::ThreadData
15 #include "vm/NativeObject.h"
19 class SharedArrayRawBuffer
;
21 class AtomicsObject
: public NativeObject
{
23 static const JSClass class_
;
27 friend class AutoLockFutexAPI
;
30 [[nodiscard
]] static bool initialize();
31 static void destroy();
37 [[nodiscard
]] bool initInstance();
38 void destroyInstance();
40 // Parameters to notify().
42 NotifyExplicit
, // Being asked to wake up by another thread
43 NotifyForJSInterrupt
// Interrupt requested
46 // Result codes from wait() and atomics_wait_impl().
47 enum class WaitResult
{
48 Error
, // Error has been reported, just propagate error signal
49 NotEqual
, // Did not wait because the values differed
50 OK
, // Waited and was woken
51 TimedOut
// Waited and timed out
54 // Block the calling thread and wait.
56 // The futex lock must be held around this call.
58 // The timeout is the number of milliseconds, with fractional
59 // times allowed; specify mozilla::Nothing() for an indefinite
62 // wait() will not wake up spuriously.
63 [[nodiscard
]] WaitResult
wait(
64 JSContext
* cx
, js::UniqueLock
<js::Mutex
>& locked
,
65 const mozilla::Maybe
<mozilla::TimeDuration
>& timeout
);
67 // Notify the thread this is associated with.
69 // The futex lock must be held around this call. (The sleeping
70 // thread will not wake up until the caller of Atomics.notify()
71 // releases the lock.)
73 // If the thread is not waiting then this method does nothing.
75 // If the thread is waiting in a call to wait() and the
76 // reason is NotifyExplicit then the wait() call will return
79 // If the thread is waiting in a call to wait() and the
80 // reason is NotifyForJSInterrupt then the wait() will return
81 // with WaitingNotifiedForInterrupt; in the latter case the caller
82 // of wait() must handle the interrupt.
83 void notify(NotifyReason reason
);
87 // If canWait() returns false (the default) then wait() is disabled
88 // on the thread to which the FutexThread belongs.
89 bool canWait() { return canWait_
; }
91 void setCanWait(bool flag
) { canWait_
= flag
; }
95 Idle
, // We are not waiting or woken
96 Waiting
, // We are waiting, nothing has happened yet
97 WaitingNotifiedForInterrupt
, // We are waiting, but have been interrupted,
98 // and have not yet started running the
100 WaitingInterrupted
, // We are waiting, but have been interrupted
101 // and are running the interrupt handler
102 Woken
// Woken by a script call to Atomics.notify
105 // Condition variable that this runtime will wait on.
106 js::ConditionVariable
* cond_
;
108 // Current futex state for this runtime. When not in a wait this
109 // is Idle; when in a wait it is Waiting or the reason the futex
110 // is about to wake up.
113 // Shared futex lock for all runtimes. We can perhaps do better,
114 // but any lock will need to be per-domain (consider SharedWorker)
116 static mozilla::Atomic
<js::Mutex
*, mozilla::SequentiallyConsistent
> lock_
;
118 // A flag that controls whether waiting is allowed.
119 ThreadData
<bool> canWait_
;
122 // Go to sleep if the int32_t value at the given address equals `value`.
123 [[nodiscard
]] FutexThread::WaitResult
atomics_wait_impl(
124 JSContext
* cx
, SharedArrayRawBuffer
* sarb
, size_t byteOffset
, int32_t value
,
125 const mozilla::Maybe
<mozilla::TimeDuration
>& timeout
);
127 // Go to sleep if the int64_t value at the given address equals `value`.
128 [[nodiscard
]] FutexThread::WaitResult
atomics_wait_impl(
129 JSContext
* cx
, SharedArrayRawBuffer
* sarb
, size_t byteOffset
, int64_t value
,
130 const mozilla::Maybe
<mozilla::TimeDuration
>& timeout
);
132 // Notify some waiters on the given address. If `count` is negative then notify
133 // all. The return value is nonnegative and is the number of waiters woken. If
134 // the number of waiters woken exceeds INT64_MAX then this never returns. If
135 // `count` is nonnegative then the return value is never greater than `count`.
136 [[nodiscard
]] int64_t atomics_notify_impl(SharedArrayRawBuffer
* sarb
,
137 size_t byteOffset
, int64_t count
);
141 #endif /* builtin_AtomicsObject_h */