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