Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/2233154/?format=api
{ "id": 2233154, "url": "http://patchwork.ozlabs.org/api/1.2/patches/2233154/?format=api", "web_url": "http://patchwork.ozlabs.org/project/glibc/patch/20260505190809.3898686-4-adhemerval.zanella@linaro.org/", "project": { "id": 41, "url": "http://patchwork.ozlabs.org/api/1.2/projects/41/?format=api", "name": "GNU C Library", "link_name": "glibc", "list_id": "libc-alpha.sourceware.org", "list_email": "libc-alpha@sourceware.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260505190809.3898686-4-adhemerval.zanella@linaro.org>", "list_archive_url": null, "date": "2026-05-05T19:06:52", "name": "[v2,3/3] nptl: Only initialize robust list at mutex usage", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "52bf4a6557218aa73514edab01a909125658b617", "submitter": { "id": 66065, "url": "http://patchwork.ozlabs.org/api/1.2/people/66065/?format=api", "name": "Adhemerval Zanella Netto", "email": "adhemerval.zanella@linaro.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/glibc/patch/20260505190809.3898686-4-adhemerval.zanella@linaro.org/mbox/", "series": [ { "id": 502884, "url": "http://patchwork.ozlabs.org/api/1.2/series/502884/?format=api", "web_url": "http://patchwork.ozlabs.org/project/glibc/list/?series=502884", "date": "2026-05-05T19:06:49", "name": "nptl: Fix robust mutex support detection and defer robust list initialization", "version": 2, "mbox": "http://patchwork.ozlabs.org/series/502884/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2233154/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2233154/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "libc-alpha@sourceware.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "libc-alpha@sourceware.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256\n header.s=google header.b=AMFu/y49;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=sourceware.org\n (client-ip=38.145.34.32; helo=vm01.sourceware.org;\n envelope-from=libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256\n header.s=google header.b=AMFu/y49", "sourceware.org;\n dmarc=pass (p=none dis=none) header.from=linaro.org", "sourceware.org; spf=pass smtp.mailfrom=linaro.org", "server2.sourceware.org;\n arc=none smtp.remote-ip=2607:f8b0:4864:20::e2b" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g97Nc0QCjz1yJx\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 06 May 2026 05:08:59 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 27FF84BAD142\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 5 May 2026 19:08:58 +0000 (GMT)", "from mail-vs1-xe2b.google.com (mail-vs1-xe2b.google.com\n [IPv6:2607:f8b0:4864:20::e2b])\n by sourceware.org (Postfix) with ESMTPS id 5E9E74BA79A2\n for <libc-alpha@sourceware.org>; Tue, 5 May 2026 19:08:26 +0000 (GMT)", "by mail-vs1-xe2b.google.com with SMTP id\n ada2fe7eead31-62f390b8df7so1606684137.1\n for <libc-alpha@sourceware.org>; Tue, 05 May 2026 12:08:26 -0700 (PDT)", "from mandiga.. ([2804:1b3:a7c1:364:abee:44ff:b045:5a7])\n by smtp.gmail.com with ESMTPSA id\n a1e0cc1a2514c-95ce08f4a7asm7504046241.5.2026.05.05.12.08.22\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Tue, 05 May 2026 12:08:23 -0700 (PDT)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 27FF84BAD142", "OpenDKIM Filter v2.11.0 sourceware.org 5E9E74BA79A2" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 5E9E74BA79A2", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 5E9E74BA79A2", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1778008106; cv=none;\n b=dVJYK8BKXSkPK4kyQb0jnarin35M0V6cKwpFmsBdsTgrWhwhDnlape9LCqdCezbauGgwj9A1sAE3p3X73QOAhzo6OQbwYodUZLygwrG5I1AeTd5UW6rlqWZgcl2z9YOPbegnuMGKAKB3d19mRLmrYhZkxJMWJ+tn+xZCN99zI+4=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1778008106; c=relaxed/simple;\n bh=L3pZ5rrC4x2yTQdRKpOevEtZJizWu1R5GAEmoIUUrFo=;\n h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version;\n b=FTR99biuxUvJ/NtiCe0L2zitXtKzC8nloRIpOkxHxyR4af3pT5a6+McCC1D/h0LhC7f0u56DHM+LGFpF4aJYruUriCSzwms/H1Xlwp7O9JZKjjkzXF51JZhuu7g+zKuWQvcIsAhudjT768q5l1BU1HQMWjPHaQ2a99HO6F36Xc8=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=linaro.org; s=google; t=1778008105; x=1778612905; darn=sourceware.org;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n :message-id:reply-to;\n bh=jxFmbu9+XBXAKdKF0W4t5VOJl29THVzXXkcLcNbj4Ss=;\n b=AMFu/y49PzX1z6nfB0l9IE/2A1aAOeRDyV7pz3vReF0/0DyjDUIzgOUPohw8DYvPBL\n mqdgEf0DQN1kteKhUTE/kaoDYYJSAkyGBBK3GTxXqbNhNvcNAGhwiNHBQNZgvTJcpJKM\n RmeY0JF3GlAvnF8FpPgZ45oS4e31kGmqlDtX+MTVZn6q5E+EgI9vqkcAczKGPGjF22SI\n T8Zi9+pjmc4/g+cTUJ9UiSb8+xeMVufPBGLEE9UmVaZQanTAxQA/k2eV6K2wpWlXUAYg\n klRvp9DO4b/IPlveJxzb79Jka2uTQq41a/9Dn9rAg5FF7QtIz7AGMMt5dG1LsT4MqIhq\n FWdw==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1778008105; x=1778612905;\n h=content-transfer-encoding:mime-version:references:in-reply-to\n :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n :to:cc:subject:date:message-id:reply-to;\n bh=jxFmbu9+XBXAKdKF0W4t5VOJl29THVzXXkcLcNbj4Ss=;\n b=s9/rG3HV4P1l1k3pwzdQjOV/9+ZLybuz8iWJoc/rLRLzIJN7adLzQ6Q9XzutjcMvX2\n vRiwKoAFGhhlGzBF3qz0gQI7FWc7JecFX1ZZ6tgEaMoxnBHhJTlm/549UPrtZsD9XCJR\n yq+tS5JV4BJabVuw8I2OciJwyn1ipTJmSyDEHV80sEsO3eBdt9Zrof15IiZbwt8IoT+N\n nnXehISBFsrn6/aYQ+fo9OlB7y91Y2twLSSeD4oDPVgBabg4Vc9Xi6YMwF9u22gjsCTw\n IS33ulvhLeYwwtYPCQAW+GH68SZhPyweYb5w7OZYiQ6gk1agQZPjjn/MwH/Tk2tI5Ez5\n xwXg==", "X-Gm-Message-State": "AOJu0Yw6xPaXNtiMlREfhD6FANXVTnb7KKSTpQrUyC14mhHRJIhkdcQ/\n NN5RAy+utO+cSJRMKtFMCmRAcmcLsSobAx08zH7KIF22gETv0cIBcS2Di+XHGL60ZFZV1dT4cMA\n DAGEc", "X-Gm-Gg": "AeBDieseoYIbU1romLIXF+HLbw/G4iBsMnIWGCKlg/EsHeiEACSXnAd0f7Q7hfj2bnV\n e7Olw8bItrzFd9GWtBQi0DOM6gmxvNIH2gr0fXY7/TdJqYfOktL4zg2ASSaFArit+3sxKX31uyh\n xr2MfM7kj4xJGZQ9P6B/css43Ld43zaMQYhlUb1tPSoJ1X/ugpCP79Kzv60PH9L0R0/ZF/Cyc9K\n Ywg4mKtvW967O/vWATeVx0ne+sF3gGtESiQ4LEFGC1zP3jGBaE3qLwngJVTxchdrXNqBXhtnaW6\n isZWqkBFZB1DtIcre9WoNm5T6WX6BoXl/z0ghxjI/K9DaCDDG9qA8MugVvHxqVOCGVeMhWoupeq\n 9K+BAOx9bcP115tseE4iqJyW9RDdVjCzhLEpHz9j0Kk8JhoVAh3ieVN52vQw5UFSgbdST7WDh3T\n AQ1sG31ZD/jPsiHPrnj+zVLeHYDSKlAfp8MmYozPNP8Ac=", "X-Received": "by 2002:a05:6102:802a:b0:618:3503:5659 with SMTP id\n ada2fe7eead31-62f591dbcfemr3622245137.14.1778008104395;\n Tue, 05 May 2026 12:08:24 -0700 (PDT)", "From": "Adhemerval Zanella <adhemerval.zanella@linaro.org>", "To": "libc-alpha@sourceware.org", "Cc": "Florian Weimer <fweimer@redhat.com>", "Subject": "[PATCH v2 3/3] nptl: Only initialize robust list at mutex usage", "Date": "Tue, 5 May 2026 16:06:52 -0300", "Message-ID": "<20260505190809.3898686-4-adhemerval.zanella@linaro.org>", "X-Mailer": "git-send-email 2.43.0", "In-Reply-To": "<20260505190809.3898686-1-adhemerval.zanella@linaro.org>", "References": "<20260505190809.3898686-1-adhemerval.zanella@linaro.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit", "X-BeenThere": "libc-alpha@sourceware.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Libc-alpha mailing list <libc-alpha.sourceware.org>", "List-Unsubscribe": "<https://sourceware.org/mailman/options/libc-alpha>,\n <mailto:libc-alpha-request@sourceware.org?subject=unsubscribe>", "List-Archive": "<https://sourceware.org/pipermail/libc-alpha/>", "List-Post": "<mailto:libc-alpha@sourceware.org>", "List-Help": "<mailto:libc-alpha-request@sourceware.org?subject=help>", "List-Subscribe": "<https://sourceware.org/mailman/listinfo/libc-alpha>,\n <mailto:libc-alpha-request@sourceware.org?subject=subscribe>", "Errors-To": "libc-alpha-bounces~incoming=patchwork.ozlabs.org@sourceware.org" }, "content": "The set_robust_list syscall is currently called unconditionally at\nprocess startup (__tls_init_tp) and on every thread creation\n(pthread_create), even in programs that never use robust mutexes.\n\nThis patch defers the call to the first time a robust mutex is actually\nlocked or initialized with PTHREAD_PROCESS_SHARED. The new helper\nrobust_list_setup() performs the deferred registration and is called\nfrom pthread_mutex_init (for pshared+robust), pthread_mutex_lock,\npthread_mutex_trylock, and pthread_mutex_timedlock.\n\nThe field robust_head.futex_offset serves as a sentinel: zero means the\nlist has not been registered with the kernel; non-zero means it has.\nrobust_list_setup() sets futex_offset to its correct value before\ncalling set_robust_list, so the kernel always reads a valid offset when\nit walks the list on thread death. On syscall failure futex_offset is\nreset to zero.\n\n_Fork is updated to re-register the list with the kernel only when the\nparent had already initialized it (futex_offset != 0). If the parent\nnever used robust mutexes, the child's first robust mutex lock calls\nrobust_list_setup() itself.\n\nThe __nptl_set_robust_list_avail variable moves from ld.so to libc.so,\nsince it no longer needs to be set during pthread startup.\n\nChecked on x86_64-linux-gnu and aarch64-linux-gnu.\n---\n nptl/Makefile | 2 +\n nptl/Versions | 1 -\n nptl/allocatestack.c | 9 +---\n nptl/descr.h | 31 ++++++++++++\n nptl/nptl_robust_setup.c | 38 +++++++++++++++\n nptl/pthread_create.c | 8 ---\n nptl/pthread_mutex_init.c | 2 +-\n nptl/pthread_mutex_lock.c | 2 +\n nptl/pthread_mutex_timedlock.c | 2 +\n nptl/pthread_mutex_trylock.c | 2 +\n nptl/tst-robust-pshared.c | 89 ++++++++++++++++++++++++++++++++++\n sysdeps/nptl/_Fork.c | 24 ++++-----\n sysdeps/nptl/dl-tls_init_tp.c | 17 +------\n sysdeps/nptl/pthreadP.h | 6 +--\n 14 files changed, 183 insertions(+), 50 deletions(-)\n create mode 100644 nptl/nptl_robust_setup.c\n create mode 100644 nptl/tst-robust-pshared.c", "diff": "diff --git a/nptl/Makefile b/nptl/Makefile\nindex 02862d1c04b..c9c7fc00f55 100644\n--- a/nptl/Makefile\n+++ b/nptl/Makefile\n@@ -50,6 +50,7 @@ routines = \\\n nptl_deallocate_tsd \\\n nptl_free_tcb \\\n nptl_nthreads \\\n+ nptl_robust_setup \\\n nptl_setxid \\\n nptlfreeres \\\n old_pthread_cond_broadcast \\\n@@ -326,6 +327,7 @@ tests = \\\n tst-pthread_exit-nothreads-static \\\n tst-pthread_gettid_np \\\n tst-robust-fork \\\n+ tst-robust-pshared \\\n tst-robustpi1 \\\n tst-robustpi2 \\\n tst-robustpi3 \\\ndiff --git a/nptl/Versions b/nptl/Versions\nindex b813b675b91..94a567bd609 100644\n--- a/nptl/Versions\n+++ b/nptl/Versions\n@@ -535,6 +535,5 @@ libpthread {\n ld {\n GLIBC_PRIVATE {\n __nptl_initial_report_events;\n- __nptl_set_robust_list_avail;\n }\n }\ndiff --git a/nptl/allocatestack.c b/nptl/allocatestack.c\nindex b2ecb001136..fcccc75ddb8 100644\n--- a/nptl/allocatestack.c\n+++ b/nptl/allocatestack.c\n@@ -631,14 +631,7 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,\n /* The robust mutex lists also need to be initialized\n unconditionally because the cleanup for the previous stack owner\n might have happened in the kernel. */\n- pd->robust_head.futex_offset = (offsetof (pthread_mutex_t, __data.__lock)\n-\t\t\t\t - offsetof (pthread_mutex_t,\n-\t\t\t\t\t __data.__list.__next));\n- pd->robust_head.list_op_pending = NULL;\n-#if __PTHREAD_MUTEX_HAVE_PREV\n- pd->robust_prev = &pd->robust_head;\n-#endif\n- pd->robust_head.list = &pd->robust_head;\n+ robust_list_init (pd);\n \n /* We place the thread descriptor at the end of the stack. */\n *pdp = pd;\ndiff --git a/nptl/descr.h b/nptl/descr.h\nindex 627cc3980f0..308100c0c30 100644\n--- a/nptl/descr.h\n+++ b/nptl/descr.h\n@@ -458,6 +458,37 @@ cancel_enabled_and_canceled_and_async (int value)\n == (CANCELTYPE_BITMASK | CANCELED_BITMASK);\n }\n \n+static inline void\n+robust_list_init (struct pthread *pd)\n+{\n+ pd->robust_head.list_op_pending = NULL;\n+#if __PTHREAD_MUTEX_HAVE_PREV\n+ pd->robust_prev = &pd->robust_head;\n+#endif\n+ pd->robust_head.list = &pd->robust_head;\n+ pd->robust_head.futex_offset = 0;\n+}\n+\n+extern bool __nptl_robust_setup (struct robust_list_head *robust_head)\n+ attribute_hidden;\n+\n+static inline bool\n+robust_list_setup (struct pthread *pd)\n+{\n+ /* The current thread was already initialized. */\n+ if (pd->robust_head.futex_offset != 0)\n+ return true;\n+\n+ pd->robust_head.futex_offset = (offsetof (pthread_mutex_t, __data.__lock)\n+\t\t\t\t - offsetof (pthread_mutex_t,\n+\t\t\t\t\t __data.__list.__next));\n+ if (__nptl_robust_setup (&pd->robust_head))\n+ return true;\n+\n+ pd->robust_head.futex_offset = 0;\n+ return false;\n+}\n+\n /* This yields the pointer that TLS support code calls the thread pointer. */\n #if TLS_TCB_AT_TP\n # define TLS_TPADJ(pd) (pd)\ndiff --git a/nptl/nptl_robust_setup.c b/nptl/nptl_robust_setup.c\nnew file mode 100644\nindex 00000000000..0b95de22009\n--- /dev/null\n+++ b/nptl/nptl_robust_setup.c\n@@ -0,0 +1,38 @@\n+/* Linux robust mutex setup.\n+ Copyright (C) 2025 Free Software Foundation, Inc.\n+ This file is part of the GNU C Library.\n+\n+ The GNU C Library is free software; you can redistribute it and/or\n+ modify it under the terms of the GNU Lesser General Public\n+ License as published by the Free Software Foundation; either\n+ version 2.1 of the License, or (at your option) any later version.\n+\n+ The GNU C Library is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ Lesser General Public License for more details.\n+\n+ You should have received a copy of the GNU Lesser General Public\n+ License along with the GNU C Library; if not, see\n+ <https://www.gnu.org/licenses/>. */\n+\n+#include <descr.h>\n+#include <atomic.h>\n+#include <pthreadP.h>\n+\n+int __nptl_set_robust_list_avail = 1;\n+\n+bool\n+__nptl_robust_setup (struct robust_list_head *robust_head)\n+{\n+ if (atomic_load_relaxed (&__nptl_set_robust_list_avail))\n+ {\n+ int res = INTERNAL_SYSCALL_CALL (set_robust_list, robust_head,\n+\t\t\t\t sizeof (struct robust_list_head));\n+ if (!INTERNAL_SYSCALL_ERROR_P (res))\n+ return true;\n+\n+ atomic_store_relaxed (&__nptl_set_robust_list_avail, 0);\n+ }\n+ return false;\n+}\ndiff --git a/nptl/pthread_create.c b/nptl/pthread_create.c\nindex 72f77d1914e..d7aed06efda 100644\n--- a/nptl/pthread_create.c\n+++ b/nptl/pthread_create.c\n@@ -386,14 +386,6 @@ start_thread (void *arg)\n __libc_fatal (\"Fatal glibc error: rseq registration failed\\n\");\n }\n \n- if (__nptl_set_robust_list_avail)\n- {\n- /* This call should never fail because the initial call in init.c\n-\t succeeded. */\n- INTERNAL_SYSCALL_CALL (set_robust_list, &pd->robust_head,\n-\t\t\t sizeof (struct robust_list_head));\n- }\n-\n /* This is where the try/finally block should be created. For\n compilers without that support we do use setjmp. */\n struct pthread_unwind_buf unwind_buf;\ndiff --git a/nptl/pthread_mutex_init.c b/nptl/pthread_mutex_init.c\nindex 9be08332f1f..2f0bb84c557 100644\n--- a/nptl/pthread_mutex_init.c\n+++ b/nptl/pthread_mutex_init.c\n@@ -94,7 +94,7 @@ ___pthread_mutex_init (pthread_mutex_t *mutex,\n if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_ROBUST) != 0)\n {\n if ((imutexattr->mutexkind & PTHREAD_MUTEXATTR_FLAG_PSHARED) != 0\n-\t && !__nptl_set_robust_list_avail)\n+\t && !robust_list_setup (THREAD_SELF))\n \treturn ENOTSUP;\n mutex_kind |= PTHREAD_MUTEX_ROBUST_NORMAL_NP;\n }\ndiff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c\nindex a697f2b6ca8..f649036d954 100644\n--- a/nptl/pthread_mutex_lock.c\n+++ b/nptl/pthread_mutex_lock.c\n@@ -177,6 +177,7 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)\n case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:\n case PTHREAD_MUTEX_ROBUST_NORMAL_NP:\n case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:\n+ robust_list_setup (THREAD_SELF);\n THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,\n \t\t &mutex->__data.__list.__next);\n /* We need to set op_pending before starting the operation. Also\n@@ -361,6 +362,7 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex)\n \n \tif (robust)\n \t {\n+\t robust_list_setup (THREAD_SELF);\n \t /* Note: robust PI futexes are signaled by setting bit 0. */\n \t THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,\n \t\t\t (void *) (((uintptr_t) &mutex->__data.__list.__next)\ndiff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c\nindex 9efca2c7791..a52ed795df0 100644\n--- a/nptl/pthread_mutex_timedlock.c\n+++ b/nptl/pthread_mutex_timedlock.c\n@@ -111,6 +111,7 @@ __pthread_mutex_clocklock_common (pthread_mutex_t *mutex,\n case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:\n case PTHREAD_MUTEX_ROBUST_NORMAL_NP:\n case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:\n+ robust_list_setup (THREAD_SELF);\n THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,\n \t\t &mutex->__data.__list.__next);\n /* We need to set op_pending before starting the operation. Also\n@@ -295,6 +296,7 @@ __pthread_mutex_clocklock_common (pthread_mutex_t *mutex,\n \n \tif (robust)\n \t {\n+\t robust_list_setup (THREAD_SELF);\n \t /* Note: robust PI futexes are signaled by setting bit 0. */\n \t THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,\n \t\t\t (void *) (((uintptr_t) &mutex->__data.__list.__next)\ndiff --git a/nptl/pthread_mutex_trylock.c b/nptl/pthread_mutex_trylock.c\nindex 236b3228ddb..09c5dc983b2 100644\n--- a/nptl/pthread_mutex_trylock.c\n+++ b/nptl/pthread_mutex_trylock.c\n@@ -77,6 +77,7 @@ ___pthread_mutex_trylock (pthread_mutex_t *mutex)\n case PTHREAD_MUTEX_ROBUST_ERRORCHECK_NP:\n case PTHREAD_MUTEX_ROBUST_NORMAL_NP:\n case PTHREAD_MUTEX_ROBUST_ADAPTIVE_NP:\n+ robust_list_setup (THREAD_SELF);\n THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,\n \t\t &mutex->__data.__list.__next);\n /* We need to set op_pending before starting the operation. Also\n@@ -219,6 +220,7 @@ ___pthread_mutex_trylock (pthread_mutex_t *mutex)\n \n \tif (robust)\n \t {\n+\t robust_list_setup (THREAD_SELF);\n \t /* Note: robust PI futexes are signaled by setting bit 0. */\n \t THREAD_SETMEM (THREAD_SELF, robust_head.list_op_pending,\n \t\t\t (void *) (((uintptr_t) &mutex->__data.__list.__next)\ndiff --git a/nptl/tst-robust-pshared.c b/nptl/tst-robust-pshared.c\nnew file mode 100644\nindex 00000000000..4074ffa494b\n--- /dev/null\n+++ b/nptl/tst-robust-pshared.c\n@@ -0,0 +1,89 @@\n+/* Test process-shared robust mutex support and lazy initialization (BZ 33225).\n+ Copyright (C) 2025 Free Software Foundation, Inc.\n+ This file is part of the GNU C Library.\n+\n+ The GNU C Library is free software; you can redistribute it and/or\n+ modify it under the terms of the GNU Lesser General Public\n+ License as published by the Free Software Foundation; either\n+ version 2.1 of the License, or (at your option) any later version.\n+\n+ The GNU C Library is distributed in the hope that it will be useful,\n+ but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n+ Lesser General Public License for more details.\n+\n+ You should have received a copy of the GNU Lesser General Public\n+ License along with the GNU C Library; if not, see\n+ <https://www.gnu.org/licenses/>. */\n+\n+/* Verify that pthread_mutex_init returns ENOTSUP for a process-shared robust\n+ mutex when the set_robust_list syscall is not available (e.g., qemu-user),\n+ and that the lazy robust list initialization works correctly when the\n+ syscall is available. */\n+\n+#include <errno.h>\n+#include <pthread.h>\n+#include <stdbool.h>\n+#include <stdio.h>\n+#include <support/check.h>\n+#include <support/test-driver.h>\n+#include <support/xthread.h>\n+\n+/* Lock the mutex and exit without unlocking to trigger EOWNERDEAD. */\n+static void *\n+owner_thread (void *arg)\n+{\n+ pthread_mutex_t *mutex = arg;\n+ TEST_COMPARE (pthread_mutex_lock (mutex), 0);\n+ /* Thread exits here without unlocking. The kernel walks the robust\n+ list registered via set_robust_list and marks the mutex owner-dead.\n+ This verifies that lazy robust_list_setup correctly set futex_offset\n+ and called set_robust_list before the first lock. */\n+ return NULL;\n+}\n+\n+static int\n+do_test (void)\n+{\n+ bool robust_support = support_process_shared_robust_mutex ();\n+ if (test_verbose)\n+ printf (\"info: process-shared robust mutex support: %d\\n\", robust_support);\n+\n+ pthread_mutexattr_t attr;\n+ TEST_COMPARE (pthread_mutexattr_init (&attr), 0);\n+ TEST_COMPARE (pthread_mutexattr_setpshared (&attr, PTHREAD_PROCESS_SHARED),\n+\t\t0);\n+ TEST_COMPARE (pthread_mutexattr_setrobust (&attr, PTHREAD_MUTEX_ROBUST), 0);\n+\n+ pthread_mutex_t mutex;\n+ int ret = pthread_mutex_init (&mutex, &attr);\n+ TEST_COMPARE (pthread_mutexattr_destroy (&attr), 0);\n+\n+ if (!robust_support)\n+ {\n+ /* When set_robust_list is unavailable, pshared+robust mutex init\n+\t must fail with ENOTSUP rather than silently succeeding. */\n+ TEST_COMPARE (ret, ENOTSUP);\n+ return 0;\n+ }\n+\n+ TEST_COMPARE (ret, 0);\n+\n+ /* Have a thread lock the mutex and exit without unlocking.\n+ This exercises the lazy robust_list_setup path in\n+ pthread_mutex_lock: futex_offset must be set before set_robust_list\n+ is called so the kernel can correctly compute the lock address on\n+ thread death. */\n+ pthread_t thread;\n+ TEST_COMPARE (pthread_create (&thread, NULL, owner_thread, &mutex), 0);\n+ TEST_COMPARE (pthread_join (thread, NULL), 0);\n+\n+ TEST_COMPARE (pthread_mutex_lock (&mutex), EOWNERDEAD);\n+ TEST_COMPARE (pthread_mutex_consistent (&mutex), 0);\n+ TEST_COMPARE (pthread_mutex_unlock (&mutex), 0);\n+ TEST_COMPARE (pthread_mutex_destroy (&mutex), 0);\n+\n+ return 0;\n+}\n+\n+#include <support/test-driver.c>\ndiff --git a/sysdeps/nptl/_Fork.c b/sysdeps/nptl/_Fork.c\nindex 907b3fef876..ba6912aa346 100644\n--- a/sysdeps/nptl/_Fork.c\n+++ b/sysdeps/nptl/_Fork.c\n@@ -35,22 +35,22 @@ _Fork (void)\n {\n struct pthread *self = THREAD_SELF;\n \n- /* Initialize the robust mutex list setting in the kernel which has\n-\t been reset during the fork. We do not check for errors because if\n-\t it fails here, it must have failed at process startup as well and\n-\t nobody could have used robust mutexes.\n-\t Before we do that, we have to clear the list of robust mutexes\n-\t because we do not inherit ownership of mutexes from the parent.\n-\t We do not have to set self->robust_head.futex_offset since we do\n-\t inherit the correct value from the parent. We do not need to clear\n-\t the pending operation because it must have been zero when fork was\n-\t called. */\n+ /* Clear the list of robust mutexes because we do not inherit ownership\n+\t of mutexes from the parent. We do not need to clear the pending\n+\t operation because it must have been zero when fork was called.\n+\t futex_offset is inherited from the parent unchanged. */\n #if __PTHREAD_MUTEX_HAVE_PREV\n self->robust_prev = &self->robust_head;\n #endif\n self->robust_head.list = &self->robust_head;\n- INTERNAL_SYSCALL_CALL (set_robust_list, &self->robust_head,\n-\t\t\t sizeof (struct robust_list_head));\n+ /* Re-register the robust list with the kernel only if the parent had\n+\t already initialized it. futex_offset is the sentinel: zero means\n+\t lazy initialization has not happened yet, so there is nothing to\n+\t re-register and the first robust mutex lock in the child will call\n+\t set_robust_list itself. */\n+ if (self->robust_head.futex_offset != 0)\n+\tINTERNAL_SYSCALL_CALL (set_robust_list, &self->robust_head,\n+\t\t\t sizeof (struct robust_list_head));\n call_function_static_weak (__getrandom_fork_subprocess);\n }\n \ndiff --git a/sysdeps/nptl/dl-tls_init_tp.c b/sysdeps/nptl/dl-tls_init_tp.c\nindex 75e3712a6d8..77f2e341822 100644\n--- a/sysdeps/nptl/dl-tls_init_tp.c\n+++ b/sysdeps/nptl/dl-tls_init_tp.c\n@@ -28,9 +28,6 @@\n #define TUNABLE_NAMESPACE pthread\n #include <dl-tunables.h>\n \n-bool __nptl_set_robust_list_avail;\n-rtld_hidden_data_def (__nptl_set_robust_list_avail)\n-\n bool __nptl_initial_report_events;\n rtld_hidden_def (__nptl_initial_report_events)\n \n@@ -82,19 +79,7 @@ __tls_init_tp (void)\n THREAD_SETMEM (pd, report_events, __nptl_initial_report_events);\n \n /* Initialize the robust mutex data. */\n- {\n-#if __PTHREAD_MUTEX_HAVE_PREV\n- pd->robust_prev = &pd->robust_head;\n-#endif\n- pd->robust_head.list = &pd->robust_head;\n- pd->robust_head.futex_offset = (offsetof (pthread_mutex_t, __data.__lock)\n- - offsetof (pthread_mutex_t,\n- __data.__list.__next));\n- int res = INTERNAL_SYSCALL_CALL (set_robust_list, &pd->robust_head,\n- sizeof (struct robust_list_head));\n- if (!INTERNAL_SYSCALL_ERROR_P (res))\n- __nptl_set_robust_list_avail = true;\n- }\n+ robust_list_init (pd);\n \n {\n /* If the registration fails or is disabled by tunable, the public\ndiff --git a/sysdeps/nptl/pthreadP.h b/sysdeps/nptl/pthreadP.h\nindex c62c8982905..38a1383c3fe 100644\n--- a/sysdeps/nptl/pthreadP.h\n+++ b/sysdeps/nptl/pthreadP.h\n@@ -192,10 +192,8 @@ libc_hidden_proto (__pthread_keys)\n extern unsigned int __nptl_nthreads;\n libc_hidden_proto (__nptl_nthreads)\n \n-/* True if the set_robust_list system call works. Initialized in\n- __tls_init_tp. */\n-extern bool __nptl_set_robust_list_avail;\n-rtld_hidden_proto (__nptl_set_robust_list_avail)\n+/* Set if the set_robust_list system call works. */\n+extern int __nptl_set_robust_list_avail attribute_hidden;\n \n /* Thread Priority Protection. */\n extern int __sched_fifo_min_prio;\n", "prefixes": [ "v2", "3/3" ] }