зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1497906 - Add THREAD_TYPE_CURRENT to simulate errors on a single worker thread. r=jonco
This commit is contained in:
Родитель
b3ce8ada8c
Коммит
bf1398f7d2
|
@ -72,6 +72,7 @@ enum ThreadType {
|
|||
THREAD_TYPE_ION_FREE, // 9
|
||||
THREAD_TYPE_WASM_TIER2, // 10
|
||||
THREAD_TYPE_WORKER, // 11
|
||||
THREAD_TYPE_CURRENT, // 12 -- Special code to only track the current thread.
|
||||
THREAD_TYPE_MAX // Used to check shell function arguments
|
||||
};
|
||||
|
||||
|
@ -92,16 +93,24 @@ namespace oom {
|
|||
// like. Testing worker threads is not supported.
|
||||
const ThreadType FirstThreadTypeToTest = THREAD_TYPE_MAIN;
|
||||
const ThreadType LastThreadTypeToTest = THREAD_TYPE_WASM_TIER2;
|
||||
const ThreadType WorkerFirstThreadTypeToTest = THREAD_TYPE_CURRENT;
|
||||
const ThreadType WorkerLastThreadTypeToTest = THREAD_TYPE_CURRENT;
|
||||
|
||||
extern bool InitThreadType(void);
|
||||
extern void SetThreadType(ThreadType);
|
||||
extern JS_FRIEND_API(uint32_t) GetThreadType(void);
|
||||
extern JS_FRIEND_API(uint32_t) GetAllocationThreadType(void);
|
||||
extern JS_FRIEND_API(uint32_t) GetStackCheckThreadType(void);
|
||||
extern JS_FRIEND_API(uint32_t) GetInterruptCheckThreadType(void);
|
||||
|
||||
# else
|
||||
|
||||
inline bool InitThreadType(void) { return true; }
|
||||
inline void SetThreadType(ThreadType t) {};
|
||||
inline uint32_t GetThreadType(void) { return 0; }
|
||||
inline uint32_t GetAllocationThreadType(void) { return 0; }
|
||||
inline uint32_t GetStackCheckThreadType(void) { return 0; }
|
||||
inline uint32_t GetInterruptCheckThreadType(void) { return 0; }
|
||||
|
||||
# endif
|
||||
|
||||
|
@ -143,7 +152,8 @@ ResetSimulatedOOM();
|
|||
inline bool
|
||||
IsThreadSimulatingOOM()
|
||||
{
|
||||
return js::oom::targetThread && js::oom::targetThread == js::oom::GetThreadType();
|
||||
return js::oom::targetThread &&
|
||||
js::oom::targetThread == js::oom::GetAllocationThreadType();
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
@ -191,7 +201,8 @@ ResetSimulatedStackOOM();
|
|||
inline bool
|
||||
IsThreadSimulatingStackOOM()
|
||||
{
|
||||
return js::oom::stackTargetThread && js::oom::stackTargetThread == js::oom::GetThreadType();
|
||||
return js::oom::stackTargetThread &&
|
||||
js::oom::stackTargetThread == js::oom::GetStackCheckThreadType();
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
@ -240,7 +251,8 @@ ResetSimulatedInterrupt();
|
|||
inline bool
|
||||
IsThreadSimulatingInterrupt()
|
||||
{
|
||||
return js::oom::interruptTargetThread && js::oom::interruptTargetThread == js::oom::GetThreadType();
|
||||
return js::oom::interruptTargetThread &&
|
||||
js::oom::interruptTargetThread == js::oom::GetInterruptCheckThreadType();
|
||||
}
|
||||
|
||||
inline bool
|
||||
|
|
|
@ -1894,7 +1894,7 @@ RunIterativeFailureTest(JSContext* cx, const IterativeFailureTestParams& params,
|
|||
|
||||
simulator.setup(cx);
|
||||
|
||||
for (unsigned thread = params.threadStart; thread < params.threadEnd; thread++) {
|
||||
for (unsigned thread = params.threadStart; thread <= params.threadEnd; thread++) {
|
||||
if (params.verbose) {
|
||||
fprintf(stderr, "thread %d\n", thread);
|
||||
}
|
||||
|
@ -2035,20 +2035,29 @@ ParseIterativeFailureTestParams(JSContext* cx, const CallArgs& args,
|
|||
params->expectExceptionOnFailure = false;
|
||||
}
|
||||
|
||||
// Test all threads by default.
|
||||
params->threadStart = oom::FirstThreadTypeToTest;
|
||||
params->threadEnd = oom::LastThreadTypeToTest;
|
||||
// Test all threads by default except worker threads, except if we are
|
||||
// running in a worker thread in which case only the worker thread which
|
||||
// requested the simulation is tested.
|
||||
if (js::oom::GetThreadType() == js::THREAD_TYPE_WORKER) {
|
||||
params->threadStart = oom::WorkerFirstThreadTypeToTest;
|
||||
params->threadEnd = oom::WorkerLastThreadTypeToTest;
|
||||
} else {
|
||||
params->threadStart = oom::FirstThreadTypeToTest;
|
||||
params->threadEnd = oom::LastThreadTypeToTest;
|
||||
}
|
||||
|
||||
// Test a single thread type if specified by the OOM_THREAD environment variable.
|
||||
int threadOption = 0;
|
||||
if (EnvVarAsInt("OOM_THREAD", &threadOption)) {
|
||||
if (threadOption < oom::FirstThreadTypeToTest || threadOption > oom::LastThreadTypeToTest) {
|
||||
if (threadOption < oom::FirstThreadTypeToTest || threadOption > oom::LastThreadTypeToTest ||
|
||||
threadOption != js::THREAD_TYPE_CURRENT)
|
||||
{
|
||||
JS_ReportErrorASCII(cx, "OOM_THREAD value out of range.");
|
||||
return false;
|
||||
}
|
||||
|
||||
params->threadStart = threadOption;
|
||||
params->threadEnd = threadOption + 1;
|
||||
params->threadEnd = threadOption;
|
||||
}
|
||||
|
||||
params->verbose = EnvVarIsDefined("OOM_VERBOSE");
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
// |jit-test| skip-if: !('oomTest' in this && 'stackTest' in this) || helperThreadCount() === 0
|
||||
|
||||
// Check the we can run a stack test on all threads except worker threads while
|
||||
// a worker thread is running a OOM test at the same time.
|
||||
//
|
||||
// This test case uses setSharedObject to "synchronize" between a worker thread
|
||||
// and the main thread. This worker thread enters the oomTest section, while the
|
||||
// main thread waits. Then the worker thread remains in the oomTest section
|
||||
// until the main thread finish entering and existing its stackTest section.
|
||||
|
||||
setSharedObject(0);
|
||||
evalInWorker(`
|
||||
oomTest(() => {
|
||||
if (getSharedObject() < 2) {
|
||||
setSharedObject(1);
|
||||
while (getSharedObject() != 2) {
|
||||
}
|
||||
}
|
||||
});
|
||||
`);
|
||||
|
||||
while (getSharedObject() != 1) {
|
||||
// poor-man wait condition.
|
||||
}
|
||||
|
||||
stackTest(() => 42);
|
||||
setSharedObject(2);
|
|
@ -38,25 +38,32 @@ MOZ_THREAD_LOCAL(uint32_t) threadType;
|
|||
JS_PUBLIC_DATA(uint64_t) maxAllocations = UINT64_MAX;
|
||||
JS_PUBLIC_DATA(uint64_t) counter = 0;
|
||||
JS_PUBLIC_DATA(bool) failAlways = true;
|
||||
MOZ_THREAD_LOCAL(bool) isAllocationThread;
|
||||
|
||||
JS_PUBLIC_DATA(uint32_t) stackTargetThread = 0;
|
||||
JS_PUBLIC_DATA(uint64_t) maxStackChecks = UINT64_MAX;
|
||||
JS_PUBLIC_DATA(uint64_t) stackCheckCounter = 0;
|
||||
JS_PUBLIC_DATA(bool) stackCheckFailAlways = true;
|
||||
MOZ_THREAD_LOCAL(bool) isStackCheckThread;
|
||||
|
||||
JS_PUBLIC_DATA(uint32_t) interruptTargetThread = 0;
|
||||
JS_PUBLIC_DATA(uint64_t) maxInterruptChecks = UINT64_MAX;
|
||||
JS_PUBLIC_DATA(uint64_t) interruptCheckCounter = 0;
|
||||
JS_PUBLIC_DATA(bool) interruptCheckFailAlways = true;
|
||||
MOZ_THREAD_LOCAL(bool) isInterruptCheckThread;
|
||||
|
||||
bool
|
||||
InitThreadType(void) {
|
||||
return threadType.init();
|
||||
return threadType.init() && isAllocationThread.init() &&
|
||||
isStackCheckThread.init() && isInterruptCheckThread.init();
|
||||
}
|
||||
|
||||
void
|
||||
SetThreadType(ThreadType type) {
|
||||
threadType.set(type);
|
||||
isAllocationThread.set(false);
|
||||
isStackCheckThread.set(false);
|
||||
isInterruptCheckThread.set(false);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -64,10 +71,35 @@ GetThreadType(void) {
|
|||
return threadType.get();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GetAllocationThreadType(void) {
|
||||
if (isAllocationThread.get()) {
|
||||
return js::THREAD_TYPE_CURRENT;
|
||||
}
|
||||
return threadType.get();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GetStackCheckThreadType(void) {
|
||||
if (isStackCheckThread.get()) {
|
||||
return js::THREAD_TYPE_CURRENT;
|
||||
}
|
||||
return threadType.get();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GetInterruptCheckThreadType(void) {
|
||||
if (isInterruptCheckThread.get()) {
|
||||
return js::THREAD_TYPE_CURRENT;
|
||||
}
|
||||
return threadType.get();
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsHelperThreadType(uint32_t thread)
|
||||
{
|
||||
return thread != THREAD_TYPE_NONE && thread != THREAD_TYPE_MAIN;
|
||||
return thread != THREAD_TYPE_NONE && thread != THREAD_TYPE_MAIN &&
|
||||
thread != THREAD_TYPE_CURRENT;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -82,6 +114,9 @@ SimulateOOMAfter(uint64_t allocations, uint32_t thread, bool always)
|
|||
MOZ_ASSERT(counter + allocations > counter);
|
||||
MOZ_ASSERT(thread > js::THREAD_TYPE_NONE && thread < js::THREAD_TYPE_MAX);
|
||||
targetThread = thread;
|
||||
if (thread == js::THREAD_TYPE_CURRENT) {
|
||||
isAllocationThread.set(true);
|
||||
}
|
||||
maxAllocations = counter + allocations;
|
||||
failAlways = always;
|
||||
}
|
||||
|
@ -96,6 +131,7 @@ ResetSimulatedOOM()
|
|||
}
|
||||
|
||||
targetThread = THREAD_TYPE_NONE;
|
||||
isAllocationThread.set(false);
|
||||
maxAllocations = UINT64_MAX;
|
||||
failAlways = false;
|
||||
}
|
||||
|
@ -112,6 +148,9 @@ SimulateStackOOMAfter(uint64_t checks, uint32_t thread, bool always)
|
|||
MOZ_ASSERT(stackCheckCounter + checks > stackCheckCounter);
|
||||
MOZ_ASSERT(thread > js::THREAD_TYPE_NONE && thread < js::THREAD_TYPE_MAX);
|
||||
stackTargetThread = thread;
|
||||
if (thread == js::THREAD_TYPE_CURRENT) {
|
||||
isStackCheckThread.set(true);
|
||||
}
|
||||
maxStackChecks = stackCheckCounter + checks;
|
||||
stackCheckFailAlways = always;
|
||||
}
|
||||
|
@ -126,6 +165,7 @@ ResetSimulatedStackOOM()
|
|||
}
|
||||
|
||||
stackTargetThread = THREAD_TYPE_NONE;
|
||||
isStackCheckThread.set(false);
|
||||
maxStackChecks = UINT64_MAX;
|
||||
stackCheckFailAlways = false;
|
||||
}
|
||||
|
@ -142,6 +182,9 @@ SimulateInterruptAfter(uint64_t checks, uint32_t thread, bool always)
|
|||
MOZ_ASSERT(interruptCheckCounter + checks > interruptCheckCounter);
|
||||
MOZ_ASSERT(thread > js::THREAD_TYPE_NONE && thread < js::THREAD_TYPE_MAX);
|
||||
interruptTargetThread = thread;
|
||||
if (thread == js::THREAD_TYPE_CURRENT) {
|
||||
isInterruptCheckThread.set(true);
|
||||
}
|
||||
maxInterruptChecks = interruptCheckCounter + checks;
|
||||
interruptCheckFailAlways = always;
|
||||
}
|
||||
|
@ -156,6 +199,7 @@ ResetSimulatedInterrupt()
|
|||
}
|
||||
|
||||
interruptTargetThread = THREAD_TYPE_NONE;
|
||||
isInterruptCheckThread.set(false);
|
||||
maxInterruptChecks = UINT64_MAX;
|
||||
interruptCheckFailAlways = false;
|
||||
}
|
||||
|
|
|
@ -6401,7 +6401,8 @@ enum class MailboxTag {
|
|||
Empty,
|
||||
SharedArrayBuffer,
|
||||
WasmMemory,
|
||||
WasmModule
|
||||
WasmModule,
|
||||
Number,
|
||||
};
|
||||
|
||||
struct SharedObjectMailbox
|
||||
|
@ -6412,6 +6413,7 @@ struct SharedObjectMailbox
|
|||
uint32_t length;
|
||||
} sarb;
|
||||
const wasm::Module* module;
|
||||
double number;
|
||||
};
|
||||
|
||||
SharedObjectMailbox() : tag(MailboxTag::Empty) {}
|
||||
|
@ -6441,6 +6443,7 @@ DestructSharedObjectMailbox()
|
|||
auto mbx = sharedObjectMailbox->lock();
|
||||
switch (mbx->tag) {
|
||||
case MailboxTag::Empty:
|
||||
case MailboxTag::Number:
|
||||
break;
|
||||
case MailboxTag::SharedArrayBuffer:
|
||||
case MailboxTag::WasmMemory:
|
||||
|
@ -6470,6 +6473,10 @@ GetSharedObject(JSContext* cx, unsigned argc, Value* vp)
|
|||
case MailboxTag::Empty: {
|
||||
break;
|
||||
}
|
||||
case MailboxTag::Number: {
|
||||
args.rval().setNumber(mbx->val.number);
|
||||
return true;
|
||||
}
|
||||
case MailboxTag::SharedArrayBuffer:
|
||||
case MailboxTag::WasmMemory: {
|
||||
// Flag was set in the sender; ensure it is set in the receiver.
|
||||
|
@ -6589,6 +6596,10 @@ SetSharedObject(JSContext* cx, unsigned argc, Value* vp)
|
|||
JS_ReportErrorASCII(cx, "Invalid argument to SetSharedObject");
|
||||
return false;
|
||||
}
|
||||
} else if (args.get(0).isNumber()) {
|
||||
tag = MailboxTag::Number;
|
||||
value.number = args.get(0).toNumber();
|
||||
// Nothing
|
||||
} else if (args.get(0).isNullOrUndefined()) {
|
||||
// Nothing
|
||||
} else {
|
||||
|
@ -6601,6 +6612,7 @@ SetSharedObject(JSContext* cx, unsigned argc, Value* vp)
|
|||
|
||||
switch (mbx->tag) {
|
||||
case MailboxTag::Empty:
|
||||
case MailboxTag::Number:
|
||||
break;
|
||||
case MailboxTag::SharedArrayBuffer:
|
||||
case MailboxTag::WasmMemory:
|
||||
|
|
|
@ -33,6 +33,9 @@ mem[0] = 314159;
|
|||
assertEq(w[0], 314159); // Shares memory (locally) with what we put in?
|
||||
mem[0] = 0;
|
||||
|
||||
setSharedObject(3.14); // Share numbers
|
||||
assertEq(getSharedObject(), 3.14);
|
||||
|
||||
setSharedObject(null); // Setting to null clears to null
|
||||
assertEq(getSharedObject(), null);
|
||||
|
||||
|
@ -51,7 +54,6 @@ assertThrowsInstanceOf(() => setSharedObject([1,2]), Error);
|
|||
assertThrowsInstanceOf(() => setSharedObject(new ArrayBuffer(10)), Error);
|
||||
assertThrowsInstanceOf(() => setSharedObject(new Int32Array(10)), Error);
|
||||
assertThrowsInstanceOf(() => setSharedObject(false), Error);
|
||||
assertThrowsInstanceOf(() => setSharedObject(3.14), Error);
|
||||
assertThrowsInstanceOf(() => setSharedObject(mem), Error);
|
||||
assertThrowsInstanceOf(() => setSharedObject("abracadabra"), Error);
|
||||
assertThrowsInstanceOf(() => setSharedObject(() => 37), Error);
|
||||
|
|
Загрузка…
Ссылка в новой задаче