diff --git a/libc-top-half/musl/src/internal/pthread_impl.h b/libc-top-half/musl/src/internal/pthread_impl.h index 41106c752..33dcf5845 100644 --- a/libc-top-half/musl/src/internal/pthread_impl.h +++ b/libc-top-half/musl/src/internal/pthread_impl.h @@ -70,6 +70,7 @@ struct pthread { void *stdio_locks; #ifdef __wasi_cooperative_threads__ volatile int joiner_futex; + char name[16]; #endif /* Part 3 -- the positions of these fields relative to diff --git a/libc-top-half/musl/src/thread/coop-threads/pthread_create.c b/libc-top-half/musl/src/thread/coop-threads/pthread_create.c index 953a8a47c..851db0d0a 100644 --- a/libc-top-half/musl/src/thread/coop-threads/pthread_create.c +++ b/libc-top-half/musl/src/thread/coop-threads/pthread_create.c @@ -280,6 +280,7 @@ int __pthread_create(pthread_t *restrict res, new->robust_list.head = &new->robust_list.head; new->canary = self->canary; new->sysinfo = self->sysinfo; + new->name[0] = 0; // Setup argument structure for the new thread on its stack. diff --git a/libc-top-half/musl/src/thread/coop-threads/pthread_getname_np.c b/libc-top-half/musl/src/thread/coop-threads/pthread_getname_np.c index 014405174..6b8d0696a 100644 --- a/libc-top-half/musl/src/thread/coop-threads/pthread_getname_np.c +++ b/libc-top-half/musl/src/thread/coop-threads/pthread_getname_np.c @@ -1,6 +1,11 @@ - +#define _GNU_SOURCE +#include #include "pthread_impl.h" int pthread_getname_np(pthread_t thread, char *name, size_t len) { - return ENOTSUP; + size_t n = strlen(thread->name); + if (n >= len) + return ERANGE; + strcpy(name, thread->name); + return 0; } diff --git a/libc-top-half/musl/src/thread/coop-threads/pthread_setname_np.c b/libc-top-half/musl/src/thread/coop-threads/pthread_setname_np.c index d49f60c17..cd293dadc 100644 --- a/libc-top-half/musl/src/thread/coop-threads/pthread_setname_np.c +++ b/libc-top-half/musl/src/thread/coop-threads/pthread_setname_np.c @@ -1,3 +1,11 @@ +#define _GNU_SOURCE +#include #include "pthread_impl.h" -int pthread_setname_np(pthread_t thread, const char *name) { return ENOTSUP; } +int pthread_setname_np(pthread_t thread, const char *name) { + size_t len = strlen(name); + if (len > 15) + return ERANGE; + strcpy(thread->name, name); + return 0; +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 4823bf367..0361df970 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -504,6 +504,7 @@ endif() if (ENABLE_COOP_THREADS) add_wasilibc_test(coop_smoke.c) + add_wasilibc_test(coop_thread_name.c) add_wasilibc_test(coop_sem_multiwaiter.c) add_wasilibc_test(coop_cond_signal_wakeup.c) add_wasilibc_test(coop_stdio_orphan_lock.c) diff --git a/test/src/coop_thread_name.c b/test/src/coop_thread_name.c new file mode 100644 index 000000000..0b424c2a7 --- /dev/null +++ b/test/src/coop_thread_name.c @@ -0,0 +1,75 @@ +#define _GNU_SOURCE +#include "test.h" +#include +#include +#include +#include + +#define TEST(c) \ + do { \ + if (!(c)) \ + t_error("%s failed\n", #c); \ + } while (0) + +static sem_t go; +static sem_t named; +static sem_t checked; + +static void *worker(void *arg) { + (void)arg; + char buf[16]; + + // The name set by the main thread is visible here. + TEST(sem_wait(&go) == 0); + TEST(pthread_getname_np(pthread_self(), buf, sizeof(buf)) == 0); + TEST(strcmp(buf, "from-main") == 0); + + // Rename ourselves and let the main thread observe it. + TEST(pthread_setname_np(pthread_self(), "from-worker") == 0); + TEST(sem_post(&named) == 0); + TEST(sem_wait(&checked) == 0); + return NULL; +} + +int main(void) { + char buf[32]; + + // The main thread starts out with no name. + TEST(pthread_getname_np(pthread_self(), buf, sizeof(buf)) == 0); + TEST(strcmp(buf, "") == 0); + + TEST(pthread_setname_np(pthread_self(), "main-thread") == 0); + TEST(pthread_getname_np(pthread_self(), buf, sizeof(buf)) == 0); + TEST(strcmp(buf, "main-thread") == 0); + + // size limits + TEST(pthread_setname_np(pthread_self(), "123456789012345") == 0); + TEST(pthread_getname_np(pthread_self(), buf, sizeof(buf)) == 0); + TEST(strcmp(buf, "123456789012345") == 0); + TEST(pthread_setname_np(pthread_self(), "1234567890123456") == ERANGE); + + char small[4]; + TEST(pthread_getname_np(pthread_self(), small, sizeof(small)) == ERANGE); + char exact[16]; + TEST(pthread_getname_np(pthread_self(), exact, sizeof(exact)) == 0); + TEST(strcmp(exact, "123456789012345") == 0); + + // Names can be set and read across threads. + TEST(sem_init(&go, 0, 0) == 0); + TEST(sem_init(&named, 0, 0) == 0); + TEST(sem_init(&checked, 0, 0) == 0); + pthread_t t; + pthread_attr_t attr; + TEST(pthread_attr_init(&attr) == 0); + TEST(pthread_create(&t, &attr, worker, NULL) == 0); + TEST(pthread_setname_np(t, "from-main") == 0); + TEST(sem_post(&go) == 0); + + TEST(sem_wait(&named) == 0); + TEST(pthread_getname_np(t, buf, sizeof(buf)) == 0); + TEST(strcmp(buf, "from-worker") == 0); + TEST(sem_post(&checked) == 0); + + TEST(pthread_join(t, NULL) == 0); + return t_status; +}