Skip to content

Commit bfa8d67

Browse files
committed
refactor(pthread): remove PThread.runningWorkers
Remove `PThread.runningWorkers` and use `PThread.pthreads` instead to track running workers. `PThread.pthreads` already contains all the necessary information, and keeping both in sync was redundant. This also optimizes thread exit by replacing an O(N) array splice with an O(1) map deletion, at the cost of making count queries (mostly used in tests) O(N) instead of O(1). TAG=agy CONV=47f918e2-bd47-4e38-9a6d-af1765cf2f7e
1 parent 7b8b5bc commit bfa8d67

8 files changed

Lines changed: 20 additions & 23 deletions

ChangeLog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ See docs/process.md for more on how version tagging works.
5555
implied). Also, if you include real dynamic libraries in your link command
5656
emscripten will now automatically produce a dynamically linked program
5757
(`-sMAIN_MODULE=2` is implied). (#25930)
58+
- The `PThread.runningWorkers` field was removed from the `PThread` object.
59+
If you have JS code that was depending on this you can transition to using the
60+
`PThread.pthreads` object. (#26998)
5861

5962
5.0.7 - 04/30/26
6063
----------------

src/lib/libpthread.js

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,6 @@ var LibraryPThread = {
108108
// terminated, but is returned to this pool as an optimization so that
109109
// starting the next thread is faster.
110110
unusedWorkers: [],
111-
// Contains all Workers that are currently hosting an active pthread.
112-
runningWorkers: [],
113111
tlsInitFunctions: [],
114112
// Maps pthread_t pointers to the workers on which they are running. For
115113
// the reverse mapping, each worker has a `pthread_ptr` when its running a
@@ -191,14 +189,13 @@ var LibraryPThread = {
191189
// pthreads will continue to be executing after `worker.terminate` has
192190
// returned. For this reason, we don't call `returnWorkerToPool` here or
193191
// free the underlying pthread data structures.
194-
for (var worker of PThread.runningWorkers) {
192+
for (var worker of Object.values(PThread.pthreads)) {
195193
terminateWorker(worker);
196194
}
197195
for (var worker of PThread.unusedWorkers) {
198196
terminateWorker(worker);
199197
}
200198
PThread.unusedWorkers = [];
201-
PThread.runningWorkers = [];
202199
PThread.pthreads = {};
203200
},
204201

@@ -229,7 +226,6 @@ var LibraryPThread = {
229226
// Note: worker is intentionally not terminated so the pool can
230227
// dynamically grow.
231228
PThread.unusedWorkers.push(worker);
232-
PThread.runningWorkers.splice(PThread.runningWorkers.indexOf(worker), 1);
233229
// Not a running Worker anymore
234230
// Detach the worker from the pthread object, and return it to the
235231
// worker pool as an unused worker.
@@ -710,8 +706,6 @@ var LibraryPThread = {
710706
assert(!worker.pthread_ptr);
711707
#endif
712708

713-
PThread.runningWorkers.push(worker);
714-
715709
// Add to pthreads map
716710
PThread.pthreads[threadParams.pthread_ptr] = worker;
717711

test/codesize/test_codesize_minimal_pthreads.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
2-
"a.out.js": 7143,
3-
"a.out.js.gz": 3542,
2+
"a.out.js": 7110,
3+
"a.out.js.gz": 3522,
44
"a.out.nodebug.wasm": 19037,
55
"a.out.nodebug.wasm.gz": 8787,
6-
"total": 26180,
7-
"total_gz": 12329,
6+
"total": 26147,
7+
"total_gz": 12309,
88
"sent": [
99
"a (memory)",
1010
"b (exit)",

test/codesize/test_codesize_minimal_pthreads_memgrowth.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
{
2-
"a.out.js": 7551,
3-
"a.out.js.gz": 3745,
2+
"a.out.js": 7518,
3+
"a.out.js.gz": 3725,
44
"a.out.nodebug.wasm": 19038,
55
"a.out.nodebug.wasm.gz": 8788,
6-
"total": 26589,
7-
"total_gz": 12533,
6+
"total": 26556,
7+
"total_gz": 12513,
88
"sent": [
99
"a (memory)",
1010
"b (exit)",

test/other/test_pthread_reuse.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ void* thread_main(void* arg) {
2424
}
2525

2626
void checkThreadPool() {
27-
int running = EM_ASM_INT(return PThread.runningWorkers.length);
27+
int running = EM_ASM_INT(return Object.keys(PThread.pthreads).length);
2828
int unused = EM_ASM_INT(return PThread.unusedWorkers.length);
2929
printf("running=%d unused=%d\n", running, unused);
3030
assert(running == 0);

test/pthread/test_pthread_join.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ int main() {
3434

3535
pthread_t thr;
3636

37-
assert(EM_ASM_INT(return PThread.runningWorkers.length) == 0);
37+
assert(EM_ASM_INT(return Object.keys(PThread.pthreads).length) == 0);
3838
assert(EM_ASM_INT(return PThread.unusedWorkers.length) == 8); // This test should be run with a prepopulated pool of size 8.
3939

4040
intptr_t n = 20;
@@ -44,14 +44,14 @@ int main() {
4444
emscripten_out("Main: Waiting for thread to join");
4545
int result = 0;
4646

47-
assert(EM_ASM_INT(return PThread.runningWorkers.length) == 1);
47+
assert(EM_ASM_INT(return Object.keys(PThread.pthreads).length) == 1);
4848
assert(EM_ASM_INT(return PThread.unusedWorkers.length) == 7);
4949

5050
s = pthread_join(thr, (void**)&result);
5151
assert(s == 0);
5252
emscripten_outf("Main: Thread joined with result: %d", result);
5353

54-
assert(EM_ASM_INT(return PThread.runningWorkers.length) == 0);
54+
assert(EM_ASM_INT(return Object.keys(PThread.pthreads).length) == 0);
5555
assert(EM_ASM_INT(return PThread.unusedWorkers.length) == 8);
5656

5757
assert(result == 6765);

test/pthread/test_pthread_preallocates_workers.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ int main()
3838
// This test should be run with a prewarmed pool of size 4. None
3939
// of the threads are allocated yet.
4040
assert(EM_ASM_INT(return PThread.unusedWorkers.length) == 4);
41-
assert(EM_ASM_INT(return PThread.runningWorkers.length) == 0);
41+
assert(EM_ASM_INT(return Object.keys(PThread.pthreads).length) == 0);
4242

4343
CreateThread(0);
4444

4545
// We have one running thread, allocated on demand.
4646
assert(EM_ASM_INT(return PThread.unusedWorkers.length) == 3);
47-
assert(EM_ASM_INT(return PThread.runningWorkers.length) == 1);
47+
assert(EM_ASM_INT(return Object.keys(PThread.pthreads).length) == 1);
4848

4949
for (int i = 1; i < 5; ++i) {
5050
CreateThread(i);
@@ -56,7 +56,7 @@ int main()
5656
// solved in non-test cases by using PROXY_TO_PTHREAD, but we can't
5757
// do that here since we need to eval the length of the various pthread
5858
// arrays.
59-
assert(EM_ASM_INT(return PThread.runningWorkers.length) == 5);
59+
assert(EM_ASM_INT(return Object.keys(PThread.pthreads).length) == 5);
6060
assert(EM_ASM_INT(return PThread.unusedWorkers.length) == 0);
6161

6262
return 0;

test/pthread/test_std_thread_detach.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ void EMSCRIPTEN_KEEPALIVE spawn_a_thread() {
2424
void EMSCRIPTEN_KEEPALIVE count_threads(int num_threads_spawned, int num_threads_spawned_extra) {
2525
num_threads_spawned += num_threads_spawned_extra;
2626
int num_workers = EM_ASM_INT({
27-
return PThread.runningWorkers.length + PThread.unusedWorkers.length;
27+
return Object.keys(PThread.pthreads).length + PThread.unusedWorkers.length;
2828
});
2929

3030
std::cout <<

0 commit comments

Comments
 (0)