Skip to content

pthread: wake cond/sem waiters when cancelled - #428

Closed
derfsss wants to merge 1 commit into
AmigaLabs:developmentfrom
derfsss:fix/pthread-cancel-cond-wait
Closed

pthread: wake cond/sem waiters when cancelled#428
derfsss wants to merge 1 commit into
AmigaLabs:developmentfrom
derfsss:fix/pthread-cancel-cond-wait

Conversation

@derfsss

@derfsss derfsss commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Problem

pthread_cancel() of a thread blocked in pthread_cond_wait / pthread_cond_timedwait / sem_wait (which is built on the cond wait) is never acted upon: the target never wakes, and a subsequent pthread_join on it blocks forever.

The cause: pthread_cancel() signals the target's dedicated cancel signal (inf->cancel_signal_mask), but _pthread_cond_timedwait() does not include that signal in its Wait() mask — it only waits on the condvar waiter bit, the optional timer bit and SIGBREAKF_CTRL_C.

Repro

pthread_create(&t, NULL, fn_that_cond_waits_forever, NULL);
sleep(1);
pthread_cancel(t);      /* returns 0 */
pthread_join(t, &res);  /* hangs forever */

Fix

Include the dedicated cancel signal in the wait mask and run pthread_testcancel() when woken by it — exactly as is already done for the SIGBREAKF_CTRL_C fallback. The existing cancellation cleanup handler (CondWaitCleanupHandler) already handles waiter-node removal and mutex reacquisition for this path, so cancellation semantics match POSIX (mutex is reacquired before cleanup handlers run).

Validation

Tested on AmigaOS 4.1 FE (QEMU amigaone) with a clean GNUmakefile.os4 build of this branch: cancel + join of a cond-parked thread and of a sem-parked thread both complete with PTHREAD_CANCELED. Found while porting OpenJDK 17 to AmigaOS 4, where JVM daemon threads parked in pthread_cond_wait could never be cancelled at VM shutdown.

🤖 Generated with Claude Code

pthread_cancel() signals the target thread''s dedicated cancel signal
(inf->cancel_signal_mask), but _pthread_cond_timedwait() does not
include that signal in its Wait() mask -- it only waits on the condvar
waiter bit, the optional timer bit and SIGBREAKF_CTRL_C.  As a result a
thread parked in pthread_cond_wait / pthread_cond_timedwait / sem_wait
(which is built on the cond wait) never wakes when cancelled, and a
subsequent pthread_join on it blocks forever.

Repro:

    pthread_create(&t, NULL, fn_that_cond_waits_forever, NULL);
    sleep(1);
    pthread_cancel(t);   /* returns 0 */
    pthread_join(t, &res);  /* hangs forever */

Fix: include the dedicated cancel signal in the wait mask and run
pthread_testcancel() when woken by it, exactly as is already done for
the SIGBREAKF_CTRL_C fallback.  The existing cancellation cleanup
handler (CondWaitCleanupHandler) already handles waiter-node removal
and mutex reacquisition for this path, and the mutex is reacquired
before cancellation cleanup runs, as POSIX requires.

Found porting OpenJDK 17 to AmigaOS 4: JVM daemon threads parked in
pthread_cond_wait could never be cancelled at VM shutdown.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@afxgroup

Copy link
Copy Markdown
Collaborator

Can you please try all pthreads examples in test_library/threads folder? just go in test_library and compile everything with make. We need to be sure that we don't broke anything on that examples

@afxgroup afxgroup closed this Jun 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants