When futex(2) got imported it didn't return ECANCELED. This was changed later with futex-based semaphores.
This modification introduced a behavior change in pthread_cond_*wait(3). The diff below restores the previous behavior by treating ECANCELED like EINTR. Note that the __thrsleep(2) version also doesn't completely check for ECANCELED, this diff also changes that. Ok? Index: rthread_cond.c =================================================================== RCS file: /cvs/src/lib/libc/thread/rthread_cond.c,v retrieving revision 1.5 diff -u -p -r1.5 rthread_cond.c --- rthread_cond.c 29 Jan 2019 17:40:26 -0000 1.5 +++ rthread_cond.c 18 Jan 2020 13:10:56 -0000 @@ -109,13 +109,13 @@ _rthread_cond_timedwait(pthread_cond_t c * we should just go back to sleep without changing state * (timeouts, etc). */ - } while ((error == EINTR) && + } while ((error == EINTR || error == ECANCELED) && (tib->tib_canceled == 0 || (tib->tib_cantcancel & CANCEL_DISABLED))); /* if timeout or canceled, make note of that */ if (error == ETIMEDOUT) rv = ETIMEDOUT; - else if (error == EINTR) + else if (error == EINTR || error == ECANCELED) canceled = 1; pthread_mutex_lock(mutexp); Index: rthread_sync.c =================================================================== RCS file: /cvs/src/lib/libc/thread/rthread_sync.c,v retrieving revision 1.5 diff -u -p -r1.5 rthread_sync.c --- rthread_sync.c 24 Apr 2018 16:28:42 -0000 1.5 +++ rthread_sync.c 18 Jan 2020 13:15:01 -0000 @@ -407,7 +407,7 @@ pthread_cond_timedwait(pthread_cond_t *c /* if timeout or canceled, make note of that */ if (error == EWOULDBLOCK) rv = ETIMEDOUT; - else if (error == EINTR) + else if (error == EINTR || error = ECANCELED) canceled = 1; /* transfer between the queues */