int main()
{
  sharedVar = 0;
  int s = pthread_create(&thr, NULL, thread_start, 0);
  assert(s == 0);

  // Wait until thread kicks in and sets the shared variable.
  while(sharedVar == 0)
    BusySleep(10);

  s = pthread_kill(thr, SIGKILL);
  assert(s == 0);

  // Wait until we see the shared variable stop incrementing. (This is a bit heuristic and hacky)
  for(;;)
  {
    int val = emscripten_atomic_load_u32((void*)&sharedVar);
    BusySleep(100);
    int val2 = emscripten_atomic_load_u32((void*)&sharedVar);
    if (val == val2) break;
  }

  // Reset to 0.
  sharedVar = 0;
  emscripten_atomic_store_u32((void*)&sharedVar, 0);

  // Wait for a long time, if the thread is still running, it should progress and set sharedVar by this time.
  BusySleep(3000);

  // Finally test that the thread is not doing any work and it is dead.
  assert(sharedVar == 0);
  assert(emscripten_atomic_load_u32((void*)&sharedVar) == 0);
  EM_ASM_INT( { Module['print']('Main: Done. Successfully killed thread. sharedVar: '+$0+'.'); }, sharedVar);
void *ThreadMain(void *arg)
{
  printf("Thread started. You should see the WebGL canvas fade from black to red.\n");
  EmscriptenWebGLContextAttributes attr;
  emscripten_webgl_init_context_attributes(&attr);
  attr.explicitSwapControl = EM_TRUE;
  ctx = emscripten_webgl_create_context(0, &attr);
  emscripten_webgl_make_context_current(ctx);

  double color = 0;
  for(int i = 0; i < 100; ++i)
  {
    color += 0.01;
    glClearColor(color, 0, 0, 1);
    glClear(GL_COLOR_BUFFER_BIT);
    EMSCRIPTEN_RESULT r = emscripten_webgl_commit_frame();
    assert(r == EMSCRIPTEN_RESULT_SUCCESS);

    double now = emscripten_get_now();
    while(emscripten_get_now() - now < 16) /*no-op*/;
  }

  emscripten_webgl_make_context_current(0);
  emscripten_webgl_destroy_context(ctx);
  emscripten_atomic_store_u32(&threadRunning, 0);
  printf("Thread quit\n");
  pthread_exit(0);
}
void *ThreadMain(void *arg)
{
	for(int i = 0; i < 10; ++i)
	{
		char str[256];
		sprintf(str, "file%d.txt", i);
		printf("Writing file %s..\n", str); // Prints out to page console, this is a proxied operation.
		FILE *handle = fopen(str, "w"); // fopen, fputs and fclose are currently proxied operations too (although hopefully not in the future)
		fputs(str, handle);
		fclose(handle);
	}
	emscripten_atomic_store_u32(&main_thread_wait_val, 0);
	emscripten_futex_wake(&main_thread_wait_val, 1);
	emscripten_atomic_store_u32(&result, 0);
	pthread_exit(0);
}
static void *thread_start(void *arg) // thread: just flip the shared flag and quit.
{
#ifdef USE_C_VOLATILE
  sharedVar = 1;
#else
  emscripten_atomic_store_u32((void*)&sharedVar, 1);
#endif
  pthread_exit(0);
}
static void *thread_start(void *arg)
{
  // As long as this thread is running, keep the shared variable latched to nonzero value.
  for(;;)
  {
    ++sharedVar;
    emscripten_atomic_store_u32((void*)&sharedVar, sharedVar+1);
  }

  pthread_exit(0);
}
emscripten_fetch_t *emscripten_fetch(emscripten_fetch_attr_t *fetch_attr, const char *url)
{
	if (!fetch_attr) return 0;
	if (!url) return 0;

	const bool waitable = (fetch_attr->attributes & EMSCRIPTEN_FETCH_WAITABLE) != 0;
	const bool synchronous = (fetch_attr->attributes & EMSCRIPTEN_FETCH_SYNCHRONOUS) != 0;
	const bool readFromIndexedDB = (fetch_attr->attributes & (EMSCRIPTEN_FETCH_APPEND | EMSCRIPTEN_FETCH_NO_DOWNLOAD)) != 0;
	const bool writeToIndexedDB = (fetch_attr->attributes & EMSCRIPTEN_FETCH_PERSIST_FILE) != 0 || !strncmp(fetch_attr->requestMethod, "EM_IDB_", strlen("EM_IDB_"));
	const bool performXhr = (fetch_attr->attributes & EMSCRIPTEN_FETCH_NO_DOWNLOAD) == 0;
	const bool isMainBrowserThread = emscripten_is_main_browser_thread() != 0;
	if (isMainBrowserThread && synchronous && (performXhr || readFromIndexedDB || writeToIndexedDB))
	{
		EM_ASM_INT( { Module['printErr']('emscripten_fetch("' + Pointer_stringify($0) + '") failed! Synchronous blocking XHRs and IndexedDB operations are not supported on the main browser thread. Try dropping the EMSCRIPTEN_FETCH_SYNCHRONOUS flag, or run with the linker flag --proxy-to-worker to decouple main C runtime thread from the main browser thread.') }, 
			url);
		return 0;
	}

	emscripten_fetch_t *fetch = (emscripten_fetch_t *)malloc(sizeof(emscripten_fetch_t));
	memset(fetch, 0, sizeof(emscripten_fetch_t));
	fetch->id = globalFetchIdCounter++; // TODO: make this thread-safe!
	fetch->userData = fetch_attr->userData;
	fetch->url = strdup(url); // TODO: free
	fetch->__attributes = *fetch_attr;
	fetch->__attributes.destinationPath = fetch->__attributes.destinationPath ? strdup(fetch->__attributes.destinationPath) : 0; // TODO: free
	fetch->__attributes.userName = fetch->__attributes.userName ? strdup(fetch->__attributes.userName) : 0; // TODO: free
	fetch->__attributes.password = fetch->__attributes.password ? strdup(fetch->__attributes.password) : 0; // TODO: free
	fetch->__attributes.requestHeaders = 0;// TODO:strdup(fetch->__attributes.requestHeaders);
	fetch->__attributes.overriddenMimeType = fetch->__attributes.overriddenMimeType ? strdup(fetch->__attributes.overriddenMimeType) : 0; // TODO: free

#if __EMSCRIPTEN_PTHREADS__
	// Depending on the type of fetch, we can either perform it in the same Worker/thread than the caller, or we might need
	// to run it in a separate Worker. There is a dedicated fetch worker that is available for the fetch, but in some scenarios
	// it might be desirable to run in the same Worker as the caller, so deduce here whether to run the fetch in this thread,
	// or if we need to use the fetch-worker instead.
	if (waitable // Waitable fetches can be synchronously waited on, so must always be proxied
		|| (synchronous && (readFromIndexedDB || writeToIndexedDB))) // Synchronous IndexedDB access needs proxying
	{
		emscripten_atomic_store_u32(&fetch->__proxyState, 1); // sent to proxy worker.
		emscripten_proxy_fetch(fetch);

		if (synchronous) emscripten_fetch_wait(fetch, INFINITY);
	}
	else
#endif
		emscripten_start_fetch(fetch);
	return fetch;
}
void CreateThread()
{
  pthread_attr_t attr;
  pthread_attr_init(&attr);
  emscripten_pthread_attr_settransferredcanvases(&attr, "#canvas");
  int rc = pthread_create(&thread, &attr, ThreadMain, 0);
  if (rc == ENOSYS)
  {
    printf("Test Skipped! OffscreenCanvas is not supported!\n");
#ifdef REPORT_RESULT
    REPORT_RESULT(0); // But report success, so that runs on non-supporting browsers don't raise noisy errors.
#endif
    exit(0);
  }
  pthread_attr_destroy(&attr);
  emscripten_atomic_store_u32(&threadRunning, 1);
}
void *mandelbrot_thread(void *arg)
{
  int idx = (int)arg;

  for(;;)
  {
    emscripten_futex_wait(&tasksPending[idx], 0, INFINITY);
    emscripten_atomic_store_u32(&tasksPending[idx], 0);
    double t0 = emscripten_get_now();
    int ni;
    if (use_sse)
      ni = ComputeMandelbrot_SSE(mandelReal, mandelImag, outputImage, sizeof(float)*W, sizeof(uint32_t)*W, 0, idx, numTasks, W, H, left, top, incrX, incrY, numItersDoneOnCanvas, numItersPerFrame);
    else
      ni = ComputeMandelbrot(mandelReal, mandelImag, outputImage, sizeof(float)*W, sizeof(uint32_t)*W, 0, idx, numTasks, W, H, left, top, incrX, incrY, numItersDoneOnCanvas, numItersPerFrame);
    //emscripten_atomic_add_u32(&numIters, ni);
    double t1 = emscripten_get_now();
    numIters[idx] += ni;
    timeSpentInMandelbrot[idx] += t1-t0;
    emscripten_atomic_add_u32(&tasksDone, 1);
    emscripten_futex_wake(&tasksDone, 9999);
  }
}
EMSCRIPTEN_RESULT emscripten_fetch_close(emscripten_fetch_t *fetch)
{
	if (!fetch) return EMSCRIPTEN_RESULT_SUCCESS; // Closing null pointer is ok, same as with free().

#if __EMSCRIPTEN_PTHREADS__
	emscripten_atomic_store_u32(&fetch->__proxyState, 0);
#endif
	// This function frees the fetch pointer so that it is invalid to access it anymore.
	// Use a few key fields as an integrity check that we are being passed a good pointer to a valid fetch structure,
	// which has not been yet closed. (double close is an error)
	if (fetch->id == 0 || fetch->readyState > 4) return EMSCRIPTEN_RESULT_INVALID_PARAM;

	// This fetch is aborted. Call the error handler if the fetch was still in progress and was canceled in flight.
	if (fetch->readyState != 4 /*DONE*/ && fetch->__attributes.onerror)
	{
		fetch->status = (unsigned short)-1;
		strcpy(fetch->statusText, "aborted with emscripten_fetch_close()");
		fetch->__attributes.onerror(fetch);
	}
	fetch->id = 0;
	free((void*)fetch->data);
	free(fetch);
	return EMSCRIPTEN_RESULT_SUCCESS;
}