Skip to content

Commit 2515780

Browse files
derfsssclaude
andcommitted
pthread: cancel remaining live threads at process exit
__pthread_exit_func() joins every non-idle joinable thread and spin-waits for detached ones. If the program exits while a daemon-style thread is parked forever in pthread_cond_wait / sem_wait, that loop never completes and the process becomes unkillable -- the exit handshake hangs in pthread_join. On POSIX systems exit() terminates all remaining threads. Approximate those semantics: request cancellation of every live thread before the join/wait loop. Parked threads wake (see previous commit), run their cancellation cleanup handlers, and exit through the normal pthread path, so dos.library''s parent/child process accounting stays intact; the existing join loop then completes as before. Threads that exit promptly on their own are unaffected: cancellation is deferred and only acts at cancellation points. Found porting OpenJDK 17 to AmigaOS 4: java prints its output, then the process hung forever in __pthread_exit_func joining the parked JVM daemon threads. With this change the JVM exits cleanly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 277723f commit 2515780

1 file changed

Lines changed: 14 additions & 0 deletions

File tree

library/pthread/pthread.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,20 @@ void __pthread_exit_func(void) {
488488
struct DOSIFace *IDOS = _IDOS;
489489
SHOWMSG("[__pthread_exit_func :] Pthread __pthread_exit_func called.\n");
490490

491+
/* A thread that never exits by itself (a daemon-style worker parked
492+
* in pthread_cond_wait / sem_wait) would wedge the join/wait loop
493+
* below forever, making the process unkillable. On POSIX systems
494+
* exit() simply terminates the remaining threads. Approximate that:
495+
* request cancellation of every live thread first, so parked threads
496+
* wake, run their cancellation cleanup handlers and leave through
497+
* the normal pthread exit path -- which keeps dos.library's
498+
* parent/child process accounting intact (no force-removal). */
499+
for (i = PTHREAD_FIRST_THREAD_ID; i < PTHREAD_THREADS_MAX; i++) {
500+
inf = &threads[i];
501+
if (inf->status != THREAD_STATE_IDLE && inf->task != NULL)
502+
pthread_cancel(i);
503+
}
504+
491505
// if we don't do this we can easily end up with unloaded code being executed
492506
for (i = PTHREAD_FIRST_THREAD_ID; i < PTHREAD_THREADS_MAX; i++) {
493507
inf = &threads[i];

0 commit comments

Comments
 (0)