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