Implement pthread_setname_np

Fixes: #12216
diff --git a/src/library_pthread.js b/src/library_pthread.js
index 9d5f833..a406697 100644
--- a/src/library_pthread.js
+++ b/src/library_pthread.js
@@ -60,6 +60,9 @@
     pthreads: {},
 #if ASSERTIONS
     nextWorkerID: 1,
+    // This doesn't seem to current do anything in chrome devtools and the
+    // worker name is instead fixed at worker creation time
+    setName: (name) => { globalThis.name = name; },
     debugInit: function() {
       function pthreadLogPrefix() {
         var t = 0;
@@ -479,7 +482,7 @@
         worker = new Worker(p.createScriptURL('ignored'));
       } else
 #endif
-      worker = new Worker(pthreadMainJs);
+      worker = new Worker(pthreadMainJs, {name: 'xxx'});
 #if EXPORT_ES6 && USE_ES6_IMPORT_META
     }
 #endif
@@ -889,6 +892,15 @@
 #endif
   },
 
+#if ASSERTIONS
+  _emscripten_set_js_thread_name__sig: 'vp',
+  _emscripten_set_js_thread_name: function(name) {
+    if (ENVIRONMENT_IS_PTHREAD) {
+      PThread.setName(UTF8ToString(name));
+    }
+  },
+#endif
+
   __pthread_kill_js__deps: ['emscripten_main_browser_thread_id'],
   __pthread_kill_js: function(thread, signal) {
     if (signal === {{{ cDefine('SIGCANCEL') }}}) { // Used by pthread_cancel in musl
@@ -1063,6 +1075,9 @@
 #if PTHREADS_DEBUG
     dbg('invokeEntryPoint: ' + ptrToString(ptr));
 #endif
+#if ASSERTIONS
+    PThread.setName('pthread worker ' + Module['workerID']);
+#endif
 #if MAIN_MODULE
     // Before we call the thread entry point, make sure any shared libraries
     // have been loaded on this there.  Otherwise our table migth be not be
diff --git a/system/include/emscripten/threading.h b/system/include/emscripten/threading.h
index ed1b29a..6e9a53f 100644
--- a/system/include/emscripten/threading.h
+++ b/system/include/emscripten/threading.h
@@ -257,7 +257,7 @@
 // The name parameter is a UTF-8 encoded string which is truncated to 32 bytes.
 // When thread profiler is not enabled (not building with --threadprofiler),
 // this is a no-op.
-void emscripten_set_thread_name(pthread_t threadId, const char *name);
+void emscripten_set_thread_name(pthread_t thread, const char *name);
 
 // Gets the stored pointer to a string representing the canvases to transfer to
 // the created thread.
diff --git a/system/lib/libc/crt1_proxy_main.c b/system/lib/libc/crt1_proxy_main.c
index 7934aac..c1fb794 100644
--- a/system/lib/libc/crt1_proxy_main.c
+++ b/system/lib/libc/crt1_proxy_main.c
@@ -24,7 +24,7 @@
 
 static void* _main_thread(void* param) {
   // This is the main runtime thread for the application.
-  emscripten_set_thread_name(pthread_self(), "Application main thread");
+  pthread_setname_np(pthread_self(), "Application main thread");
   // Will either call user's __main_void or weak version above.
   int rtn = __main_void();
   if (!emscripten_runtime_keepalive_check()) {
diff --git a/system/lib/libc/musl/src/thread/pthread_setname_np.c b/system/lib/libc/musl/src/thread/pthread_setname_np.c
index fc2d230..404c6a6 100644
--- a/system/lib/libc/musl/src/thread/pthread_setname_np.c
+++ b/system/lib/libc/musl/src/thread/pthread_setname_np.c
@@ -2,12 +2,18 @@
 #include <fcntl.h>
 #include <string.h>
 #include <unistd.h>
+#ifndef __EMSCRIPTEN__
 #include <sys/prctl.h>
+#endif
 
 #include "pthread_impl.h"
 
 int pthread_setname_np(pthread_t thread, const char *name)
 {
+#if __EMSCRIPTEN__
+	emscripten_set_thread_name(thread, name);
+	return 0;
+#else
 	int fd, cs, status = 0;
 	char f[sizeof "/proc/self/task//comm" + 3*sizeof(int)];
 	size_t len;
@@ -23,4 +29,5 @@
 	if (fd >= 0) close(fd);
 	pthread_setcancelstate(cs, 0);
 	return status;
+#endif
 }
diff --git a/system/lib/pthread/emscripten_set_thread_name.c b/system/lib/pthread/emscripten_set_thread_name.c
new file mode 100644
index 0000000..25c4d24
--- /dev/null
+++ b/system/lib/pthread/emscripten_set_thread_name.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2021 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 <string.h>
+
+#include <emscripten/proxying.h>
+
+#include "threading_internal.h"
+#include "pthread_impl.h"
+
+#ifndef NDEBUG
+// JS function for setting thread name within devtools.
+void _emscripten_set_js_thread_name(const char* name);
+
+static void set_js_thread_name(void* arg) {
+  const char* name = (const char*)arg;
+  _emscripten_set_js_thread_name(name);
+}
+#endif
+
+void emscripten_set_thread_name(pthread_t thread, const char* name) {
+  if (thread->profilerBlock) {
+    strncpy(thread->profilerBlock->name, name, EM_THREAD_NAME_MAX-1);
+  }
+#ifndef NDEBUG
+  if (thread == pthread_self()) {
+    _emscripten_set_js_thread_name(name);
+  } else {
+    emscripten_proxy_sync(emscripten_proxy_get_system_queue(),
+                          thread,
+                          set_js_thread_name,
+                          (void*)name);
+  }
+#endif
+}
diff --git a/system/lib/pthread/thread_profiler.c b/system/lib/pthread/thread_profiler.c
index 5598ed0..8f85d24 100644
--- a/system/lib/pthread/thread_profiler.c
+++ b/system/lib/pthread/thread_profiler.c
@@ -15,7 +15,6 @@
 static bool enabled = false;
 
 #ifndef NDEBUG
-
 void _emscripten_thread_profiler_init(pthread_t thread) {
   assert(thread);
   if (!enabled) {
@@ -61,12 +60,4 @@
   _emscripten_thread_profiler_init(pthread_self());
   emscripten_set_thread_name(pthread_self(), "Browser main thread");
 }
-
 #endif
-
-void emscripten_set_thread_name(pthread_t thread, const char* name) {
-  if (!enabled) {
-    return;
-  }
-  strncpy(thread->profilerBlock->name, name, EM_THREAD_NAME_MAX-1);
-}
diff --git a/system/lib/pthread/threading_internal.h b/system/lib/pthread/threading_internal.h
index 3cf88e9..24151c4 100644
--- a/system/lib/pthread/threading_internal.h
+++ b/system/lib/pthread/threading_internal.h
@@ -8,6 +8,7 @@
 #pragma once
 
 #include <pthread.h>
+#include <stdint.h>
 
 typedef union em_variant_val {
   int i;
diff --git a/test/test_browser.py b/test/test_browser.py
index 8100ccb..4f1a580 100644
--- a/test/test_browser.py
+++ b/test/test_browser.py
@@ -3872,7 +3872,7 @@
     def test(args):
       print(args)
       self.btest_exit(test_file('pthread/test_pthread_create.cpp'),
-                      args=['-sINITIAL_MEMORY=64MB', '-sUSE_PTHREADS', '-sPTHREAD_POOL_SIZE=8'] + args,
+                      args=['-sINITIAL_MEMORY=64MB', '-sPROXY_TO_PTHREAD', '-sUSE_PTHREADS', '-sPTHREAD_POOL_SIZE=8'] + args,
                       extra_tries=0) # this should be 100% deterministic
     print() # new line
     test([])
diff --git a/test/test_other.py b/test/test_other.py
index 20cb663..30a643e 100644
--- a/test/test_other.py
+++ b/test/test_other.py
@@ -11516,8 +11516,8 @@
 
   @node_pthreads
   def test_threadprofiler(self):
-    self.run_process([EMCC, test_file('test_threadprofiler.cpp'), '-sUSE_PTHREADS', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME', '--threadprofiler', '-sASSERTIONS'])
-    output = self.run_js('a.out.js')
+    output = self.do_runf(test_file('test_threadprofiler.cpp'), emcc_args=['-sUSE_PTHREADS', '-sPROXY_TO_PTHREAD', '-sEXIT_RUNTIME', '--threadprofiler', '-sASSERTIONS'])
+    print(output)
     self.assertRegex(output, r'Thread "Browser main thread" \(0x.*\) now: running.')
     self.assertRegex(output, r'Thread "Application main thread" \(0x.*\) now: waiting for a futex.')
     self.assertRegex(output, r'Thread "test worker" \(0x.*\) now: sleeping.')
diff --git a/test/test_threadprofiler.cpp b/test/test_threadprofiler.cpp
index bdd8b01..624a807 100644
--- a/test/test_threadprofiler.cpp
+++ b/test/test_threadprofiler.cpp
@@ -1,9 +1,8 @@
 #include <pthread.h>
 #include <unistd.h>
-#include <emscripten/threading.h>
 
 void* worker_thread(void*) {
-  emscripten_set_thread_name(pthread_self(), "test worker");
+  pthread_setname_np(pthread_self(), "test worker");
   for (int i = 0; i < 2; i++) {
     usleep(1000*1000);
   }
diff --git a/tools/system_libs.py b/tools/system_libs.py
index 2bcfeb0..daabd27 100644
--- a/tools/system_libs.py
+++ b/tools/system_libs.py
@@ -989,8 +989,7 @@
         '__unmapself.c',
         # Empty files, simply ignore them.
         'syscall_cp.c', 'tls.c',
-        # TODO: Support these. See #12216.
-        'pthread_setname_np.c',
+        # TODO: Support this. See #12216.
         'pthread_getname_np.c',
       ]
       libc_files += files_in_path(
@@ -1006,12 +1005,14 @@
           'emscripten_futex_wait.c',
           'emscripten_futex_wake.c',
           'emscripten_yield.c',
+          'thread_profiler.c',
         ])
     else:
       ignore += ['thread']
       libc_files += files_in_path(
         path='system/lib/libc/musl/src/thread',
         filenames=[
+          'pthread_setname_np.c',
           'pthread_self.c',
           'pthread_cleanup_push.c',
           'pthread_attr_get.c',
@@ -1149,7 +1150,7 @@
 
     libc_files += files_in_path(
         path='system/lib/pthread',
-        filenames=['emscripten_atomic.c', 'thread_profiler.c'])
+        filenames=['emscripten_atomic.c', 'emscripten_set_thread_name.c'])
 
     libc_files += glob_in_path('system/lib/libc/compat', '*.c')