Bug 1497906 - Add THREAD_TYPE_CURRENT to simulate errors on a single worker thread. r=jonco

This commit is contained in:
Nicolas B. Pierron 2018-10-15 16:41:33 +02:00
Родитель b3ce8ada8c
Коммит bf1398f7d2
6 изменённых файлов: 119 добавлений и 13 удалений

Просмотреть файл

@ -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);