1/* Make sure pthread_mutex_timedlock doesn't return spurious error codes.
2
3 Copyright (C) 2020-2022 Free Software Foundation, Inc.
4 This file is part of the GNU C Library.
5
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Lesser General Public
8 License as published by the Free Software Foundation; either
9 version 2.1 of the License, or (at your option) any later version.
10
11 The GNU C Library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with the GNU C Library; if not, see
18 <https://www.gnu.org/licenses/>. */
19
20#include <errno.h>
21#include <pthread.h>
22#include <signal.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <support/check.h>
26#include <support/timespec.h>
27#include <support/xsignal.h>
28#include <support/xthread.h>
29#include <support/xtime.h>
30#include <time.h>
31#include <unistd.h>
32
33#define NANO_PER_SEC 1000000000LL
34#define TIMEOUT (NANO_PER_SEC / 1000LL)
35#define NUM_THREADS 50
36#define RETEST_TIMES 100
37
38static pthread_mutex_t mutex;
39static int runs;
40static clockid_t clockid;
41
42static void
43signal_handler (int sig_num)
44{
45 TEST_COMPARE (sig_num, SIGUSR1);
46}
47
48/* Call pthread_mutex_timedlock()/pthread_mutex_unlock() repetitively, hoping
49 that one of them returns EAGAIN or EINTR unexpectedly. */
50static void *
51worker_timedlock (void *arg)
52{
53 for (unsigned int run = 0; run < runs; run++)
54 {
55 struct timespec abs_time = timespec_add (xclock_now (CLOCK_REALTIME),
56 make_timespec (s: 0, ns: 1000000));
57
58 int ret = pthread_mutex_timedlock (mutex: &mutex, abstime: &abs_time);
59
60 if (ret == 0)
61 xpthread_mutex_unlock (mutex: &mutex);
62
63 TEST_VERIFY_EXIT (ret == 0 || ret == ETIMEDOUT);
64 }
65 return NULL;
66}
67
68static void *
69worker_clocklock (void *arg)
70{
71 for (unsigned int run = 0; run < runs; run++)
72 {
73 struct timespec time =
74 timespec_add (xclock_now (clock: clockid), make_timespec (s: 0, ns: 1000000));
75
76 int ret = pthread_mutex_clocklock (mutex: &mutex, clockid: clockid, abstime: &time);
77
78 if (ret == 0)
79 xpthread_mutex_unlock (mutex: &mutex);
80
81 TEST_VERIFY_EXIT (ret == 0 || ret == ETIMEDOUT);
82 }
83 return NULL;
84}
85
86static int
87run_test_set (void *(*worker) (void *))
88{
89 pthread_t workers[NUM_THREADS];
90
91 /* Check if default pthread_mutex_{timed,clock}lock with valid arguments
92 returns either 0 or ETIMEDOUT. Since there is no easy way to force
93 the error condition, the test creates multiple threads which in turn
94 issues pthread_mutex_timedlock multiple times. */
95 runs = 100;
96 for (int run = 0; run < RETEST_TIMES; run++)
97 {
98 for (int i = 0; i < NUM_THREADS; i++)
99 workers[i] = xpthread_create (NULL, thread_func: worker, NULL);
100 for (int i = 0; i < NUM_THREADS; i++)
101 xpthread_join (thr: workers[i]);
102 }
103
104 /* The idea is similar to previous tests, but we check if
105 pthread_mutex_{timed,clock}lock does not return EINTR. */
106 pthread_t thread;
107 runs = 1;
108 for (int i = 0; i < RETEST_TIMES * 1000; i++)
109 {
110 xpthread_mutex_lock (mutex: &mutex);
111 thread = xpthread_create (NULL, thread_func: worker, NULL);
112 /* Sleep just a little bit to reach the lock on the worker thread. */
113 usleep (useconds: 10);
114 pthread_kill (threadid: thread, SIGUSR1);
115 xpthread_mutex_unlock (mutex: &mutex);
116 xpthread_join (thr: thread);
117 }
118
119 return 0;
120}
121
122static int
123do_test (void)
124{
125
126 xsignal (SIGUSR1, handler: signal_handler);
127
128 xpthread_mutex_init (&mutex, NULL);
129
130 run_test_set (worker: worker_timedlock);
131 clockid = CLOCK_REALTIME;
132 run_test_set (worker: worker_clocklock);
133 clockid = CLOCK_MONOTONIC;
134 run_test_set (worker: worker_clocklock);
135 return 0;
136}
137
138#include <support/test-driver.c>
139

source code of glibc/nptl/tst-pthread-timedlock-lockloop.c