summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Guenthe <guenther@cvs.openbsd.org>2009-11-19 08:06:07 +0000
committerPhilip Guenthe <guenther@cvs.openbsd.org>2009-11-19 08:06:07 +0000
commit8b12ee1bb78ac0a27cbe0aa1285ad6c24a55095e (patch)
tree0cc36b3ca78a96095f17f206a7605922a381c238
parentdc4c19c59c4f534146b68f5578a7c2454b8ae98e (diff)
Add regression tests for stdio threading. Originally by blambert with
some further hacking by me
-rw-r--r--regress/lib/libc/Makefile3
-rw-r--r--regress/lib/libc/stdio_threading/Makefile3
-rw-r--r--regress/lib/libc/stdio_threading/fgetln/Makefile6
-rwxr-xr-xregress/lib/libc/stdio_threading/fgetln/fgetln_test.c70
-rw-r--r--regress/lib/libc/stdio_threading/fgets/Makefile6
-rwxr-xr-xregress/lib/libc/stdio_threading/fgets/fgets_test.c69
-rw-r--r--regress/lib/libc/stdio_threading/fopen/Makefile6
-rwxr-xr-xregress/lib/libc/stdio_threading/fopen/fopen_test.c48
-rw-r--r--regress/lib/libc/stdio_threading/fputs/Makefile6
-rwxr-xr-xregress/lib/libc/stdio_threading/fputs/fputs_test.c66
-rw-r--r--regress/lib/libc/stdio_threading/fread/Makefile6
-rwxr-xr-xregress/lib/libc/stdio_threading/fread/fread_test.c71
-rw-r--r--regress/lib/libc/stdio_threading/fwrite/Makefile6
-rwxr-xr-xregress/lib/libc/stdio_threading/fwrite/fwrite_test.c66
-rw-r--r--regress/lib/libc/stdio_threading/include/local.h80
15 files changed, 511 insertions, 1 deletions
diff --git a/regress/lib/libc/Makefile b/regress/lib/libc/Makefile
index cca83b0a868..b210b7df719 100644
--- a/regress/lib/libc/Makefile
+++ b/regress/lib/libc/Makefile
@@ -1,9 +1,10 @@
-# $OpenBSD: Makefile,v 1.28 2008/10/02 12:26:45 millert Exp $
+# $OpenBSD: Makefile,v 1.29 2009/11/19 08:06:06 guenther Exp $
SUBDIR+= _setjmp alloca atexit basename cxa-atexit db dirname fnmatch
SUBDIR+= fpclassify getaddrinfo getcap getopt_long glob hsearch longjmp
SUBDIR+= locale malloc netdb popen printf regex setjmp setjmp-signal
SUBDIR+= sigreturn sigsetjmp sprintf strerror strtod strtonum telldir time vis
+SUBDIR+= stdio_threading
.if (${MACHINE_ARCH} != "vax")
SUBDIR+= ieeefp
diff --git a/regress/lib/libc/stdio_threading/Makefile b/regress/lib/libc/stdio_threading/Makefile
new file mode 100644
index 00000000000..e42481afc2f
--- /dev/null
+++ b/regress/lib/libc/stdio_threading/Makefile
@@ -0,0 +1,3 @@
+SUBDIR += fopen fread fwrite fgetln fgets fputs
+
+.include <bsd.subdir.mk>
diff --git a/regress/lib/libc/stdio_threading/fgetln/Makefile b/regress/lib/libc/stdio_threading/fgetln/Makefile
new file mode 100644
index 00000000000..216db188ef0
--- /dev/null
+++ b/regress/lib/libc/stdio_threading/fgetln/Makefile
@@ -0,0 +1,6 @@
+TOPDIR=${.CURDIR}
+PROG=fgetln_test
+CFLAGS+=-I ${TOPDIR}/../include/
+LDFLAGS+=-lpthread
+
+.include <bsd.regress.mk>
diff --git a/regress/lib/libc/stdio_threading/fgetln/fgetln_test.c b/regress/lib/libc/stdio_threading/fgetln/fgetln_test.c
new file mode 100755
index 00000000000..d5c4db2edf5
--- /dev/null
+++ b/regress/lib/libc/stdio_threading/fgetln/fgetln_test.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2008 Bret S. Lambert <blambert@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "local.h"
+
+void
+fgetln_thread(void *v)
+{
+ FILE *file = v;
+ size_t len;
+ char *buf;
+ int i;
+
+ for (i = 0; i < 4096; i++) {
+ if ((buf = fgetln(file, &len)) == NULL) {
+
+ if (feof(file))
+ break;
+
+ printf("OMG!!!\n");
+ fflush(stdout);
+ break;
+ }
+ if (strncmp(buf, TEXT_N, sizeof(TEXT_N)))
+ err(1, "fgetln not atomic!!!");
+ }
+}
+
+int
+main(void)
+{
+ char sfn[24];
+ char buf[sizeof(TEXT_N)];
+ FILE *sfp;
+ int fd, i;
+
+ strlcpy(sfn, "/tmp/barnacles.XXXXXXXX", sizeof(sfn));
+ if ((fd = mkstemp(sfn)) == -1 ||
+ (sfp = fdopen(fd, "w+")) == NULL) {
+ if (fd != -1) {
+ unlink(sfn);
+ close(fd);
+ }
+ err(1, "could not open temporary file");
+ }
+
+ for (i = 0; i < 4096 * THREAD_COUNT; i++)
+ if (fwrite(TEXT_N, sizeof(char), strlen(TEXT_N), sfp) == 0)
+ err(1, "Could not populate test file");
+
+ run_threads(fgetln_thread, sfp);
+
+ unlink(sfn);
+ close(fd);
+
+ exit(0);
+}
diff --git a/regress/lib/libc/stdio_threading/fgets/Makefile b/regress/lib/libc/stdio_threading/fgets/Makefile
new file mode 100644
index 00000000000..dfd210cbf41
--- /dev/null
+++ b/regress/lib/libc/stdio_threading/fgets/Makefile
@@ -0,0 +1,6 @@
+TOPDIR=${.CURDIR}
+PROG=fgets_test
+CFLAGS+=-I ${TOPDIR}/../include/
+LDFLAGS+=-lpthread
+
+.include <bsd.regress.mk>
diff --git a/regress/lib/libc/stdio_threading/fgets/fgets_test.c b/regress/lib/libc/stdio_threading/fgets/fgets_test.c
new file mode 100755
index 00000000000..685d4c8257d
--- /dev/null
+++ b/regress/lib/libc/stdio_threading/fgets/fgets_test.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2008 Bret S. Lambert <blambert@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "local.h"
+
+void
+fgets_thread(void *v)
+{
+ char buf[sizeof(TEXT_N) + 1];
+ FILE *file = v;
+ int i;
+
+ for (i = 0; i < 4096; i++) {
+ if (fgets(buf, sizeof(buf), file) == NULL) {
+
+ if (feof(file))
+ break;
+
+ printf("OMG!!!\n");
+ fflush(stdout);
+ break;
+ }
+ if (strncmp(buf, TEXT, sizeof(TEXT)))
+ err(1, "Read not atomic!!!");
+ }
+}
+
+int
+main(void)
+{
+ char sfn[24];
+ char buf[sizeof(TEXT)];
+ FILE *sfp;
+ int fd, i;
+
+ strlcpy(sfn, "/tmp/barnacles.XXXXXXXX", sizeof(sfn));
+ if ((fd = mkstemp(sfn)) == -1 ||
+ (sfp = fdopen(fd, "w+")) == NULL) {
+ if (fd != -1) {
+ unlink(sfn);
+ close(fd);
+ }
+ err(1, "could not open temporary file");
+ }
+
+ for (i = 0; i < 4096 * THREAD_COUNT; i++)
+ if (fwrite(TEXT_N, sizeof(char), strlen(TEXT_N), sfp) == 0)
+ err(1, "Could not populate test file");
+
+ run_threads(fgets_thread, sfp);
+
+ unlink(sfn);
+ close(fd);
+
+ exit(0);
+}
diff --git a/regress/lib/libc/stdio_threading/fopen/Makefile b/regress/lib/libc/stdio_threading/fopen/Makefile
new file mode 100644
index 00000000000..4301a83978f
--- /dev/null
+++ b/regress/lib/libc/stdio_threading/fopen/Makefile
@@ -0,0 +1,6 @@
+TOPDIR=${.CURDIR}
+PROG=fopen_test
+CFLAGS+=-I ${TOPDIR}/../include/
+LDFLAGS+=-lpthread
+
+.include <bsd.regress.mk>
diff --git a/regress/lib/libc/stdio_threading/fopen/fopen_test.c b/regress/lib/libc/stdio_threading/fopen/fopen_test.c
new file mode 100755
index 00000000000..72359bb323f
--- /dev/null
+++ b/regress/lib/libc/stdio_threading/fopen/fopen_test.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2008 Bret S. Lambert <blambert@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <pthread.h>
+#include "local.h"
+
+int
+writefn(void *cookie, const char *buf, int size)
+{
+ return 0;
+}
+
+void
+fopen_thread(void *v)
+{
+ FILE *file;
+ int i;
+
+ for (i = 0; i < 4096; i++) {
+ file = fwopen(&i, writefn);
+ if (file != NULL) {
+ fputc('0', file);
+ pthread_yield();
+ fclose(file);
+ }
+ }
+}
+
+int
+main(void)
+{
+ run_threads(fopen_thread, NULL);
+ exit(0);
+}
diff --git a/regress/lib/libc/stdio_threading/fputs/Makefile b/regress/lib/libc/stdio_threading/fputs/Makefile
new file mode 100644
index 00000000000..5542dd3979d
--- /dev/null
+++ b/regress/lib/libc/stdio_threading/fputs/Makefile
@@ -0,0 +1,6 @@
+TOPDIR=${.CURDIR}
+PROG=fputs_test
+CFLAGS+=-I ${TOPDIR}/../include/
+LDFLAGS+=-lpthread
+
+.include <bsd.regress.mk>
diff --git a/regress/lib/libc/stdio_threading/fputs/fputs_test.c b/regress/lib/libc/stdio_threading/fputs/fputs_test.c
new file mode 100755
index 00000000000..c0a617510e9
--- /dev/null
+++ b/regress/lib/libc/stdio_threading/fputs/fputs_test.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2008 Bret S. Lambert <blambert@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "local.h"
+
+void
+fputs_thread(void *v)
+{
+ FILE *file = v;
+ int i;
+
+ for (i = 0; i < 4096; i++) {
+ if (fputs(TEXT, file) != 0) {
+
+ if (feof(file))
+ break;
+
+ printf("OMG!!!\n");
+ fflush(stdout);
+ break;
+ }
+ }
+}
+
+int
+main(void)
+{
+ char sfn[24];
+ char buf[sizeof(TEXT)];
+ FILE *sfp;
+ int fd, i;
+
+ strlcpy(sfn, "/tmp/barnacles.XXXXXXXX", sizeof(sfn));
+ if ((fd = mkstemp(sfn)) == -1 ||
+ (sfp = fdopen(fd, "w+")) == NULL) {
+ if (fd != -1) {
+ unlink(sfn);
+ close(fd);
+ }
+ err(1, "could not open temporary file");
+ }
+
+ run_threads(fputs_thread, sfp);
+
+ while (fgets(buf, sizeof(buf), sfp) != NULL) /* verify */
+ if (strcmp(buf, TEXT))
+ err(1, "Thread writes were not atomic!!!");
+
+ unlink(sfn);
+ close(fd);
+
+ exit(0);
+}
diff --git a/regress/lib/libc/stdio_threading/fread/Makefile b/regress/lib/libc/stdio_threading/fread/Makefile
new file mode 100644
index 00000000000..97c8816652e
--- /dev/null
+++ b/regress/lib/libc/stdio_threading/fread/Makefile
@@ -0,0 +1,6 @@
+TOPDIR=${.CURDIR}
+PROG=fread_test
+CFLAGS+=-I ${TOPDIR}/../include/
+LDFLAGS+=-lpthread
+
+.include <bsd.regress.mk>
diff --git a/regress/lib/libc/stdio_threading/fread/fread_test.c b/regress/lib/libc/stdio_threading/fread/fread_test.c
new file mode 100755
index 00000000000..b2372f5ab60
--- /dev/null
+++ b/regress/lib/libc/stdio_threading/fread/fread_test.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2008 Bret S. Lambert <blambert@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <pthread.h>
+#include "local.h"
+
+void
+fread_thread(void *v)
+{
+ char buf[sizeof(TEXT)];
+ FILE *file = v;
+ int i;
+
+ for (i = 0; i < 4096; i++) {
+ if (fread(buf, sizeof(char), strlen(TEXT), file) == 0) {
+
+ if (feof(file))
+ break;
+
+ printf("OMG!!!\n");
+ fflush(stdout);
+ break;
+ }
+ if (strncmp(buf, TEXT, sizeof(TEXT)))
+ err(1, "Read not atomic!!!");
+ }
+}
+
+int
+main(void)
+{
+ char sfn[24];
+ char buf[sizeof(TEXT)];
+ FILE *sfp;
+ int fd, i;
+
+ strlcpy(sfn, "/tmp/barnacles.XXXXXXXX", sizeof(sfn));
+ if ((fd = mkstemp(sfn)) == -1 ||
+ (sfp = fdopen(fd, "w+")) == NULL) {
+ if (fd != -1) {
+ unlink(sfn);
+ close(fd);
+ }
+ err(1, "could not open temporary file");
+ }
+
+ for (i = 0; i < 4096 * THREAD_COUNT; i++)
+ if (fwrite(TEXT, sizeof(char), strlen(TEXT), sfp) == 0)
+ err(1, "Could not populate test file");
+
+ run_threads(fread_thread, sfp);
+
+ unlink(sfn);
+ close(fd);
+
+ exit(0);
+}
diff --git a/regress/lib/libc/stdio_threading/fwrite/Makefile b/regress/lib/libc/stdio_threading/fwrite/Makefile
new file mode 100644
index 00000000000..5952a1f48a0
--- /dev/null
+++ b/regress/lib/libc/stdio_threading/fwrite/Makefile
@@ -0,0 +1,6 @@
+TOPDIR=${.CURDIR}
+PROG=fwrite_test
+CFLAGS+=-I ${TOPDIR}/../include/
+LDFLAGS+=-lpthread
+
+.include <bsd.regress.mk>
diff --git a/regress/lib/libc/stdio_threading/fwrite/fwrite_test.c b/regress/lib/libc/stdio_threading/fwrite/fwrite_test.c
new file mode 100755
index 00000000000..39bfb51ef0b
--- /dev/null
+++ b/regress/lib/libc/stdio_threading/fwrite/fwrite_test.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2008 Bret S. Lambert <blambert@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "local.h"
+
+void
+fwrite_thread(void *v)
+{
+ FILE *file = v;
+ int i;
+
+ for (i = 0; i < 4096; i++) {
+ if (fwrite(TEXT, sizeof(char), strlen(TEXT), file) == 0) {
+
+ if (feof(file))
+ break;
+
+ printf("OMG!!!\n");
+ fflush(stdout);
+ break;
+ }
+ }
+}
+
+int
+main(void)
+{
+ char sfn[24];
+ char buf[sizeof(TEXT)];
+ FILE *sfp;
+ int fd, i;
+
+ strlcpy(sfn, "/tmp/barnacles.XXXXXXXX", sizeof(sfn));
+ if ((fd = mkstemp(sfn)) == -1 ||
+ (sfp = fdopen(fd, "w+")) == NULL) {
+ if (fd != -1) {
+ unlink(sfn);
+ close(fd);
+ }
+ err(1, "could not open temporary file");
+ }
+
+ run_threads(fwrite_thread, sfp);
+
+ while (fread(buf, sizeof(char), strlen(TEXT), sfp)) /* verify */
+ if (strncmp(buf, TEXT, sizeof(TEXT)))
+ err(1, "Thread writes were not atomic!!!");
+
+ unlink(sfn);
+ close(fd);
+
+ exit(0);
+}
diff --git a/regress/lib/libc/stdio_threading/include/local.h b/regress/lib/libc/stdio_threading/include/local.h
new file mode 100644
index 00000000000..794d8680719
--- /dev/null
+++ b/regress/lib/libc/stdio_threading/include/local.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2008 Bret S. Lambert <blambert@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#define THREAD_COUNT 64
+
+#define TEXT "barnacles"
+#define TEXT_N "barnacles\n"
+
+void run_threads(void (*)(void *), void *);
+
+static pthread_rwlock_t start;
+static void (*real_func)(void *);
+
+static void *
+thread(void *arg)
+{
+ int r;
+
+ if ((r = pthread_rwlock_rdlock(&start)))
+ errx(1, "could not obtain lock in thread: %s", strerror(r));
+ real_func(arg);
+ if ((r = pthread_rwlock_unlock(&start)))
+ errx(1, "could not release lock in thread: %s", strerror(r));
+ return NULL;
+}
+
+void
+run_threads(void (*func)(void *), void *arg)
+{
+ pthread_t self, pthread[THREAD_COUNT];
+ int i, r;
+
+ self = pthread_self();
+ real_func = func;
+ if ((r = pthread_rwlock_init(&start, NULL)))
+ errx(1, "could not initialize lock: %s", strerror(r));
+
+ if ((r = pthread_rwlock_wrlock(&start))) /* block */
+ errx(1, "could not lock lock: %s", strerror(r));
+
+ for (i = 0; i < THREAD_COUNT; i++)
+ if ((r = pthread_create(&pthread[i], NULL, thread, arg))) {
+ warnx("could not create thread: %s", strerror(r));
+ pthread[i] = self;
+ }
+
+
+ if ((r = pthread_rwlock_unlock(&start))) /* unleash */
+ errx(1, "could not release lock: %s", strerror(r));
+
+ sleep(1);
+
+ if ((r = pthread_rwlock_wrlock(&start))) /* sync */
+ errx(1, "parent could not sync with children: %s",
+ strerror(r));
+
+ for (i = 0; i < THREAD_COUNT; i++)
+ if (! pthread_equal(pthread[i], self) &&
+ (r = pthread_join(pthread[i], NULL)))
+ warnx("could not join thread: %s", strerror(r));
+}
+