xref: /freebsd/tools/test/stress2/misc/pthread7.sh (revision fe75646a0234a261c0013bf1840fdac4acaf0cec)
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