From 3bf8c221bc859ae3254fe6b11fb60750f0bae04e Mon Sep 17 00:00:00 2001 From: guenther <> Date: Thu, 19 Nov 2009 08:06:06 +0000 Subject: Add regression tests for stdio threading. Originally by blambert with some further hacking by me --- src/regress/lib/libc/Makefile | 3 +- src/regress/lib/libc/stdio_threading/Makefile | 3 + .../lib/libc/stdio_threading/fgetln/Makefile | 6 ++ .../lib/libc/stdio_threading/fgetln/fgetln_test.c | 70 +++++++++++++++++++ .../lib/libc/stdio_threading/fgets/Makefile | 6 ++ .../lib/libc/stdio_threading/fgets/fgets_test.c | 69 +++++++++++++++++++ .../lib/libc/stdio_threading/fopen/Makefile | 6 ++ .../lib/libc/stdio_threading/fopen/fopen_test.c | 48 +++++++++++++ .../lib/libc/stdio_threading/fputs/Makefile | 6 ++ .../lib/libc/stdio_threading/fputs/fputs_test.c | 66 ++++++++++++++++++ .../lib/libc/stdio_threading/fread/Makefile | 6 ++ .../lib/libc/stdio_threading/fread/fread_test.c | 71 +++++++++++++++++++ .../lib/libc/stdio_threading/fwrite/Makefile | 6 ++ .../lib/libc/stdio_threading/fwrite/fwrite_test.c | 66 ++++++++++++++++++ .../lib/libc/stdio_threading/include/local.h | 80 ++++++++++++++++++++++ 15 files changed, 511 insertions(+), 1 deletion(-) create mode 100644 src/regress/lib/libc/stdio_threading/Makefile create mode 100644 src/regress/lib/libc/stdio_threading/fgetln/Makefile create mode 100755 src/regress/lib/libc/stdio_threading/fgetln/fgetln_test.c create mode 100644 src/regress/lib/libc/stdio_threading/fgets/Makefile create mode 100755 src/regress/lib/libc/stdio_threading/fgets/fgets_test.c create mode 100644 src/regress/lib/libc/stdio_threading/fopen/Makefile create mode 100755 src/regress/lib/libc/stdio_threading/fopen/fopen_test.c create mode 100644 src/regress/lib/libc/stdio_threading/fputs/Makefile create mode 100755 src/regress/lib/libc/stdio_threading/fputs/fputs_test.c create mode 100644 src/regress/lib/libc/stdio_threading/fread/Makefile create mode 100755 src/regress/lib/libc/stdio_threading/fread/fread_test.c create mode 100644 src/regress/lib/libc/stdio_threading/fwrite/Makefile create mode 100755 src/regress/lib/libc/stdio_threading/fwrite/fwrite_test.c create mode 100644 src/regress/lib/libc/stdio_threading/include/local.h (limited to 'src') diff --git a/src/regress/lib/libc/Makefile b/src/regress/lib/libc/Makefile index cca83b0a86..b210b7df71 100644 --- a/src/regress/lib/libc/Makefile +++ b/src/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/src/regress/lib/libc/stdio_threading/Makefile b/src/regress/lib/libc/stdio_threading/Makefile new file mode 100644 index 0000000000..e42481afc2 --- /dev/null +++ b/src/regress/lib/libc/stdio_threading/Makefile @@ -0,0 +1,3 @@ +SUBDIR += fopen fread fwrite fgetln fgets fputs + +.include diff --git a/src/regress/lib/libc/stdio_threading/fgetln/Makefile b/src/regress/lib/libc/stdio_threading/fgetln/Makefile new file mode 100644 index 0000000000..216db188ef --- /dev/null +++ b/src/regress/lib/libc/stdio_threading/fgetln/Makefile @@ -0,0 +1,6 @@ +TOPDIR=${.CURDIR} +PROG=fgetln_test +CFLAGS+=-I ${TOPDIR}/../include/ +LDFLAGS+=-lpthread + +.include diff --git a/src/regress/lib/libc/stdio_threading/fgetln/fgetln_test.c b/src/regress/lib/libc/stdio_threading/fgetln/fgetln_test.c new file mode 100755 index 0000000000..d5c4db2edf --- /dev/null +++ b/src/regress/lib/libc/stdio_threading/fgetln/fgetln_test.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2008 Bret S. Lambert + * + * 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/src/regress/lib/libc/stdio_threading/fgets/Makefile b/src/regress/lib/libc/stdio_threading/fgets/Makefile new file mode 100644 index 0000000000..dfd210cbf4 --- /dev/null +++ b/src/regress/lib/libc/stdio_threading/fgets/Makefile @@ -0,0 +1,6 @@ +TOPDIR=${.CURDIR} +PROG=fgets_test +CFLAGS+=-I ${TOPDIR}/../include/ +LDFLAGS+=-lpthread + +.include diff --git a/src/regress/lib/libc/stdio_threading/fgets/fgets_test.c b/src/regress/lib/libc/stdio_threading/fgets/fgets_test.c new file mode 100755 index 0000000000..685d4c8257 --- /dev/null +++ b/src/regress/lib/libc/stdio_threading/fgets/fgets_test.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2008 Bret S. Lambert + * + * 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/src/regress/lib/libc/stdio_threading/fopen/Makefile b/src/regress/lib/libc/stdio_threading/fopen/Makefile new file mode 100644 index 0000000000..4301a83978 --- /dev/null +++ b/src/regress/lib/libc/stdio_threading/fopen/Makefile @@ -0,0 +1,6 @@ +TOPDIR=${.CURDIR} +PROG=fopen_test +CFLAGS+=-I ${TOPDIR}/../include/ +LDFLAGS+=-lpthread + +.include diff --git a/src/regress/lib/libc/stdio_threading/fopen/fopen_test.c b/src/regress/lib/libc/stdio_threading/fopen/fopen_test.c new file mode 100755 index 0000000000..72359bb323 --- /dev/null +++ b/src/regress/lib/libc/stdio_threading/fopen/fopen_test.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2008 Bret S. Lambert + * + * 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 +#include +#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/src/regress/lib/libc/stdio_threading/fputs/Makefile b/src/regress/lib/libc/stdio_threading/fputs/Makefile new file mode 100644 index 0000000000..5542dd3979 --- /dev/null +++ b/src/regress/lib/libc/stdio_threading/fputs/Makefile @@ -0,0 +1,6 @@ +TOPDIR=${.CURDIR} +PROG=fputs_test +CFLAGS+=-I ${TOPDIR}/../include/ +LDFLAGS+=-lpthread + +.include diff --git a/src/regress/lib/libc/stdio_threading/fputs/fputs_test.c b/src/regress/lib/libc/stdio_threading/fputs/fputs_test.c new file mode 100755 index 0000000000..c0a617510e --- /dev/null +++ b/src/regress/lib/libc/stdio_threading/fputs/fputs_test.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2008 Bret S. Lambert + * + * 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/src/regress/lib/libc/stdio_threading/fread/Makefile b/src/regress/lib/libc/stdio_threading/fread/Makefile new file mode 100644 index 0000000000..97c8816652 --- /dev/null +++ b/src/regress/lib/libc/stdio_threading/fread/Makefile @@ -0,0 +1,6 @@ +TOPDIR=${.CURDIR} +PROG=fread_test +CFLAGS+=-I ${TOPDIR}/../include/ +LDFLAGS+=-lpthread + +.include diff --git a/src/regress/lib/libc/stdio_threading/fread/fread_test.c b/src/regress/lib/libc/stdio_threading/fread/fread_test.c new file mode 100755 index 0000000000..b2372f5ab6 --- /dev/null +++ b/src/regress/lib/libc/stdio_threading/fread/fread_test.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2008 Bret S. Lambert + * + * 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 +#include +#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/src/regress/lib/libc/stdio_threading/fwrite/Makefile b/src/regress/lib/libc/stdio_threading/fwrite/Makefile new file mode 100644 index 0000000000..5952a1f48a --- /dev/null +++ b/src/regress/lib/libc/stdio_threading/fwrite/Makefile @@ -0,0 +1,6 @@ +TOPDIR=${.CURDIR} +PROG=fwrite_test +CFLAGS+=-I ${TOPDIR}/../include/ +LDFLAGS+=-lpthread + +.include diff --git a/src/regress/lib/libc/stdio_threading/fwrite/fwrite_test.c b/src/regress/lib/libc/stdio_threading/fwrite/fwrite_test.c new file mode 100755 index 0000000000..39bfb51ef0 --- /dev/null +++ b/src/regress/lib/libc/stdio_threading/fwrite/fwrite_test.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2008 Bret S. Lambert + * + * 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/src/regress/lib/libc/stdio_threading/include/local.h b/src/regress/lib/libc/stdio_threading/include/local.h new file mode 100644 index 0000000000..794d868071 --- /dev/null +++ b/src/regress/lib/libc/stdio_threading/include/local.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2008 Bret S. Lambert + * + * 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 +#include +#include +#include + +#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)); +} + -- cgit v1.2.3-55-g6feb