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