1#!/bin/sh 2 3# 4# Copyright (c) 2016 EMC Corp. 5# All rights reserved. 6# 7# Redistribution and use in source and binary forms, with or without 8# modification, are permitted provided that the following conditions 9# are met: 10# 1. Redistributions of source code must retain the above copyright 11# notice, this list of conditions and the following disclaimer. 12# 2. Redistributions in binary form must reproduce the above copyright 13# notice, this list of conditions and the following disclaimer in the 14# documentation and/or other materials provided with the distribution. 15# 16# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26# SUCH DAMAGE. 27# 28 29# The combination of ualarm() firing before and after the select(2) timeout 30# triggers select() to return EINTR a number of times. 31# Problem only seen on i386. 32 33# Test scenario suggestion by kib@ 34 35# "FAIL n = 2389" seen on r302369, no debug build. 36# Fixed by: r302573. 37 38. ../default.cfg 39 40dir=/tmp 41odir=`pwd` 42cd $dir 43sed '1,/^EOF/d' < $odir/$0 > $dir/select.c 44mycc -o select -Wall -Wextra -O0 -g select.c -lpthread || exit 1 45rm -f select.c 46cd $odir 47 48/tmp/select 49s=$? 50 51rm -f /tmp/select 52exit $s 53EOF 54#include <sys/param.h> 55#include <sys/mman.h> 56#include <sys/stat.h> 57#include <sys/wait.h> 58 59#include <err.h> 60#include <errno.h> 61#include <fcntl.h> 62#include <pthread.h> 63#include <signal.h> 64#include <stdio.h> 65#include <stdlib.h> 66#include <string.h> 67#include <time.h> 68#include <unistd.h> 69 70static pthread_barrier_t barr; 71static sig_atomic_t alarms; 72static int lines; 73 74#define LINES 128000 75#define N 2000 /* also seen fail with N = 20.000 */ 76#define PARALLEL 16 /* Fails seen with 1 - 16 */ 77#define RUNTIME (10 * 60) 78 79static void 80handler(int i __unused) { 81 alarms++; 82} 83 84static void 85test(void) 86{ 87 struct timeval tv; 88 int i, n, r, s; 89 90 r = pthread_barrier_wait(&barr); 91 if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD) 92 errc(1, r, "pthread_barrier_wait"); 93 94 signal(SIGALRM, handler); 95 s = 0; 96 for (i = 0; i < lines; i++) { 97 alarms = 0; 98 if (arc4random() % 100 < 50) 99 ualarm(N / 2, 0); 100 else 101 ualarm(N * 2, 0); 102 tv.tv_sec = 0; 103 tv.tv_usec = N; 104 n = 0; 105 do { 106 r = select(1, NULL, NULL, NULL, &tv); 107 n++; 108 } while (r == -1 && errno == EINTR); 109 if (r == -1) 110 err(1, "select"); 111 ualarm(0, 0); 112 if (n > 2) { 113 fprintf(stderr, "FAIL n = %d, tv = %ld.%06ld\n", 114 n, (long)tv.tv_sec, tv.tv_usec); 115 s = 1; 116 break; 117 } 118 if (alarms > 1) { 119 fprintf(stderr, "FAIL alarms = %d\n", (int)alarms); 120 s = 2; 121 break; 122 } 123 124 } 125 126 exit(s); 127} 128 129int 130main(void) 131{ 132 pthread_barrierattr_t attr; 133 time_t start; 134 int e, i, j, pids[PARALLEL], r, status; 135 136 lines = LINES / PARALLEL; 137 if (lines == 0) 138 lines = 1; 139 e = 0; 140 if ((r = pthread_barrierattr_init(&attr)) != 0) 141 errc(1, r, "pthread_barrierattr_init"); 142 if ((r = pthread_barrierattr_setpshared(&attr, 143 PTHREAD_PROCESS_SHARED)) != 0) 144 errc(1, r, "pthread_barrierattr_setpshared"); 145 if ((r = pthread_barrier_init(&barr, &attr, PARALLEL)) != 0) 146 errc(1, r, "pthread_barrier_init"); 147 148 start = time(NULL); 149 while ((time(NULL) - start) < RUNTIME && e == 0) { 150 for (i = 0; i < PARALLEL; i++) { 151 if ((pids[i] = fork()) == 0) 152 test(); 153 } 154 for (i = 0; i < PARALLEL; i++) { 155 waitpid(pids[i], &status, 0); 156 e += status == 0 ? 0 : 1; 157 if (status != 0) { 158 for (j = i + 1; j < PARALLEL; j++) 159 kill(pids[j], SIGINT); 160 } 161 } 162 } 163 164 if ((r = pthread_barrier_destroy(&barr)) > 0) 165 errc(1, r, "pthread_barrier_destroy"); 166 167 return (e); 168} 169