1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * Copyright (c) International Business Machines  Corp., 2004.
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or modify it
5f08c3bdfSopenharmony_ci * under the terms of version 2 of the GNU General Public License as
6f08c3bdfSopenharmony_ci * published by the Free Software Foundation.
7f08c3bdfSopenharmony_ci *
8f08c3bdfSopenharmony_ci * This program is distributed in the hope that it would be useful, but
9f08c3bdfSopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
10f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11f08c3bdfSopenharmony_ci *
12f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License along
13f08c3bdfSopenharmony_ci * with this program; if not, write the Free Software Foundation, Inc.,
14f08c3bdfSopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
15f08c3bdfSopenharmony_ci *
16f08c3bdfSopenharmony_ci */
17f08c3bdfSopenharmony_ci/**********************************************************
18f08c3bdfSopenharmony_ci *
19f08c3bdfSopenharmony_ci *    TEST IDENTIFIER   : nptl01
20f08c3bdfSopenharmony_ci *
21f08c3bdfSopenharmony_ci *    EXECUTED BY       : root
22f08c3bdfSopenharmony_ci *
23f08c3bdfSopenharmony_ci *    TEST TITLE        : NPTL test for pthread_cond_timedwait() error
24f08c3bdfSopenharmony_ci *			  path bug.
25f08c3bdfSopenharmony_ci *
26f08c3bdfSopenharmony_ci *    TEST CASE TOTAL   : 1
27f08c3bdfSopenharmony_ci *
28f08c3bdfSopenharmony_ci *    AUTHOR            : Neil Richards <neil_richards@uk.ibm.com>
29f08c3bdfSopenharmony_ci *
30f08c3bdfSopenharmony_ci *    DESCRIPTION
31f08c3bdfSopenharmony_ci *      This is a test for a bug found in the pthread_cond_timedwait() system call.
32f08c3bdfSopenharmony_ci *	of the Native POSIX Thread Library (NPTL) library code.
33f08c3bdfSopenharmony_ci *      There was an error path in the system call, where the sequence counters were
34f08c3bdfSopenharmony_ci *      getting updated w/o holding the internal condvar lock. A FAIL is indicated
35f08c3bdfSopenharmony_ci *	by the test hanging and not completing execution.
36f08c3bdfSopenharmony_ci *
37f08c3bdfSopenharmony_ci ****************************************************************/
38f08c3bdfSopenharmony_ci#define _GNU_SOURCE
39f08c3bdfSopenharmony_ci#include <stdio.h>
40f08c3bdfSopenharmony_ci#include <stdlib.h>
41f08c3bdfSopenharmony_ci#include <string.h>
42f08c3bdfSopenharmony_ci#include <pthread.h>
43f08c3bdfSopenharmony_ci#include <errno.h>
44f08c3bdfSopenharmony_ci#include <unistd.h>
45f08c3bdfSopenharmony_ci#include <time.h>
46f08c3bdfSopenharmony_ci#include <sys/time.h>
47f08c3bdfSopenharmony_ci#include "test.h"
48f08c3bdfSopenharmony_ci
49f08c3bdfSopenharmony_ci#define MAXTIME 72000		/* Maximum # of secs to wait before failing */
50f08c3bdfSopenharmony_ci#define NUMLOOPS 100000		/* # of loops */
51f08c3bdfSopenharmony_ci
52f08c3bdfSopenharmony_cichar *TCID = "nptl01";		/* Test program identifier.    */
53f08c3bdfSopenharmony_ciint TST_TOTAL = 1;		/* Total number of test cases. */
54f08c3bdfSopenharmony_civoid cleanup();
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_cipthread_mutex_t req;
57f08c3bdfSopenharmony_cipthread_mutex_t ack;
58f08c3bdfSopenharmony_cipthread_mutex_t wait;
59f08c3bdfSopenharmony_cipthread_cond_t parent;
60f08c3bdfSopenharmony_cipthread_cond_t child;
61f08c3bdfSopenharmony_ciint idle_count = 0;
62f08c3bdfSopenharmony_ci
63f08c3bdfSopenharmony_ci/*
64f08c3bdfSopenharmony_ci * The time to wait should be set appropriately so that the waiting thread
65f08c3bdfSopenharmony_ci * is coming out of the wait at around the same time as the other thread is
66f08c3bdfSopenharmony_ci * signalling it.
67f08c3bdfSopenharmony_ci * The value of 1000 seems to work (ie. demonstrate the problem) on my
68f08c3bdfSopenharmony_ci * 8 way (hyperthreaded) 2GHz Xeon box.
69f08c3bdfSopenharmony_ci */
70f08c3bdfSopenharmony_ci#define NSECS_TO_WAIT	(1)
71f08c3bdfSopenharmony_ci
72f08c3bdfSopenharmony_civoid call_mutex_init(pthread_mutex_t * mutex, char *buf, size_t buf_len)
73f08c3bdfSopenharmony_ci{
74f08c3bdfSopenharmony_ci	int ret;
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_ci	if ((ret = pthread_mutex_init(mutex, NULL)) != 0) {
77f08c3bdfSopenharmony_ci		tst_brkm(TBROK, cleanup, "pthread_mutex_init failed: %s",
78f08c3bdfSopenharmony_ci			 strerror_r(ret, buf, buf_len));
79f08c3bdfSopenharmony_ci	}
80f08c3bdfSopenharmony_ci}
81f08c3bdfSopenharmony_ci
82f08c3bdfSopenharmony_civoid call_mutex_lock(pthread_mutex_t * mutex, char *buf, size_t buf_len)
83f08c3bdfSopenharmony_ci{
84f08c3bdfSopenharmony_ci	int ret;
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci	if ((ret = pthread_mutex_lock(mutex)) != 0) {
87f08c3bdfSopenharmony_ci		tst_brkm(TBROK, cleanup, "pthread_mutex_lock failed: %s",
88f08c3bdfSopenharmony_ci			 strerror_r(ret, buf, buf_len));
89f08c3bdfSopenharmony_ci	}
90f08c3bdfSopenharmony_ci}
91f08c3bdfSopenharmony_ci
92f08c3bdfSopenharmony_civoid call_mutex_unlock(pthread_mutex_t * mutex, char *buf, size_t buf_len)
93f08c3bdfSopenharmony_ci{
94f08c3bdfSopenharmony_ci	int ret;
95f08c3bdfSopenharmony_ci
96f08c3bdfSopenharmony_ci	if ((ret = pthread_mutex_unlock(mutex)) != 0) {
97f08c3bdfSopenharmony_ci		tst_brkm(TBROK, cleanup, "pthread_mutex_unlock failed: %s",
98f08c3bdfSopenharmony_ci			 strerror_r(ret, buf, buf_len));
99f08c3bdfSopenharmony_ci	}
100f08c3bdfSopenharmony_ci}
101f08c3bdfSopenharmony_ci
102f08c3bdfSopenharmony_civoid call_cond_init(pthread_cond_t * cond, char *buf, size_t buf_len)
103f08c3bdfSopenharmony_ci{
104f08c3bdfSopenharmony_ci	int ret;
105f08c3bdfSopenharmony_ci
106f08c3bdfSopenharmony_ci	if ((ret = pthread_cond_init(cond, NULL)) != 0) {
107f08c3bdfSopenharmony_ci		tst_brkm(TBROK, cleanup, "pthread_cond_init failed: %s",
108f08c3bdfSopenharmony_ci			 strerror_r(ret, buf, buf_len));
109f08c3bdfSopenharmony_ci	}
110f08c3bdfSopenharmony_ci}
111f08c3bdfSopenharmony_ci
112f08c3bdfSopenharmony_civoid call_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex,
113f08c3bdfSopenharmony_ci		    char *buf, size_t buf_len)
114f08c3bdfSopenharmony_ci{
115f08c3bdfSopenharmony_ci	int ret;
116f08c3bdfSopenharmony_ci
117f08c3bdfSopenharmony_ci	if ((ret = pthread_cond_wait(cond, mutex)) != 0) {
118f08c3bdfSopenharmony_ci		tst_brkm(TBROK, cleanup, "pthread_cond_wait failed: %s",
119f08c3bdfSopenharmony_ci			 strerror_r(ret, buf, buf_len));
120f08c3bdfSopenharmony_ci	}
121f08c3bdfSopenharmony_ci}
122f08c3bdfSopenharmony_ci
123f08c3bdfSopenharmony_civoid call_cond_signal(pthread_cond_t * cond, char *buf, size_t buf_len)
124f08c3bdfSopenharmony_ci{
125f08c3bdfSopenharmony_ci	int ret;
126f08c3bdfSopenharmony_ci
127f08c3bdfSopenharmony_ci	if ((ret = pthread_cond_signal(cond)) != 0) {
128f08c3bdfSopenharmony_ci		tst_brkm(TBROK, cleanup, "pthread_cond_signal failed: %s",
129f08c3bdfSopenharmony_ci			 strerror_r(ret, buf, buf_len));
130f08c3bdfSopenharmony_ci	}
131f08c3bdfSopenharmony_ci}
132f08c3bdfSopenharmony_ci
133f08c3bdfSopenharmony_civoid do_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
134f08c3bdfSopenharmony_ci		  char *buf, size_t buf_len, int i)
135f08c3bdfSopenharmony_ci{
136f08c3bdfSopenharmony_ci	struct timeval tv;
137f08c3bdfSopenharmony_ci	struct timespec ts;
138f08c3bdfSopenharmony_ci	int ret;
139f08c3bdfSopenharmony_ci
140f08c3bdfSopenharmony_ci	if (gettimeofday(&tv, NULL) != 0) {
141f08c3bdfSopenharmony_ci		tst_brkm(TBROK, cleanup, "gettimeofday failed: %s",
142f08c3bdfSopenharmony_ci			 strerror_r(errno, buf, buf_len));
143f08c3bdfSopenharmony_ci	}
144f08c3bdfSopenharmony_ci
145f08c3bdfSopenharmony_ci	ts.tv_sec = tv.tv_sec;
146f08c3bdfSopenharmony_ci	ts.tv_nsec = (tv.tv_usec * 1000) + NSECS_TO_WAIT;
147f08c3bdfSopenharmony_ci	ts.tv_sec += ts.tv_nsec / 1000000000;
148f08c3bdfSopenharmony_ci	ts.tv_nsec = ts.tv_nsec % 1000000000;
149f08c3bdfSopenharmony_ci
150f08c3bdfSopenharmony_ci	call_mutex_lock(mutex, buf, buf_len);
151f08c3bdfSopenharmony_ci	if ((ret = pthread_cond_timedwait(cond, mutex, &ts)) != ETIMEDOUT) {
152f08c3bdfSopenharmony_ci#if DEBUG
153f08c3bdfSopenharmony_ci		tst_resm(TINFO,
154f08c3bdfSopenharmony_ci			 "Loop %d of 1000000: pthread_cond_timedwait() didn't timeout",
155f08c3bdfSopenharmony_ci			 i);
156f08c3bdfSopenharmony_ci		tst_resm(TINFO,
157f08c3bdfSopenharmony_ci			 "You may want to try reducing the value of NSECS_TO_WAIT (currently=%d)",
158f08c3bdfSopenharmony_ci			 NSECS_TO_WAIT);
159f08c3bdfSopenharmony_ci#endif
160f08c3bdfSopenharmony_ci	}
161f08c3bdfSopenharmony_ci	call_mutex_unlock(mutex, buf, buf_len);
162f08c3bdfSopenharmony_ci
163f08c3bdfSopenharmony_ci}
164f08c3bdfSopenharmony_ci
165f08c3bdfSopenharmony_civoid *run(void *arg)
166f08c3bdfSopenharmony_ci{
167f08c3bdfSopenharmony_ci	char buf[1024];
168f08c3bdfSopenharmony_ci
169f08c3bdfSopenharmony_ci	while (1) {
170f08c3bdfSopenharmony_ci		call_mutex_lock(&ack, buf, sizeof(buf));
171f08c3bdfSopenharmony_ci		idle_count = 1;
172f08c3bdfSopenharmony_ci		call_cond_signal(&parent, buf, sizeof(buf));
173f08c3bdfSopenharmony_ci		call_mutex_lock(&req, buf, sizeof(buf));
174f08c3bdfSopenharmony_ci		call_mutex_unlock(&ack, buf, sizeof(buf));
175f08c3bdfSopenharmony_ci
176f08c3bdfSopenharmony_ci		call_mutex_lock(&wait, buf, sizeof(buf));
177f08c3bdfSopenharmony_ci		call_cond_signal(&parent, buf, sizeof(buf));
178f08c3bdfSopenharmony_ci		call_mutex_unlock(&wait, buf, sizeof(buf));
179f08c3bdfSopenharmony_ci
180f08c3bdfSopenharmony_ci		call_cond_wait(&child, &req, buf, sizeof(buf));
181f08c3bdfSopenharmony_ci		call_mutex_unlock(&req, buf, sizeof(buf));
182f08c3bdfSopenharmony_ci	}
183f08c3bdfSopenharmony_ci}
184f08c3bdfSopenharmony_ci
185f08c3bdfSopenharmony_civoid create_child_thread(char *buf, size_t buf_len)
186f08c3bdfSopenharmony_ci{
187f08c3bdfSopenharmony_ci	pthread_attr_t attr;
188f08c3bdfSopenharmony_ci	pthread_t child_tid;
189f08c3bdfSopenharmony_ci	int ret;
190f08c3bdfSopenharmony_ci
191f08c3bdfSopenharmony_ci	if ((ret = pthread_attr_init(&attr)) != 0) {
192f08c3bdfSopenharmony_ci		tst_brkm(TBROK, cleanup, "pthread_attr_init failed: %s",
193f08c3bdfSopenharmony_ci			 strerror_r(ret, buf, buf_len));
194f08c3bdfSopenharmony_ci	}
195f08c3bdfSopenharmony_ci	if ((ret = pthread_attr_setdetachstate(&attr,
196f08c3bdfSopenharmony_ci					       PTHREAD_CREATE_DETACHED)) != 0) {
197f08c3bdfSopenharmony_ci		tst_brkm(TBROK, cleanup,
198f08c3bdfSopenharmony_ci			 "pthread_attr_setdetachstate failed: %s",
199f08c3bdfSopenharmony_ci			 strerror_r(ret, buf, buf_len));
200f08c3bdfSopenharmony_ci	}
201f08c3bdfSopenharmony_ci	if ((ret = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)) != 0) {
202f08c3bdfSopenharmony_ci		tst_brkm(TBROK, cleanup, "pthread_attr_setscope failed: %s",
203f08c3bdfSopenharmony_ci			 strerror_r(ret, buf, buf_len));
204f08c3bdfSopenharmony_ci	}
205f08c3bdfSopenharmony_ci
206f08c3bdfSopenharmony_ci	if ((ret = pthread_create(&child_tid, &attr, run, NULL)) != 0) {
207f08c3bdfSopenharmony_ci		tst_brkm(TBROK, cleanup, "pthread_create failed: %s",
208f08c3bdfSopenharmony_ci			 strerror_r(ret, buf, buf_len));
209f08c3bdfSopenharmony_ci	}
210f08c3bdfSopenharmony_ci}
211f08c3bdfSopenharmony_ci
212f08c3bdfSopenharmony_civoid trap_alarm(int sig)
213f08c3bdfSopenharmony_ci{
214f08c3bdfSopenharmony_ci	tst_brkm(TFAIL, cleanup, "Test hang longer than %d sec detected",
215f08c3bdfSopenharmony_ci		 MAXTIME);
216f08c3bdfSopenharmony_ci}
217f08c3bdfSopenharmony_ci
218f08c3bdfSopenharmony_cistatic void usage(const char *progname)
219f08c3bdfSopenharmony_ci{
220f08c3bdfSopenharmony_ci	fprintf(stderr, "usage: %s -l loops\n", progname);
221f08c3bdfSopenharmony_ci	fprintf(stderr, "\t-l specify the number of loops to carry out\n");
222f08c3bdfSopenharmony_ci}
223f08c3bdfSopenharmony_ci
224f08c3bdfSopenharmony_ciint main(int argc, char **argv)
225f08c3bdfSopenharmony_ci{
226f08c3bdfSopenharmony_ci#ifdef USING_NPTL
227f08c3bdfSopenharmony_ci	char buf[1024];
228f08c3bdfSopenharmony_ci	int i;
229f08c3bdfSopenharmony_ci	extern char *optarg;
230f08c3bdfSopenharmony_ci	int numloops = NUMLOOPS;
231f08c3bdfSopenharmony_ci
232f08c3bdfSopenharmony_ci	while ((i = getopt(argc, argv, "l:")) != -1) {
233f08c3bdfSopenharmony_ci		switch (i) {
234f08c3bdfSopenharmony_ci		case 'l':
235f08c3bdfSopenharmony_ci			if (optarg)
236f08c3bdfSopenharmony_ci				numloops = atoi(optarg);
237f08c3bdfSopenharmony_ci			else
238f08c3bdfSopenharmony_ci				fprintf(stderr,
239f08c3bdfSopenharmony_ci					"%s: option -l requires an argument\n",
240f08c3bdfSopenharmony_ci					argv[0]);
241f08c3bdfSopenharmony_ci			break;
242f08c3bdfSopenharmony_ci		default:
243f08c3bdfSopenharmony_ci			usage(argv[0]);
244f08c3bdfSopenharmony_ci			exit(1);
245f08c3bdfSopenharmony_ci		}
246f08c3bdfSopenharmony_ci	}
247f08c3bdfSopenharmony_ci
248f08c3bdfSopenharmony_ci	signal(SIGALRM, trap_alarm);
249f08c3bdfSopenharmony_ci	alarm(MAXTIME);
250f08c3bdfSopenharmony_ci
251f08c3bdfSopenharmony_ci	call_mutex_init(&req, buf, sizeof(buf));
252f08c3bdfSopenharmony_ci	call_mutex_init(&ack, buf, sizeof(buf));
253f08c3bdfSopenharmony_ci	call_mutex_init(&wait, buf, sizeof(buf));
254f08c3bdfSopenharmony_ci	call_cond_init(&parent, buf, sizeof(buf));
255f08c3bdfSopenharmony_ci	call_cond_init(&child, buf, sizeof(buf));
256f08c3bdfSopenharmony_ci
257f08c3bdfSopenharmony_ci	call_mutex_lock(&ack, buf, sizeof(buf));
258f08c3bdfSopenharmony_ci
259f08c3bdfSopenharmony_ci	create_child_thread(buf, sizeof(buf));
260f08c3bdfSopenharmony_ci
261f08c3bdfSopenharmony_ci	tst_resm(TINFO, "Starting test, please wait.");
262f08c3bdfSopenharmony_ci	for (i = 0; i < numloops; i++) {
263f08c3bdfSopenharmony_ci		while (idle_count == 0) {
264f08c3bdfSopenharmony_ci			call_cond_wait(&parent, &ack, buf, sizeof(buf));
265f08c3bdfSopenharmony_ci		};
266f08c3bdfSopenharmony_ci		idle_count = 0;
267f08c3bdfSopenharmony_ci		call_mutex_unlock(&ack, buf, sizeof(buf));
268f08c3bdfSopenharmony_ci
269f08c3bdfSopenharmony_ci		do_timedwait(&parent, &wait, buf, sizeof(buf), i);
270f08c3bdfSopenharmony_ci
271f08c3bdfSopenharmony_ci		call_mutex_lock(&req, buf, sizeof(buf));
272f08c3bdfSopenharmony_ci		call_cond_signal(&child, buf, sizeof(buf));
273f08c3bdfSopenharmony_ci		call_mutex_unlock(&req, buf, sizeof(buf));
274f08c3bdfSopenharmony_ci#ifdef DEBUG
275f08c3bdfSopenharmony_ci		tst_resm(TINFO, "Success in loop %d", i);
276f08c3bdfSopenharmony_ci#else
277f08c3bdfSopenharmony_ci		if (((i % (numloops / 10)) == 0) && (i != 0))
278f08c3bdfSopenharmony_ci			tst_resm(TINFO, "Success thru loop %d of %i", i,
279f08c3bdfSopenharmony_ci				 numloops);
280f08c3bdfSopenharmony_ci#endif
281f08c3bdfSopenharmony_ci		call_mutex_lock(&ack, buf, sizeof(buf));
282f08c3bdfSopenharmony_ci	}
283f08c3bdfSopenharmony_ci
284f08c3bdfSopenharmony_ci	alarm(0);
285f08c3bdfSopenharmony_ci	tst_resm(TPASS, "Test completed successfully!");
286f08c3bdfSopenharmony_ci	cleanup();
287f08c3bdfSopenharmony_ci
288f08c3bdfSopenharmony_ci#else
289f08c3bdfSopenharmony_ci	tst_brkm(TCONF, NULL,
290f08c3bdfSopenharmony_ci		 "Skipping Execution - This system is not using NPTL");
291f08c3bdfSopenharmony_ci#endif
292f08c3bdfSopenharmony_ci
293f08c3bdfSopenharmony_ci	return 1;
294f08c3bdfSopenharmony_ci}
295f08c3bdfSopenharmony_ci
296f08c3bdfSopenharmony_ci/*
297f08c3bdfSopenharmony_ci *cleanup() -  performs all ONE TIME cleanup for this test at
298f08c3bdfSopenharmony_ci *              completion or premature exit.
299f08c3bdfSopenharmony_ci */
300f08c3bdfSopenharmony_civoid cleanup()
301f08c3bdfSopenharmony_ci{
302f08c3bdfSopenharmony_ci
303f08c3bdfSopenharmony_ci	tst_exit();
304f08c3bdfSopenharmony_ci}
305