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# "panic: pmap active 0xfffff80128cd84b8" seen: 30# http://people.freebsd.org/~pho/stress/log/attilio101.txt 31 32. ../default.cfg 33 34here=`pwd` 35cd /tmp 36sed '1,/^EOF/d' < $here/$0 > pthread6.c 37mycc -o pthread6 -Wall -Wextra -O2 -g -gdwarf-2 pthread6.c -lpthread || exit 1 38rm -f pthread6.c /tmp/pthread6.core 39 40daemon sh -c "(cd $here/../testcases/swap; ./swap -t 2m -i 20 -k)" 41sleep `jot -r 1 1 9` 42echo "Expect SIGABRT" 43for i in `jot 50`; do 44 /tmp/pthread6 45done 46while pgrep -q swap; do 47 pkill swap 48 sleep 1 49done 50 51rm -f /tmp/pthread6 /tmp/pthread6.core 52exit 0 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 <sys/wait.h> 78#include <time.h> 79#include <unistd.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 86#define PARALLEL 4 87#define LOOPS 2 88 89long ncreate, nrename, nunlink; 90int bench, max; 91char *dirname1; 92char *dirname2; 93 94struct file { 95 char *name; 96 STAILQ_ENTRY(file) next; 97}; 98 99struct files { 100 pthread_mutex_t mtx; 101 pthread_cond_t wait; 102 STAILQ_HEAD(, file) list; 103}; 104 105static struct files newfiles; 106static struct files renamedfiles; 107 108static void 109hand(int i __unused) { /* handler */ 110} 111 112static void 113ahand(int i __unused) { /* handler */ 114 abort(); 115} 116 117void 118plock(pthread_mutex_t *l) 119{ 120 int rc; 121 122 if ((rc = pthread_mutex_lock(l)) != 0) 123 errc(1, rc, "pthread_mutex_lock"); 124} 125 126void 127punlock(pthread_mutex_t *l) 128{ 129 int rc; 130 131 if ((rc = pthread_mutex_unlock(l)) != 0) 132 errc(1, rc, "pthread_mutex_unlock"); 133} 134 135void 136psig(pthread_cond_t *c) 137{ 138 int rc; 139 140 if ((rc = pthread_cond_signal(c)) != 0) 141 errc(1, rc, "pthread_cond_signal"); 142} 143 144void 145pwait(pthread_cond_t *c, pthread_mutex_t *l) 146{ 147 int rc; 148 149 if ((rc = pthread_cond_wait(c, l)) != 0) 150 errc(1, rc, "pthread_cond_wait"); 151} 152 153void * 154loop_create(void *arg __unused) 155{ 156 int i, j; 157 struct file *file; 158 159#ifdef __NP__ 160 pthread_set_name_np(pthread_self(), __func__); 161#endif 162 163 for (i = 0; i < max; i++) { 164 file = malloc(sizeof(*file)); 165 asprintf(&file->name, "%s/filename_too-long:%d", dirname1, i); 166 LOCK(newfiles); 167 STAILQ_INSERT_TAIL(&newfiles.list, file, next); 168 ncreate++; 169 UNLOCK(newfiles); 170 SIGNAL(newfiles); 171 if ((bench == 0) && (i > 0) && (i % 100000 == 0)) 172 for (j = 0; j < 10 && ncreate != nrename; j++) 173 usleep(400); 174 } 175 return (NULL); 176} 177 178void * 179loop_rename(void *arg __unused) 180{ 181 char *filename, *newname; 182 struct file *file; 183 184#ifdef __NP__ 185 pthread_set_name_np(pthread_self(), __func__); 186#endif 187 188 while (nrename < max) { 189 LOCK(newfiles); 190 while (STAILQ_EMPTY(&newfiles.list)) { 191 WAIT(newfiles); 192 } 193 file = STAILQ_FIRST(&newfiles.list); 194 STAILQ_REMOVE_HEAD(&newfiles.list, next); 195 UNLOCK(newfiles); 196 filename = strrchr(file->name, '/'); 197 asprintf(&newname, "%s/%s", dirname2, filename); 198 nrename++; 199 free(file->name); 200 file->name = newname; 201 LOCK(renamedfiles); 202 STAILQ_INSERT_TAIL(&renamedfiles.list, file, next); 203 UNLOCK(renamedfiles); 204 SIGNAL(renamedfiles); 205 } 206 return (NULL); 207} 208 209void * 210loop_unlink(void *arg __unused) 211{ 212 struct file *file; 213 214#ifdef __NP__ 215 pthread_set_name_np(pthread_self(), __func__); 216#endif 217 218 while (nunlink < max) { 219 LOCK(renamedfiles); 220 while (STAILQ_EMPTY(&renamedfiles.list)) { 221 WAIT(renamedfiles); 222 } 223 file = STAILQ_FIRST(&renamedfiles.list); 224 STAILQ_REMOVE_HEAD(&renamedfiles.list, next); 225 nunlink++; 226 UNLOCK(renamedfiles); 227 free(file->name); 228 free(file); 229 } 230 return (NULL); 231} 232 233void 234test(void) 235{ 236 int i; 237 int rc; 238 pthread_t tid[3]; 239 pthread_mutexattr_t attr, *pattr = NULL; 240 241 bench = getenv("bench") != NULL; 242 bench = 1; 243 asprintf(&dirname1, "%s.1", "f1"); 244 asprintf(&dirname2, "%s.2", "f2"); 245 max = 15000000; 246 247 STAILQ_INIT(&newfiles.list); 248 STAILQ_INIT(&renamedfiles.list); 249 250 pthread_mutexattr_init (&attr); 251 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); 252 pattr = &attr; 253 if ((rc = pthread_mutex_init(&newfiles.mtx, pattr)) != 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 if ((rc = pthread_create(&tid[0], NULL, loop_create, NULL)) != 0) 265 errc(1, rc, "pthread_create()"); 266 if ((rc = pthread_create(&tid[1], NULL, loop_rename, NULL)) != 0) 267 errc(1, rc, "pthread_create()"); 268 if ((rc = pthread_create(&tid[2], NULL, loop_unlink, NULL)) != 0) 269 errc(1, rc, "pthread_create()"); 270 271 usleep(1000); 272 ualarm(arc4random() % 100000, 0); 273 for (i = 0; i < 3; i++) { 274 if ((rc = pthread_join(tid[i], NULL)) != 0) 275 errc(1, rc, "pthread_join(%d)", i); 276 } 277 278 if ((rc = pthread_mutex_destroy(&newfiles.mtx)) != 0) 279 errc(1, rc, "pthread_mutex_destroy(newfiles)"); 280 if ((rc = pthread_cond_destroy(&newfiles.wait)) != 0) 281 errc(1, rc, "pthread_cond_destroy(newfiles)"); 282 if ((rc = pthread_mutex_destroy(&renamedfiles.mtx)) != 0) 283 errc(1, rc, "pthread_mutex_destroy(renamedfiles)"); 284 if ((rc = pthread_cond_destroy(&renamedfiles.wait)) != 0) 285 errc(1, rc, "pthread_cond_destroy(renamedfiles)"); 286 free(dirname1); 287 free(dirname2); 288 289 _exit(0); 290} 291 292int 293main(void) 294{ 295 int i, j; 296 297 for (i = 0; i < LOOPS; i++) { 298 for (j = 0; j < PARALLEL; j++) { 299 if (fork() == 0) 300 test(); 301 } 302 303 for (j = 0; j < PARALLEL; j++) 304 wait(NULL); 305 } 306 307 return (0); 308} 309