1#!/bin/sh 2 3# 4# Copyright (c) 2014 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# _exit(2) test scenario with focus on shared channel tear down. 30 31. ../default.cfg 32 33here=`pwd` 34cd /tmp 35sed '1,/^EOF/d' < $here/$0 > pthread3.c 36mycc -o pthread3 -Wall -Wextra -O2 -g -gdwarf-2 pthread3.c -lpthread || exit 1 37rm -f pthread3.c 38 39for i in `jot 8`; do 40 /tmp/pthread3 & 41 pids="$pids $!" 42done 43s=0 44for i in $pids; do 45 wait $i 46 e=$? 47 [ $e -ne 0 ] && s=$e 48done 49 50rm -f /tmp/pthread3 51 52exit $s 53EOF 54/* 55 * Threaded producer-consumer test. 56 * Loosly based on work by 57 * Andrey Zonov (c) 2012 58 */ 59 60#include <sys/types.h> 61#include <sys/stat.h> 62#include <sys/time.h> 63#include <sys/queue.h> 64#include <err.h> 65#include <errno.h> 66#include <fcntl.h> 67#include <pthread.h> 68#ifdef __FreeBSD__ 69#include <pthread_np.h> 70#define __NP__ 71#endif 72#include <sched.h> 73#include <signal.h> 74#include <stdio.h> 75#include <stdlib.h> 76#include <string.h> 77#include <time.h> 78#include <unistd.h> 79#include <sys/wait.h> 80 81#define LOCK(x) plock(&x.mtx) 82#define UNLOCK(x) punlock(&x.mtx) 83#define SIGNAL(x) psig(&x.wait) 84#define WAIT(x) pwait(&x.wait, &x.mtx) 85 86long ncreate, nrename, nunlink; 87int max; 88char *dirname1; 89char *dirname2; 90 91struct file { 92 char *name; 93 STAILQ_ENTRY(file) next; 94}; 95 96struct files { 97 pthread_mutex_t mtx; 98 pthread_cond_t wait; 99 STAILQ_HEAD(, file) list; 100}; 101 102static struct files newfiles; 103static struct files renamedfiles; 104 105static void 106hand(int i __unused) { /* handler */ 107 fprintf(stderr, "max = %d, ncreate = %ld, nrename = %ld, nunlink = %ld\n", 108 max, ncreate, nrename, nunlink); 109} 110 111static void 112ahand(int i __unused) { /* handler */ 113 fprintf(stderr, "FAIL\n"); 114 hand(0); 115 _exit(0); 116} 117 118void 119plock(pthread_mutex_t *l) 120{ 121 int rc; 122 123 if ((rc = pthread_mutex_lock(l)) != 0) 124 errc(1, rc, "pthread_mutex_lock"); 125} 126 127void 128punlock(pthread_mutex_t *l) 129{ 130 int rc; 131 132 if ((rc = pthread_mutex_unlock(l)) != 0) 133 errc(1, rc, "pthread_mutex_unlock"); 134} 135 136void 137psig(pthread_cond_t *c) 138{ 139 int rc; 140 141 if ((rc = pthread_cond_signal(c)) != 0) 142 errc(1, rc, "pthread_cond_signal"); 143} 144 145void 146pwait(pthread_cond_t *c, pthread_mutex_t *l) 147{ 148 int rc; 149 150 if ((rc = pthread_cond_wait(c, l)) != 0) 151 errc(1, rc, "pthread_cond_wait"); 152} 153 154void * 155loop_create(void *arg __unused) 156{ 157 int i, j; 158 struct file *file; 159 160#ifdef __NP__ 161 pthread_set_name_np(pthread_self(), __func__); 162#endif 163 164 for (i = 0; i < max; i++) { 165 file = malloc(sizeof(*file)); 166 asprintf(&file->name, "%s/filename_too-long:%d", dirname1, i); 167 LOCK(newfiles); 168 STAILQ_INSERT_TAIL(&newfiles.list, file, next); 169 ncreate++; 170 UNLOCK(newfiles); 171 SIGNAL(newfiles); 172 if ((i > 0) && (i % 100000 == 0)) 173 for (j = 0; j < 10 && ncreate != nrename; j++) 174 usleep(400); 175 } 176 return (NULL); 177} 178 179void * 180loop_rename(void *arg __unused) 181{ 182 char *filename, *newname; 183 struct file *file; 184 185#ifdef __NP__ 186 pthread_set_name_np(pthread_self(), __func__); 187#endif 188 189 while (nrename < max) { 190 LOCK(newfiles); 191 while (STAILQ_EMPTY(&newfiles.list)) { 192 WAIT(newfiles); 193 } 194 file = STAILQ_FIRST(&newfiles.list); 195 STAILQ_REMOVE_HEAD(&newfiles.list, next); 196 UNLOCK(newfiles); 197 filename = strrchr(file->name, '/'); 198 asprintf(&newname, "%s/%s", dirname2, filename); 199 nrename++; 200 free(file->name); 201 file->name = newname; 202 LOCK(renamedfiles); 203 STAILQ_INSERT_TAIL(&renamedfiles.list, file, next); 204 UNLOCK(renamedfiles); 205 SIGNAL(renamedfiles); 206 } 207 return (NULL); 208} 209 210void * 211loop_unlink(void *arg __unused) 212{ 213 struct file *file; 214 215#ifdef __NP__ 216 pthread_set_name_np(pthread_self(), __func__); 217#endif 218 219 while (nunlink < max) { 220 LOCK(renamedfiles); 221 while (STAILQ_EMPTY(&renamedfiles.list)) { 222 WAIT(renamedfiles); 223 } 224 file = STAILQ_FIRST(&renamedfiles.list); 225 STAILQ_REMOVE_HEAD(&renamedfiles.list, next); 226 nunlink++; 227 UNLOCK(renamedfiles); 228 free(file->name); 229 free(file); 230 if (arc4random() % 100 == 1) 231 if (arc4random() % 100 == 1) 232 if (arc4random() % 100 < 10) 233 _exit(0); 234 } 235 return (NULL); 236} 237 238void 239test(void) 240{ 241 int i; 242 int rc; 243 pthread_t tid[3]; 244 245 asprintf(&dirname1, "%s.1", "f1"); 246 asprintf(&dirname2, "%s.2", "f2"); 247// max = 15000000; 248 max = 50000; 249 250 STAILQ_INIT(&newfiles.list); 251 STAILQ_INIT(&renamedfiles.list); 252 253 if ((rc = pthread_mutex_init(&newfiles.mtx, NULL)) != 0) 254 errc(1, rc, "pthread_mutex_init()"); 255 if ((rc = pthread_cond_init(&newfiles.wait, NULL)) != 0) 256 errc(1, rc, "pthread_cond_init()"); 257 if ((rc = pthread_mutex_init(&renamedfiles.mtx, NULL)) != 0) 258 errc(1, rc, "pthread_mutex_init()"); 259 if ((rc = pthread_cond_init(&renamedfiles.wait, NULL)) != 0) 260 errc(1, rc, "pthread_cond_init()"); 261 262 signal(SIGINFO, hand); 263 signal(SIGALRM, ahand); 264 alarm(300); 265 if ((rc = pthread_create(&tid[0], NULL, loop_create, NULL)) != 0) 266 errc(1, rc, "pthread_create()"); 267 if ((rc = pthread_create(&tid[1], NULL, loop_rename, NULL)) != 0) 268 errc(1, rc, "pthread_create()"); 269 if ((rc = pthread_create(&tid[2], NULL, loop_unlink, NULL)) != 0) 270 errc(1, rc, "pthread_create()"); 271 272 for (i = 0; i < 3; i++) { 273 if ((rc = pthread_join(tid[i], NULL)) != 0) 274 errc(1, rc, "pthread_join(%d)", i); 275 } 276 277 if ((rc = pthread_mutex_destroy(&newfiles.mtx)) != 0) 278 errc(1, rc, "pthread_mutex_destroy(newfiles)"); 279 if ((rc = pthread_cond_destroy(&newfiles.wait)) != 0) 280 errc(1, rc, "pthread_cond_destroy(newfiles)"); 281 if ((rc = pthread_mutex_destroy(&renamedfiles.mtx)) != 0) 282 errc(1, rc, "pthread_mutex_destroy(renamedfiles)"); 283 if ((rc = pthread_cond_destroy(&renamedfiles.wait)) != 0) 284 errc(1, rc, "pthread_cond_destroy(renamedfiles)"); 285 free(dirname1); 286 free(dirname2); 287 288 _exit(0); 289} 290 291int 292main(void) 293{ 294 int i; 295 296 alarm(1200); 297 for (i = 0; i < 1000; i++) { 298 if (fork() == 0) 299 test(); 300 wait(NULL); 301 } 302 303 return (0); 304} 305