Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add example with multiple threads creation #1826

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions samples/wasi-threads/wasm-apps/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ endfunction ()

compile_sample(no_pthread.c)
compile_sample(exception_propagation.c)
compile_sample(multiple_threads.c)
84 changes: 84 additions & 0 deletions samples/wasi-threads/wasm-apps/multiple_threads.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright (C) 2022 Amazon.com Inc. or its affiliates. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef __wasi__
#error This example only compiles to WASM/WASI target
#endif

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <wasi/api.h>
#include <stdbool.h>

#define MAX_NUM_THREADS 4 // Default maximum number of threads for iwasm
static const int64_t SECOND = 1000 * 1000 * 1000;

typedef struct {
int th_ready;
int th_done;
} shared_t;

__attribute__((export_name("wasi_thread_start"))) void
wasi_thread_start(int thread_id, int *start_arg)
{
shared_t *data = (shared_t *)start_arg;

if (__builtin_wasm_memory_atomic_wait32(&data->th_ready, 0, SECOND) == 2)
assert(false && "Wait operation in thread failed");

data->th_done = 1;
__builtin_wasm_memory_atomic_notify(&data->th_done, 1);
}

int
main(int argc, char **argv)
{
int thread_ids[MAX_NUM_THREADS];
shared_t data[MAX_NUM_THREADS] = { 0 };

for (int i = 0; i < MAX_NUM_THREADS; i++) {
thread_ids[i] = __wasi_thread_spawn(&data[i]);
printf("Created thread with id = %d\n", thread_ids[i]);
assert(thread_ids[i] >= 0 && "Thread ids must be >= 0");

bool is_id_already_existing = false;
for (int j = 0; j < i; j++) {
if (thread_ids[i] == thread_ids[j])
is_id_already_existing = true;
}
assert(!is_id_already_existing && "Thread ids must be unique");
}

printf("Try to create additional thread after limit reached\n");
shared_t data_fail = { 0 };
int thread_id = __wasi_thread_spawn(&data_fail);
assert(thread_id < 0 && "Thread creation must fail");

// Unlock first-created thread
data[0].th_ready = 1;
__builtin_wasm_memory_atomic_notify(&data[0].th_ready, 1);
// And wait for it to return
if (__builtin_wasm_memory_atomic_wait32(&data[0].th_done, 0, SECOND) == 2)
assert(false && "Wait operation in main thread failed");

printf("Try to create additional thread after previous was released\n");
shared_t data_succeed = { 0 };
thread_id = __wasi_thread_spawn(&data_succeed);
assert(thread_id >= 0 && "Thread creation must succeed");

printf("Created thread with id = %d\n", thread_id);
assert(thread_id == thread_ids[0]
&& "New thread must reuse previously-released identifier");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • it seems racy as the first thread might be still running
  • i'm not sure if it's a good idea to test this kind of implementation details (how ids are reused) in these samples.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about the race condition, but I definitely agree that the check on the id is an implementation detail and should not be tested.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's unsafe is maybe that, after __builtin_wasm_memory_atomic_wait32() in the main thread, I can't assume that the thread created has finished and it's possible to create a new thread.


// Unlock all running threads
data_succeed.th_ready = 1;
__builtin_wasm_memory_atomic_notify(&data_succeed.th_ready, 1);
for (int i = 1; i < MAX_NUM_THREADS; i++) {
data[i].th_ready = 1;
__builtin_wasm_memory_atomic_notify(&data[i].th_ready, 1);
}

return EXIT_SUCCESS;
}