1 /* Restartable Sequences NPTL test.
2 Copyright (C) 2021-2023 Free Software Foundation, Inc.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <https://www.gnu.org/licenses/>. */
18 /* These tests validate that rseq is registered from various execution
19 contexts (main thread, destructor, other threads, other threads created
20 from destructor, forked process (without exec), pthread_atfork handlers,
21 pthread setspecific destructors, signal handlers, atexit handlers).
23 See the Linux kernel selftests for extensive rseq stress-tests. */
26 #include <support/check.h>
27 #include <support/xthread.h>
32 # include <array_length.h>
39 # include <support/namespace.h>
40 # include <support/xsignal.h>
42 # include <sys/types.h>
43 # include <sys/wait.h>
44 # include "tst-rseq.h"
46 static pthread_key_t rseq_test_key
;
51 if (!rseq_thread_registered ())
53 printf ("error: rseq not registered in pthread atfork prepare\n");
54 support_record_failure ();
61 if (!rseq_thread_registered ())
63 printf ("error: rseq not registered in pthread atfork parent\n");
64 support_record_failure ();
71 if (!rseq_thread_registered ())
73 printf ("error: rseq not registered in pthread atfork child\n");
74 support_record_failure ();
79 rseq_key_destructor (void *arg
)
81 /* Cannot use deferred failure reporting after main returns. */
82 if (!rseq_thread_registered ())
83 FAIL_EXIT1 ("rseq not registered in pthread key destructor");
89 /* Cannot use deferred failure reporting after main returns. */
90 if (!rseq_thread_registered ())
91 FAIL_EXIT1 ("rseq not registered in atexit handler");
94 /* Used to avoid -Werror=stringop-overread warning with
95 pthread_setspecific and GCC 11. */
99 do_rseq_main_test (void)
101 TEST_COMPARE (atexit (atexit_handler
), 0);
102 rseq_test_key
= xpthread_key_create (rseq_key_destructor
);
103 TEST_COMPARE (pthread_atfork (atfork_prepare
, atfork_parent
, atfork_child
), 0);
105 TEST_COMPARE (pthread_setspecific (rseq_test_key
, &one
), 0);
106 TEST_VERIFY_EXIT (rseq_thread_registered ());
110 cancel_routine (void *arg
)
112 if (!rseq_thread_registered ())
114 printf ("error: rseq not registered in cancel routine\n");
115 support_record_failure ();
119 static pthread_barrier_t cancel_thread_barrier
;
120 static pthread_cond_t cancel_thread_cond
= PTHREAD_COND_INITIALIZER
;
121 static pthread_mutex_t cancel_thread_mutex
= PTHREAD_MUTEX_INITIALIZER
;
124 test_cancel_thread (void)
126 pthread_cleanup_push (cancel_routine
, NULL
);
127 (void) xpthread_barrier_wait (&cancel_thread_barrier
);
128 /* Wait forever until cancellation. */
129 xpthread_cond_wait (&cancel_thread_cond
, &cancel_thread_mutex
);
130 pthread_cleanup_pop (0);
134 thread_function (void * arg
)
136 int i
= (int) (intptr_t) arg
;
140 test_cancel_thread ();
141 TEST_COMPARE (pthread_setspecific (rseq_test_key
, &one
), 0);
142 return rseq_thread_registered () ? NULL
: (void *) 1l;
148 if (!rseq_thread_registered ())
150 printf ("error: rseq not registered in signal handler\n");
151 support_record_failure ();
160 sigemptyset (&sa
.sa_mask
);
161 sigaddset (&sa
.sa_mask
, SIGUSR1
);
163 sa
.sa_handler
= sighandler
;
164 xsigaction (SIGUSR1
, &sa
, NULL
);
168 do_rseq_threads_test (int nr_threads
)
170 pthread_t th
[nr_threads
];
174 xpthread_barrier_init (&cancel_thread_barrier
, NULL
, 2);
176 for (i
= 0; i
< nr_threads
; ++i
)
177 th
[i
] = xpthread_create (NULL
, thread_function
,
178 (void *) (intptr_t) i
);
180 (void) xpthread_barrier_wait (&cancel_thread_barrier
);
182 xpthread_cancel (th
[0]);
184 for (i
= 0; i
< nr_threads
; ++i
)
188 v
= xpthread_join (th
[i
]);
189 if (i
!= 0 && v
!= NULL
)
191 printf ("error: join %d successful, but child failed\n", i
);
194 else if (i
== 0 && v
== NULL
)
196 printf ("error: join %d successful, child did not fail as expected\n", i
);
201 xpthread_barrier_destroy (&cancel_thread_barrier
);
207 subprocess_callback (void *closure
)
209 do_rseq_main_test ();
213 do_rseq_fork_test (void)
215 support_isolate_in_subprocess (subprocess_callback
, NULL
);
221 int t
[] = { 1, 2, 6, 5, 4, 3, 50 };
224 if (!rseq_available ())
225 FAIL_UNSUPPORTED ("kernel does not support rseq, skipping test");
228 do_rseq_main_test ();
229 for (i
= 0; i
< array_length (t
); i
++)
230 if (do_rseq_threads_test (t
[i
]))
232 do_rseq_fork_test ();
236 static void __attribute__ ((destructor
))
237 do_rseq_destructor_test (void)
239 /* Cannot use deferred failure reporting after main returns. */
241 FAIL_EXIT1 ("rseq not registered within destructor");
242 xpthread_key_delete (rseq_test_key
);
249 FAIL_UNSUPPORTED ("glibc does not define RSEQ_SIG, skipping test");
252 #endif /* RSEQ_SIG */
257 return do_rseq_test ();
260 #include <support/test-driver.c>