wasm C code can't get a pointer-value immediately, have to wait some time
source code:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#define MAX_NUM_THREADS 3
_Noreturn void pthread_exit(void *);
void *thread_routine(void *arg)
{
struct timespec ts;
int i = 0;
pthread_t *tid = (pthread_t *)arg;
//sleep(1);
printf("Enter thread %08x\n", (int)*tid);
for(i = 0; i < 10; i++)
{
clock_gettime(CLOCK_REALTIME, &ts);
printf("%llds %ldns: thread %08x running i=%d\n", ts.tv_sec, ts.tv_nsec, (int)*tid, i);
sleep(1);
}
pthread_exit(NULL);
return NULL;
}
int main(int argc, char** argv)
{
pthread_t tids[MAX_NUM_THREADS];
setbuf(stdout, NULL);//output immediately
for (int i = 0; i < MAX_NUM_THREADS; i++) {
if (pthread_create(&tids[i], NULL, thread_routine, &tids[i]) != 0) {
printf("Thread creation failed\n");
}
}
printf("pthread_join\n");
for (int i = 0; i < MAX_NUM_THREADS; i++) {
if (pthread_join(tids[i], NULL) != 0) {
printf("Thread join failed\n");
}
}
printf("before sleep\n");
sleep(3);
printf("Exit\n");
return 0;
}
build:
opt/wasi-sdk/bin/clang --target=wasm32-wasi -pthread -O3 -Wl,--allow-undefined,--no-check-features -Wl,--export=__heap_base,--export=__data_end -Wl,--export=malloc -Wl,--export=free main.c -o test.wasm
run:
$ ./iwasm --max-threads=20 --heap-size=65535 test.wasm
Enter thread 00000000 //===>thread id not get correct value
1704705385s 805131021ns: thread 00000001 running i=0
Enter thread 00000000 //===>thread id not get correct value
1704705385s 805513255ns: thread 00000002 running i=0
Enter thread 00000000 //===>thread id not get correct value
1704705385s 805665156ns: thread 00000003 running i=0
1704705386s 808273644ns: thread 00000001 running i=1
1704705386s 811101859ns: thread 00000003 running i=1
1704705386s 819979233ns: thread 00000002 running i=1
1704705387s 814727723ns: thread 00000001 running i=2
1704705387s 822503027ns: thread 00000003 running i=2
1704705387s 835201966ns: thread 00000002 running i=2
1704705388s 818195647ns: thread 00000001 running i=3
1704705388s 829340960ns: thread 00000003 running i=3
1704705388s 854175241ns: thread 00000002 running i=3
1704705389s 823698363ns: thread 00000001 running i=4
1704705389s 838319743ns: thread 00000003 running i=4
1704705389s 875401961ns: thread 00000002 running i=4
1704705390s 828702692ns: thread 00000001 running i=5
1704705390s 847107535ns: thread 00000003 running i=5
1704705390s 878263286ns: thread 00000002 running i=5
1704705391s 834154848ns: thread 00000001 running i=6
1704705391s 855453612ns: thread 00000003 running i=6
1704705391s 912887171ns: thread 00000002 running i=6
1704705392s 841931376ns: thread 00000001 running i=7
1704705392s 865333238ns: thread 00000003 running i=7
1704705392s 931382623ns: thread 00000002 running i=7
1704705393s 848815045ns: thread 00000001 running i=8
1704705393s 872374532ns: thread 00000003 running i=8
1704705393s 968670058ns: thread 00000002 running i=8
1704705394s 858598053ns: thread 00000001 running i=9
1704705394s 885874963ns: thread 00000003 running i=9
1704705394s 983285488ns: thread 00000002 running i=9
before sleep
Exit
if add a sleep(1) before print thread id, the result is correct now
pthread_join
Enter thread 00000002 //===>thread id is correct
1704705801s 280416341ns: thread 00000002 running i=0
Enter thread 00000003 //===>thread id is correct
1704705801s 281247387ns: thread 00000003 running i=0
Enter thread 00000001 //===>thread id is correct
1704705801s 292010354ns: thread 00000001 running i=0
1704705802s 280998016ns: thread 00000002 running i=1
1704705802s 282319397ns: thread 00000003 running i=1
1704705802s 294618323ns: thread 00000001 running i=1
1704705803s 281254384ns: thread 00000002 running i=2
1704705803s 287189411ns: thread 00000003 running i=2
...
so It's very strange, anybody know this? Thanks.
WAMR generates the thread ID in the spawn-thread implementation but is wasi-libc who sets the pthread_t * here. after calling wasi_thread_spawn.
The simplest solution would be to create independent args:
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#define MAX_NUM_THREADS 3
void *thread_routine(void *arg) {
printf("Enter thread %d\n", *((int *)arg));
return NULL;
}
int main(int argc, char** argv) {
pthread_t tids[MAX_NUM_THREADS];
int buf[MAX_NUM_THREADS];
setbuf(stdout, NULL);
for (int i = 0; i < MAX_NUM_THREADS; i++) {
buf[i] = i;
if (pthread_create(&tids[i], NULL, thread_routine, &buf[i]) != 0) {
printf("Thread creation failed\n");
}
}
printf("pthread_join\n");
for (int i = 0; i < MAX_NUM_THREADS; i++) {
if (pthread_join(tids[i], NULL) != 0) {
printf("Thread join failed\n");
}
}
printf("Exit\n");
return 0;
}
Output:
Enter thread 0
Enter thread 1
Enter thread 2
pthread_join
Exit
hello @tonibofarull , Thanks for your reply and solution share another test result: when I set iwasm main thread higher priority than default user thread, It works fine. so I think maybe have some synchronization issue in wasm, what do you think?
Thanks.
in the wasi-libc: int __pthread_create
ret = __wasi_thread_spawn((void *) args); //will let os task switch to run new thread
//but after that value changed: *res = new;
so if target thread priority lower than current thread, new thread will not start immediately, the *res = new; will first execute
so currently this dependent on priority except have some api just create thread but not start, after some work then enable it running
Interesting! While we find a better solution, if you want to keep passing tids in args, you can synchronize the threads yourself at the WASM app level. I'm studying right now the internals of wasi-threads.
in fact, there is no requirement about this, just a interesting finding to your team, if it can make the wasm improve stability, I will very happy.