robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 1 | /* |
| 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 Gao | fed9641 | 2012-10-24 10:10:29 +0800 | [diff] [blame] | 13 | * with this program; if not, write the Free Software Foundation, Inc., |
| 14 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 15 | * |
| 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_modak | da124b9 | 2009-10-13 14:00:45 +0000 | [diff] [blame] | 38 | #define _GNU_SOURCE |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 39 | #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" |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 48 | |
mridge | bf7d859 | 2006-02-20 17:26:10 +0000 | [diff] [blame] | 49 | #define MAXTIME 72000 /* Maximum # of secs to wait before failing */ |
robbiew | 283ef20 | 2005-08-03 15:18:36 +0000 | [diff] [blame] | 50 | #define NUMLOOPS 100000 /* # of loops */ |
plars | 1f9577e | 2005-04-27 15:24:35 +0000 | [diff] [blame] | 51 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 52 | char *TCID = "nptl01"; /* Test program identifier. */ |
| 53 | int TST_TOTAL = 1; /* Total number of test cases. */ |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 54 | void cleanup(); |
| 55 | |
| 56 | pthread_mutex_t req; |
| 57 | pthread_mutex_t ack; |
| 58 | pthread_mutex_t wait; |
| 59 | pthread_cond_t parent; |
| 60 | pthread_cond_t child; |
| 61 | int 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 | */ |
robbiew | b6bd2b4 | 2004-03-17 23:19:01 +0000 | [diff] [blame] | 70 | #define NSECS_TO_WAIT (1) |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 71 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 72 | void call_mutex_init(pthread_mutex_t * mutex, char *buf, size_t buf_len) |
| 73 | { |
| 74 | int ret; |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 75 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 76 | 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 | } |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 80 | } |
| 81 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 82 | void call_mutex_lock(pthread_mutex_t * mutex, char *buf, size_t buf_len) |
| 83 | { |
| 84 | int ret; |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 85 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 86 | 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 | } |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 90 | } |
| 91 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 92 | void call_mutex_unlock(pthread_mutex_t * mutex, char *buf, size_t buf_len) |
| 93 | { |
| 94 | int ret; |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 95 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 96 | 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 | } |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 100 | } |
| 101 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 102 | void call_cond_init(pthread_cond_t * cond, char *buf, size_t buf_len) |
| 103 | { |
| 104 | int ret; |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 105 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 106 | 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 | } |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 110 | } |
| 111 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 112 | void call_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex, |
| 113 | char *buf, size_t buf_len) |
| 114 | { |
| 115 | int ret; |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 116 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 117 | 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 | } |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 121 | } |
| 122 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 123 | void call_cond_signal(pthread_cond_t * cond, char *buf, size_t buf_len) |
| 124 | { |
| 125 | int ret; |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 126 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 127 | 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 | } |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 131 | } |
| 132 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 133 | void 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; |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 139 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 140 | if (gettimeofday(&tv, NULL) != 0) { |
| 141 | tst_brkm(TBROK, cleanup, "gettimeofday failed: %s", |
| 142 | strerror_r(errno, buf, buf_len)); |
| 143 | } |
subrata_modak | bdbaec5 | 2009-02-26 12:14:51 +0000 | [diff] [blame] | 144 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 145 | 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; |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 149 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 150 | call_mutex_lock(mutex, buf, buf_len); |
| 151 | if ((ret = pthread_cond_timedwait(cond, mutex, &ts)) != ETIMEDOUT) { |
robbiew | cf925b2 | 2004-04-23 16:18:40 +0000 | [diff] [blame] | 152 | #if DEBUG |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 153 | 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); |
robbiew | cf925b2 | 2004-04-23 16:18:40 +0000 | [diff] [blame] | 159 | #endif |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 160 | } |
| 161 | call_mutex_unlock(mutex, buf, buf_len); |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 162 | |
| 163 | } |
| 164 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 165 | void *run(void *arg) |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 166 | { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 167 | char buf[1024]; |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 168 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 169 | 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_modak | bdbaec5 | 2009-02-26 12:14:51 +0000 | [diff] [blame] | 175 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 176 | call_mutex_lock(&wait, buf, sizeof(buf)); |
| 177 | call_cond_signal(&parent, buf, sizeof(buf)); |
| 178 | call_mutex_unlock(&wait, buf, sizeof(buf)); |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 179 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 180 | call_cond_wait(&child, &req, buf, sizeof(buf)); |
| 181 | call_mutex_unlock(&req, buf, sizeof(buf)); |
| 182 | } |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 183 | } |
| 184 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 185 | void create_child_thread(char *buf, size_t buf_len) |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 186 | { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 187 | pthread_attr_t attr; |
| 188 | pthread_t child_tid; |
| 189 | int ret; |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 190 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 191 | 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 | } |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 205 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 206 | 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 | } |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 210 | } |
| 211 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 212 | void trap_alarm(int sig) |
subrata_modak | f413e9a | 2008-07-11 10:25:10 +0000 | [diff] [blame] | 213 | { |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 214 | tst_brkm(TFAIL, cleanup, "Test hang longer than %d sec detected", |
| 215 | MAXTIME); |
subrata_modak | f413e9a | 2008-07-11 10:25:10 +0000 | [diff] [blame] | 216 | } |
| 217 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 218 | static 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 | |
| 224 | int main(int argc, char **argv) |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 225 | { |
robbiew | da2abda | 2004-03-17 21:27:20 +0000 | [diff] [blame] | 226 | #ifdef USING_NPTL |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 227 | char buf[1024]; |
| 228 | int i; |
| 229 | extern char *optarg; |
| 230 | int numloops = NUMLOOPS; |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 231 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 232 | 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 Cooper | 2c28215 | 2010-12-16 00:55:50 -0800 | [diff] [blame] | 247 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 248 | signal(SIGALRM, trap_alarm); |
| 249 | alarm(MAXTIME); |
plars | 1f9577e | 2005-04-27 15:24:35 +0000 | [diff] [blame] | 250 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 251 | 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)); |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 256 | |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 257 | call_mutex_lock(&ack, buf, sizeof(buf)); |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 258 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 259 | 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(); |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 287 | |
robbiew | da2abda | 2004-03-17 21:27:20 +0000 | [diff] [blame] | 288 | #else |
Cyril Hrubis | 526fdf8 | 2014-12-04 14:35:01 +0100 | [diff] [blame] | 289 | tst_brkm(TCONF, NULL, |
| 290 | "Skipping Execution - This system is not using NPTL"); |
robbiew | da2abda | 2004-03-17 21:27:20 +0000 | [diff] [blame] | 291 | #endif |
Garrett Cooper | 2c28215 | 2010-12-16 00:55:50 -0800 | [diff] [blame] | 292 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 293 | return 1; |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 294 | } |
| 295 | |
| 296 | /* |
| 297 | *cleanup() - performs all ONE TIME cleanup for this test at |
| 298 | * completion or premature exit. |
| 299 | */ |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 300 | void cleanup() |
robbiew | 7bdb08e | 2004-03-17 21:14:52 +0000 | [diff] [blame] | 301 | { |
| 302 | |
Wanlong Gao | 354ebb4 | 2012-12-07 10:10:04 +0800 | [diff] [blame] | 303 | tst_exit(); |
Chris Dearman | ec6edca | 2012-10-17 19:54:01 -0700 | [diff] [blame] | 304 | } |