blob: 9bce2e56f5ae5bdb631be21a11fdcc3632ae9750 [file]
// Copyright 2019 The Emscripten Authors. All rights reserved.
// Emscripten is available under two separate licenses, the MIT license and the
// University of Illinois/NCSA Open Source License. Both these licenses can be
// found in the LICENSE file.
#include <pthread.h>
#include <stdlib.h>
#include <assert.h>
#include <emscripten/em_js.h>
#include <stdbool.h>
// We want to test that JavaScript access in the main thread automatically
// updates the memory views if the heap has grown from the pthread meanwhile.
//
// Checking this correctly is somewhat tricky because a lot of Emscripten APIs
// access heap on their own, so the memory views might be updated by them before
// we explicitly check the state in our own JS routines below, which leads to
// false positives (test passing even though in isolation the heap access in our
// own JS is not the one updating the memory views).
//
// To test it in isolation, we need to use only EM_JS - which is as close to a
// pure JS call as we can get - and not EM_ASM, pthread_join, proxying etc., not
// even `puts`/`printf` for logging - as all of those access the heap from JS on
// their own and might update the memory views too early. Not using standard
// proxying mechanisms also means we need to drop down all the way to raw
// atomics.
EM_JS(void, assert_initial_heap_state, (bool isWorker), {
err(`Checking initial heap state on the ${isWorker ? 'worker' : 'main'} thread`);
assert(HEAP8.length === 32 * 1024 * 1024, "start at 32MB");
});
EM_JS(void, js_assert_final_heap_state, (bool isWorker, const char* buffer, int finalHeapSize), {
err(`Checking final heap state on the ${isWorker ? 'worker' : 'main'} thread`);
assert(HEAP8.length > finalHeapSize, "end with >64MB");
assert(HEAP8[buffer] === 42, "readable from JS");
});
#define FINAL_HEAP_SIZE (64 * 1024 * 1024)
char *alloc_beyond_initial_heap() {
char *buffer = malloc(FINAL_HEAP_SIZE);
assert(buffer);
// Write value at the end of the buffer to check that any thread can access addresses beyond the initial heap size.
buffer += FINAL_HEAP_SIZE - 1;
*buffer = 42;
return buffer;
}
const char *_Atomic buffer = NULL;
void assert_final_heap_state(bool is_worker) {
assert(buffer != NULL);
assert(*buffer == 42);
js_assert_final_heap_state(is_worker, buffer, FINAL_HEAP_SIZE);
}
void *thread_start(void *arg) {
assert_initial_heap_state(true);
// allocate more memory than we currently have, forcing a growth
buffer = alloc_beyond_initial_heap();
assert_final_heap_state(true);
return NULL;
}
int main() {
assert_initial_heap_state(false);
pthread_t thr;
int res = pthread_create(&thr, NULL, thread_start, NULL);
assert(res == 0);
while (!buffer);
assert(*buffer == 42); // should see the value the thread wrote
assert_final_heap_state(false);
res = pthread_join(thr, NULL);
assert(res == 0);
return 0;
}