1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#include <errno.h>
24#include <getopt.h>
25#include <limits.h>
26#include <pthread.h>
27#include <signal.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31#include "atomic.h"
32#include "futextest.h"
33#include "logging.h"
34
35#define TEST_NAME "futex-requeue-pi-signal-restart"
36#define DELAY_US 100
37
38futex_t f1 = FUTEX_INITIALIZER;
39futex_t f2 = FUTEX_INITIALIZER;
40atomic_t requeued = ATOMIC_INITIALIZER;
41
42int waiter_ret = 0;
43
44void usage(char *prog)
45{
46 printf("Usage: %s\n", prog);
47 printf(" -c Use color\n");
48 printf(" -h Display this help message\n");
49 printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n",
50 VQUIET, VCRITICAL, VINFO);
51}
52
53int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg,
54 int policy, int prio)
55{
56 struct sched_param schedp;
57 pthread_attr_t attr;
58 int ret;
59
60 pthread_attr_init(&attr);
61 memset(&schedp, 0, sizeof(schedp));
62
63 ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
64 if (ret) {
65 error("pthread_attr_setinheritsched\n", ret);
66 return -1;
67 }
68
69 ret = pthread_attr_setschedpolicy(&attr, policy);
70 if (ret) {
71 error("pthread_attr_setschedpolicy\n", ret);
72 return -1;
73 }
74
75 schedp.sched_priority = prio;
76 ret = pthread_attr_setschedparam(&attr, &schedp);
77 if (ret) {
78 error("pthread_attr_setschedparam\n", ret);
79 return -1;
80 }
81
82 ret = pthread_create(pth, &attr, func, arg);
83 if (ret) {
84 error("pthread_create\n", ret);
85 return -1;
86 }
87 return 0;
88}
89
90void handle_signal(int signo)
91{
92 info("signal received %s requeue\n",
93 requeued.val ? "after" : "prior to");
94}
95
96void *waiterfn(void *arg)
97{
98 unsigned int old_val;
99 int res;
100
101 waiter_ret = RET_PASS;
102
103 info("Waiter running\n");
104 info("Calling FUTEX_LOCK_PI on f2=%x @ %p\n", f2, &f2);
105 old_val = f1;
106 res = futex_wait_requeue_pi(&f1, old_val, &(f2), NULL,
107 FUTEX_PRIVATE_FLAG);
108 if (!requeued.val || errno != EWOULDBLOCK) {
109 fail("unexpected return from futex_wait_requeue_pi: %d (%s)\n",
110 res, strerror(errno));
111 info("w2:futex: %x\n", f2);
112 if (!res)
113 futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
114 waiter_ret = RET_FAIL;
115 }
116
117 info("Waiter exiting with %d\n", waiter_ret);
118 pthread_exit(NULL);
119}
120
121
122int main(int argc, char *argv[])
123{
124 unsigned int old_val;
125 struct sigaction sa;
126 pthread_t waiter;
127 int c, res, ret = RET_PASS;
128
129 while ((c = getopt(argc, argv, "chv:")) != -1) {
130 switch (c) {
131 case 'c':
132 log_color(1);
133 break;
134 case 'h':
135 usage(basename(argv[0]));
136 exit(0);
137 case 'v':
138 log_verbosity(atoi(optarg));
139 break;
140 default:
141 usage(basename(argv[0]));
142 exit(1);
143 }
144 }
145
146 ksft_print_header();
147 ksft_set_plan(1);
148 ksft_print_msg("%s: Test signal handling during requeue_pi\n",
149 basename(argv[0]));
150 ksft_print_msg("\tArguments: <none>\n");
151
152 sa.sa_handler = handle_signal;
153 sigemptyset(&sa.sa_mask);
154 sa.sa_flags = 0;
155 if (sigaction(SIGUSR1, &sa, NULL)) {
156 error("sigaction\n", errno);
157 exit(1);
158 }
159
160 info("m1:f2: %x\n", f2);
161 info("Creating waiter\n");
162 res = create_rt_thread(&waiter, waiterfn, NULL, SCHED_FIFO, 1);
163 if (res) {
164 error("Creating waiting thread failed", res);
165 ret = RET_ERROR;
166 goto out;
167 }
168
169 info("Calling FUTEX_LOCK_PI on f2=%x @ %p\n", f2, &f2);
170 info("m2:f2: %x\n", f2);
171 futex_lock_pi(&f2, 0, 0, FUTEX_PRIVATE_FLAG);
172 info("m3:f2: %x\n", f2);
173
174 while (1) {
175
176
177
178
179
180 info("Issuing SIGUSR1 to waiter\n");
181 pthread_kill(waiter, SIGUSR1);
182 usleep(DELAY_US);
183
184 info("Requeueing waiter via FUTEX_CMP_REQUEUE_PI\n");
185 old_val = f1;
186 res = futex_cmp_requeue_pi(&f1, old_val, &(f2), 1, 0,
187 FUTEX_PRIVATE_FLAG);
188
189
190
191
192
193
194 if (res > 0) {
195 atomic_set(&requeued, 1);
196 break;
197 } else if (res < 0) {
198 error("FUTEX_CMP_REQUEUE_PI failed\n", errno);
199 ret = RET_ERROR;
200 break;
201 }
202 }
203 info("m4:f2: %x\n", f2);
204
205
206
207
208
209
210
211 info("Issuing SIGUSR1 to waiter\n");
212 pthread_kill(waiter, SIGUSR1);
213 info("Waiting for waiter to return\n");
214 pthread_join(waiter, NULL);
215
216 info("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p\n", f2, &f2);
217 futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
218 info("m5:f2: %x\n", f2);
219
220 out:
221 if (ret == RET_PASS && waiter_ret)
222 ret = waiter_ret;
223
224 print_result(TEST_NAME, ret);
225 return ret;
226}
227