Skip to content

Commit e797203

Browse files
dvyukovKAGA-KOKO
authored andcommitted
selftests/timers/posix_timers: Test delivery of signals across threads
Test that POSIX timers using CLOCK_PROCESS_CPUTIME_ID eventually deliver a signal to all running threads. This effectively tests that the kernel doesn't prefer any one thread (or subset of threads) for signal delivery. Signed-off-by: Dmitry Vyukov <dvyukov@google.com> Signed-off-by: Marco Elver <elver@google.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Link: https://lore.kernel.org/r/20230316123028.2890338-2-elver@google.com
1 parent bcb7ee7 commit e797203

1 file changed

Lines changed: 77 additions & 0 deletions

File tree

tools/testing/selftests/timers/posix_timers.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,80 @@ static int check_timer_create(int which)
188188
return 0;
189189
}
190190

191+
int remain;
192+
__thread int got_signal;
193+
194+
static void *distribution_thread(void *arg)
195+
{
196+
while (__atomic_load_n(&remain, __ATOMIC_RELAXED));
197+
return NULL;
198+
}
199+
200+
static void distribution_handler(int nr)
201+
{
202+
if (!__atomic_exchange_n(&got_signal, 1, __ATOMIC_RELAXED))
203+
__atomic_fetch_sub(&remain, 1, __ATOMIC_RELAXED);
204+
}
205+
206+
/*
207+
* Test that all running threads _eventually_ receive CLOCK_PROCESS_CPUTIME_ID
208+
* timer signals. This primarily tests that the kernel does not favour any one.
209+
*/
210+
static int check_timer_distribution(void)
211+
{
212+
int err, i;
213+
timer_t id;
214+
const int nthreads = 10;
215+
pthread_t threads[nthreads];
216+
struct itimerspec val = {
217+
.it_value.tv_sec = 0,
218+
.it_value.tv_nsec = 1000 * 1000,
219+
.it_interval.tv_sec = 0,
220+
.it_interval.tv_nsec = 1000 * 1000,
221+
};
222+
223+
printf("Check timer_create() per process signal distribution... ");
224+
fflush(stdout);
225+
226+
remain = nthreads + 1; /* worker threads + this thread */
227+
signal(SIGALRM, distribution_handler);
228+
err = timer_create(CLOCK_PROCESS_CPUTIME_ID, NULL, &id);
229+
if (err < 0) {
230+
perror("Can't create timer\n");
231+
return -1;
232+
}
233+
err = timer_settime(id, 0, &val, NULL);
234+
if (err < 0) {
235+
perror("Can't set timer\n");
236+
return -1;
237+
}
238+
239+
for (i = 0; i < nthreads; i++) {
240+
if (pthread_create(&threads[i], NULL, distribution_thread, NULL)) {
241+
perror("Can't create thread\n");
242+
return -1;
243+
}
244+
}
245+
246+
/* Wait for all threads to receive the signal. */
247+
while (__atomic_load_n(&remain, __ATOMIC_RELAXED));
248+
249+
for (i = 0; i < nthreads; i++) {
250+
if (pthread_join(threads[i], NULL)) {
251+
perror("Can't join thread\n");
252+
return -1;
253+
}
254+
}
255+
256+
if (timer_delete(id)) {
257+
perror("Can't delete timer\n");
258+
return -1;
259+
}
260+
261+
printf("[OK]\n");
262+
return 0;
263+
}
264+
191265
int main(int argc, char **argv)
192266
{
193267
printf("Testing posix timers. False negative may happen on CPU execution \n");
@@ -217,5 +291,8 @@ int main(int argc, char **argv)
217291
if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0)
218292
return ksft_exit_fail();
219293

294+
if (check_timer_distribution() < 0)
295+
return ksft_exit_fail();
296+
220297
return ksft_exit_pass();
221298
}

0 commit comments

Comments
 (0)