blob: 1389249b3ef91beb33d4d475b60279ca7b8743cf [file] [log] [blame]
robbiew7bdb08e2004-03-17 21:14:52 +00001/*
2 * Copyright (c) International Business Machines Corp., 2004.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * You should have received a copy of the GNU General Public License along
Wanlong Gaofed96412012-10-24 10:10:29 +080013 * with this program; if not, write the Free Software Foundation, Inc.,
14 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
robbiew7bdb08e2004-03-17 21:14:52 +000015 *
16 */
17/**********************************************************
18 *
19 * TEST IDENTIFIER : nptl01
20 *
21 * EXECUTED BY : root
22 *
23 * TEST TITLE : NPTL test for pthread_cond_timedwait() error
24 * path bug.
25 *
26 * TEST CASE TOTAL : 1
27 *
28 * AUTHOR : Neil Richards <neil_richards@uk.ibm.com>
29 *
30 * DESCRIPTION
31 * This is a test for a bug found in the pthread_cond_timedwait() system call.
32 * of the Native POSIX Thread Library (NPTL) library code.
33 * There was an error path in the system call, where the sequence counters were
34 * getting updated w/o holding the internal condvar lock. A FAIL is indicated
35 * by the test hanging and not completing execution.
36 *
37 ****************************************************************/
subrata_modakda124b92009-10-13 14:00:45 +000038#define _GNU_SOURCE
robbiew7bdb08e2004-03-17 21:14:52 +000039#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <pthread.h>
43#include <errno.h>
44#include <unistd.h>
45#include <time.h>
46#include <sys/time.h>
47#include "test.h"
robbiew7bdb08e2004-03-17 21:14:52 +000048
mridgebf7d8592006-02-20 17:26:10 +000049#define MAXTIME 72000 /* Maximum # of secs to wait before failing */
robbiew283ef202005-08-03 15:18:36 +000050#define NUMLOOPS 100000 /* # of loops */
plars1f9577e2005-04-27 15:24:35 +000051
Wanlong Gao354ebb42012-12-07 10:10:04 +080052char *TCID = "nptl01"; /* Test program identifier. */
53int TST_TOTAL = 1; /* Total number of test cases. */
robbiew7bdb08e2004-03-17 21:14:52 +000054void cleanup();
55
56pthread_mutex_t req;
57pthread_mutex_t ack;
58pthread_mutex_t wait;
59pthread_cond_t parent;
60pthread_cond_t child;
61int idle_count = 0;
62
63/*
64 * The time to wait should be set appropriately so that the waiting thread
65 * is coming out of the wait at around the same time as the other thread is
66 * signalling it.
67 * The value of 1000 seems to work (ie. demonstrate the problem) on my
68 * 8 way (hyperthreaded) 2GHz Xeon box.
69 */
robbiewb6bd2b42004-03-17 23:19:01 +000070#define NSECS_TO_WAIT (1)
robbiew7bdb08e2004-03-17 21:14:52 +000071
Wanlong Gao354ebb42012-12-07 10:10:04 +080072void call_mutex_init(pthread_mutex_t * mutex, char *buf, size_t buf_len)
73{
74 int ret;
robbiew7bdb08e2004-03-17 21:14:52 +000075
Wanlong Gao354ebb42012-12-07 10:10:04 +080076 if ((ret = pthread_mutex_init(mutex, NULL)) != 0) {
77 tst_brkm(TBROK, cleanup, "pthread_mutex_init failed: %s",
78 strerror_r(ret, buf, buf_len));
79 }
robbiew7bdb08e2004-03-17 21:14:52 +000080}
81
Wanlong Gao354ebb42012-12-07 10:10:04 +080082void call_mutex_lock(pthread_mutex_t * mutex, char *buf, size_t buf_len)
83{
84 int ret;
robbiew7bdb08e2004-03-17 21:14:52 +000085
Wanlong Gao354ebb42012-12-07 10:10:04 +080086 if ((ret = pthread_mutex_lock(mutex)) != 0) {
87 tst_brkm(TBROK, cleanup, "pthread_mutex_lock failed: %s",
88 strerror_r(ret, buf, buf_len));
89 }
robbiew7bdb08e2004-03-17 21:14:52 +000090}
91
Wanlong Gao354ebb42012-12-07 10:10:04 +080092void call_mutex_unlock(pthread_mutex_t * mutex, char *buf, size_t buf_len)
93{
94 int ret;
robbiew7bdb08e2004-03-17 21:14:52 +000095
Wanlong Gao354ebb42012-12-07 10:10:04 +080096 if ((ret = pthread_mutex_unlock(mutex)) != 0) {
97 tst_brkm(TBROK, cleanup, "pthread_mutex_unlock failed: %s",
98 strerror_r(ret, buf, buf_len));
99 }
robbiew7bdb08e2004-03-17 21:14:52 +0000100}
101
Wanlong Gao354ebb42012-12-07 10:10:04 +0800102void call_cond_init(pthread_cond_t * cond, char *buf, size_t buf_len)
103{
104 int ret;
robbiew7bdb08e2004-03-17 21:14:52 +0000105
Wanlong Gao354ebb42012-12-07 10:10:04 +0800106 if ((ret = pthread_cond_init(cond, NULL)) != 0) {
107 tst_brkm(TBROK, cleanup, "pthread_cond_init failed: %s",
108 strerror_r(ret, buf, buf_len));
109 }
robbiew7bdb08e2004-03-17 21:14:52 +0000110}
111
Wanlong Gao354ebb42012-12-07 10:10:04 +0800112void call_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex,
113 char *buf, size_t buf_len)
114{
115 int ret;
robbiew7bdb08e2004-03-17 21:14:52 +0000116
Wanlong Gao354ebb42012-12-07 10:10:04 +0800117 if ((ret = pthread_cond_wait(cond, mutex)) != 0) {
118 tst_brkm(TBROK, cleanup, "pthread_cond_wait failed: %s",
119 strerror_r(ret, buf, buf_len));
120 }
robbiew7bdb08e2004-03-17 21:14:52 +0000121}
122
Wanlong Gao354ebb42012-12-07 10:10:04 +0800123void call_cond_signal(pthread_cond_t * cond, char *buf, size_t buf_len)
124{
125 int ret;
robbiew7bdb08e2004-03-17 21:14:52 +0000126
Wanlong Gao354ebb42012-12-07 10:10:04 +0800127 if ((ret = pthread_cond_signal(cond)) != 0) {
128 tst_brkm(TBROK, cleanup, "pthread_cond_signal failed: %s",
129 strerror_r(ret, buf, buf_len));
130 }
robbiew7bdb08e2004-03-17 21:14:52 +0000131}
132
Wanlong Gao354ebb42012-12-07 10:10:04 +0800133void do_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
134 char *buf, size_t buf_len, int i)
135{
136 struct timeval tv;
137 struct timespec ts;
138 int ret;
robbiew7bdb08e2004-03-17 21:14:52 +0000139
Wanlong Gao354ebb42012-12-07 10:10:04 +0800140 if (gettimeofday(&tv, NULL) != 0) {
141 tst_brkm(TBROK, cleanup, "gettimeofday failed: %s",
142 strerror_r(errno, buf, buf_len));
143 }
subrata_modakbdbaec52009-02-26 12:14:51 +0000144
Wanlong Gao354ebb42012-12-07 10:10:04 +0800145 ts.tv_sec = tv.tv_sec;
146 ts.tv_nsec = (tv.tv_usec * 1000) + NSECS_TO_WAIT;
147 ts.tv_sec += ts.tv_nsec / 1000000000;
148 ts.tv_nsec = ts.tv_nsec % 1000000000;
robbiew7bdb08e2004-03-17 21:14:52 +0000149
Wanlong Gao354ebb42012-12-07 10:10:04 +0800150 call_mutex_lock(mutex, buf, buf_len);
151 if ((ret = pthread_cond_timedwait(cond, mutex, &ts)) != ETIMEDOUT) {
robbiewcf925b22004-04-23 16:18:40 +0000152#if DEBUG
Wanlong Gao354ebb42012-12-07 10:10:04 +0800153 tst_resm(TINFO,
154 "Loop %d of 1000000: pthread_cond_timedwait() didn't timeout",
155 i);
156 tst_resm(TINFO,
157 "You may want to try reducing the value of NSECS_TO_WAIT (currently=%d)",
158 NSECS_TO_WAIT);
robbiewcf925b22004-04-23 16:18:40 +0000159#endif
Wanlong Gao354ebb42012-12-07 10:10:04 +0800160 }
161 call_mutex_unlock(mutex, buf, buf_len);
robbiew7bdb08e2004-03-17 21:14:52 +0000162
163}
164
Wanlong Gao354ebb42012-12-07 10:10:04 +0800165void *run(void *arg)
robbiew7bdb08e2004-03-17 21:14:52 +0000166{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800167 char buf[1024];
robbiew7bdb08e2004-03-17 21:14:52 +0000168
Wanlong Gao354ebb42012-12-07 10:10:04 +0800169 while (1) {
170 call_mutex_lock(&ack, buf, sizeof(buf));
171 idle_count = 1;
172 call_cond_signal(&parent, buf, sizeof(buf));
173 call_mutex_lock(&req, buf, sizeof(buf));
174 call_mutex_unlock(&ack, buf, sizeof(buf));
subrata_modakbdbaec52009-02-26 12:14:51 +0000175
Wanlong Gao354ebb42012-12-07 10:10:04 +0800176 call_mutex_lock(&wait, buf, sizeof(buf));
177 call_cond_signal(&parent, buf, sizeof(buf));
178 call_mutex_unlock(&wait, buf, sizeof(buf));
robbiew7bdb08e2004-03-17 21:14:52 +0000179
Wanlong Gao354ebb42012-12-07 10:10:04 +0800180 call_cond_wait(&child, &req, buf, sizeof(buf));
181 call_mutex_unlock(&req, buf, sizeof(buf));
182 }
robbiew7bdb08e2004-03-17 21:14:52 +0000183}
184
Wanlong Gao354ebb42012-12-07 10:10:04 +0800185void create_child_thread(char *buf, size_t buf_len)
robbiew7bdb08e2004-03-17 21:14:52 +0000186{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800187 pthread_attr_t attr;
188 pthread_t child_tid;
189 int ret;
robbiew7bdb08e2004-03-17 21:14:52 +0000190
Wanlong Gao354ebb42012-12-07 10:10:04 +0800191 if ((ret = pthread_attr_init(&attr)) != 0) {
192 tst_brkm(TBROK, cleanup, "pthread_attr_init failed: %s",
193 strerror_r(ret, buf, buf_len));
194 }
195 if ((ret = pthread_attr_setdetachstate(&attr,
196 PTHREAD_CREATE_DETACHED)) != 0) {
197 tst_brkm(TBROK, cleanup,
198 "pthread_attr_setdetachstate failed: %s",
199 strerror_r(ret, buf, buf_len));
200 }
201 if ((ret = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)) != 0) {
202 tst_brkm(TBROK, cleanup, "pthread_attr_setscope failed: %s",
203 strerror_r(ret, buf, buf_len));
204 }
robbiew7bdb08e2004-03-17 21:14:52 +0000205
Wanlong Gao354ebb42012-12-07 10:10:04 +0800206 if ((ret = pthread_create(&child_tid, &attr, run, NULL)) != 0) {
207 tst_brkm(TBROK, cleanup, "pthread_create failed: %s",
208 strerror_r(ret, buf, buf_len));
209 }
robbiew7bdb08e2004-03-17 21:14:52 +0000210}
211
Wanlong Gao354ebb42012-12-07 10:10:04 +0800212void trap_alarm(int sig)
subrata_modakf413e9a2008-07-11 10:25:10 +0000213{
Wanlong Gao354ebb42012-12-07 10:10:04 +0800214 tst_brkm(TFAIL, cleanup, "Test hang longer than %d sec detected",
215 MAXTIME);
subrata_modakf413e9a2008-07-11 10:25:10 +0000216}
217
Wanlong Gao354ebb42012-12-07 10:10:04 +0800218static void usage(const char *progname)
219{
220 fprintf(stderr, "usage: %s -l loops\n", progname);
221 fprintf(stderr, "\t-l specify the number of loops to carry out\n");
222}
223
224int main(int argc, char **argv)
robbiew7bdb08e2004-03-17 21:14:52 +0000225{
robbiewda2abda2004-03-17 21:27:20 +0000226#ifdef USING_NPTL
Wanlong Gao354ebb42012-12-07 10:10:04 +0800227 char buf[1024];
228 int i;
229 extern char *optarg;
230 int numloops = NUMLOOPS;
robbiew7bdb08e2004-03-17 21:14:52 +0000231
Wanlong Gao354ebb42012-12-07 10:10:04 +0800232 while ((i = getopt(argc, argv, "l:")) != -1) {
233 switch (i) {
234 case 'l':
235 if (optarg)
236 numloops = atoi(optarg);
237 else
238 fprintf(stderr,
239 "%s: option -l requires an argument\n",
240 argv[0]);
241 break;
242 default:
243 usage(argv[0]);
244 exit(1);
245 }
246 }
Garrett Cooper2c282152010-12-16 00:55:50 -0800247
Wanlong Gao354ebb42012-12-07 10:10:04 +0800248 signal(SIGALRM, trap_alarm);
249 alarm(MAXTIME);
plars1f9577e2005-04-27 15:24:35 +0000250
Wanlong Gao354ebb42012-12-07 10:10:04 +0800251 call_mutex_init(&req, buf, sizeof(buf));
252 call_mutex_init(&ack, buf, sizeof(buf));
253 call_mutex_init(&wait, buf, sizeof(buf));
254 call_cond_init(&parent, buf, sizeof(buf));
255 call_cond_init(&child, buf, sizeof(buf));
robbiew7bdb08e2004-03-17 21:14:52 +0000256
robbiew7bdb08e2004-03-17 21:14:52 +0000257 call_mutex_lock(&ack, buf, sizeof(buf));
robbiew7bdb08e2004-03-17 21:14:52 +0000258
Wanlong Gao354ebb42012-12-07 10:10:04 +0800259 create_child_thread(buf, sizeof(buf));
260
261 tst_resm(TINFO, "Starting test, please wait.");
262 for (i = 0; i < numloops; i++) {
263 while (idle_count == 0) {
264 call_cond_wait(&parent, &ack, buf, sizeof(buf));
265 };
266 idle_count = 0;
267 call_mutex_unlock(&ack, buf, sizeof(buf));
268
269 do_timedwait(&parent, &wait, buf, sizeof(buf), i);
270
271 call_mutex_lock(&req, buf, sizeof(buf));
272 call_cond_signal(&child, buf, sizeof(buf));
273 call_mutex_unlock(&req, buf, sizeof(buf));
274#ifdef DEBUG
275 tst_resm(TINFO, "Success in loop %d", i);
276#else
277 if (((i % (numloops / 10)) == 0) && (i != 0))
278 tst_resm(TINFO, "Success thru loop %d of %i", i,
279 numloops);
280#endif
281 call_mutex_lock(&ack, buf, sizeof(buf));
282 }
283
284 alarm(0);
285 tst_resm(TPASS, "Test completed successfully!");
286 cleanup();
robbiew7bdb08e2004-03-17 21:14:52 +0000287
robbiewda2abda2004-03-17 21:27:20 +0000288#else
Cyril Hrubis526fdf82014-12-04 14:35:01 +0100289 tst_brkm(TCONF, NULL,
290 "Skipping Execution - This system is not using NPTL");
robbiewda2abda2004-03-17 21:27:20 +0000291#endif
Garrett Cooper2c282152010-12-16 00:55:50 -0800292
Wanlong Gao354ebb42012-12-07 10:10:04 +0800293 return 1;
robbiew7bdb08e2004-03-17 21:14:52 +0000294}
295
296/*
297 *cleanup() - performs all ONE TIME cleanup for this test at
298 * completion or premature exit.
299 */
Wanlong Gao354ebb42012-12-07 10:10:04 +0800300void cleanup()
robbiew7bdb08e2004-03-17 21:14:52 +0000301{
302
Wanlong Gao354ebb42012-12-07 10:10:04 +0800303 tst_exit();
Chris Dearmanec6edca2012-10-17 19:54:01 -0700304}