git: 030f48f78f96 - main - pthread_setcancelstate(3): make it async-signal-safe

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sat, 28 Dec 2024 17:20:25 UTC
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=030f48f78f96e0cdb30c960e1a11e5ae01d0eee8

commit 030f48f78f96e0cdb30c960e1a11e5ae01d0eee8
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-12-23 06:42:15 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-12-28 17:01:50 +0000

    pthread_setcancelstate(3): make it async-signal-safe
    
    by setting new cancel state and reading old cancel state from the
    curthread structure atomic.
    
    Note that this does not play well with async cancellation, since if
    cancellation is enabled from a signal handler and cancellation request
    is pending, the thread is cancelled immediately, calling user-defined
    destructors, which all must be async-signal-safe (but this is a general
    requirement for async cancellation anyway).
    
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D48200
---
 lib/libthr/thread/thr_cancel.c      | 12 ++++++------
 share/man/man3/pthread_testcancel.3 |  6 ++++++
 2 files changed, 12 insertions(+), 6 deletions(-)

diff --git a/lib/libthr/thread/thr_cancel.c b/lib/libthr/thread/thr_cancel.c
index 7622e306f937..4189a2640d14 100644
--- a/lib/libthr/thread/thr_cancel.c
+++ b/lib/libthr/thread/thr_cancel.c
@@ -83,22 +83,22 @@ int
 _thr_setcancelstate(int state, int *oldstate)
 {
 	struct pthread *curthread = _get_curthread();
-	int oldval;
+	int oldval, val;
 
-	oldval = curthread->cancel_enable;
 	switch (state) {
 	case PTHREAD_CANCEL_DISABLE:
-		curthread->cancel_enable = 0;
+		val = 0;
 		break;
 	case PTHREAD_CANCEL_ENABLE:
-		curthread->cancel_enable = 1;
-		if (curthread->cancel_async)
-			testcancel(curthread);
+		val = 1;
 		break;
 	default:
 		return (EINVAL);
 	}
 
+	oldval = atomic_swap_int(&curthread->cancel_enable, val);
+	if (state == PTHREAD_CANCEL_ENABLE && curthread->cancel_async)
+		testcancel(curthread);
 	if (oldstate != NULL) {
 		*oldstate = oldval ? PTHREAD_CANCEL_ENABLE :
 		    PTHREAD_CANCEL_DISABLE;
diff --git a/share/man/man3/pthread_testcancel.3 b/share/man/man3/pthread_testcancel.3
index 2d2bb06c48e2..c74cdcfe943b 100644
--- a/share/man/man3/pthread_testcancel.3
+++ b/share/man/man3/pthread_testcancel.3
@@ -34,6 +34,7 @@ are
 .Dv PTHREAD_CANCEL_ENABLE
 and
 .Dv PTHREAD_CANCEL_DISABLE .
+The function is async-signal-safe.
 .Pp
 The
 .Fn pthread_setcanceltype
@@ -248,6 +249,11 @@ function conforms to
 .St -p1003.1-96 .
 The standard allows implementations to make many more functions
 cancellation points.
+.Pp
+The
+.Fn pthread_setcancelstate
+function is async-signal-safe as required by
+.St -p1003.1-2024 .
 .Sh AUTHORS
 This manual page was written by
 .An David Leonard Aq Mt d@openbsd.org