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