Module Name: src Committed By: thorpej Date: Thu Aug 5 23:23:50 UTC 2021
Modified Files: src/sys/kern [thorpej-futex2]: sys_futex.c Log Message: At the end of futex_wait(), when sleepq_block() returns 0, we would like to assert that l->l_futex == NULL, because all of the code paths that awaken a blocked thread in sys_futex.c itself clear l->l_futex. Unfortunately, there are certain received-a-signal situations (e.g. SIGKILL) where sleepq_block() will not return an error after being awakened by the signal, rendering this assertion too strong. So, rather than going down the rabbit hole of reasoning out and altering long-standing behavior of the signals code, just don't assert there and treat a zero-return from sleepq_block() as an aborted futex wait if l->l_futex != NULL. (Thanks chs@ for helping chase this one down.) To generate a diff of this commit: cvs rdiff -u -r1.12.4.1 -r1.12.4.2 src/sys/kern/sys_futex.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/sys_futex.c diff -u src/sys/kern/sys_futex.c:1.12.4.1 src/sys/kern/sys_futex.c:1.12.4.2 --- src/sys/kern/sys_futex.c:1.12.4.1 Thu Aug 5 23:14:21 2021 +++ src/sys/kern/sys_futex.c Thu Aug 5 23:23:50 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: sys_futex.c,v 1.12.4.1 2021/08/05 23:14:21 thorpej Exp $ */ +/* $NetBSD: sys_futex.c,v 1.12.4.2 2021/08/05 23:23:50 thorpej Exp $ */ /*- * Copyright (c) 2018, 2019, 2020 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sys_futex.c,v 1.12.4.1 2021/08/05 23:14:21 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_futex.c,v 1.12.4.2 2021/08/05 23:23:50 thorpej Exp $"); /* * Futexes @@ -1122,8 +1122,23 @@ futex_wait(struct futex *f, int q, const else if (error != ETIMEDOUT) error = EINTR; } else { - KASSERT(l->l_futex == NULL); - SDT_PROBE0(futex, wait, finish, normally); + f = l->l_futex; + if (__predict_false(f != NULL)) { + /* + * There are certain situations that can cause + * sleepq_block() to return 0 even if we were + * signalled (by e.g. SIGKILL). In this case, + * we will need to release our futex hold and + * return EINTR (we're probably about to die + * anyway). + */ + SDT_PROBE0(futex, wait, finish, aborted); + l->l_futex = NULL; + futex_rele(f); + error = EINTR; + } else { + SDT_PROBE0(futex, wait, finish, normally); + } } return error;