From 18efd8d8b6ef4eb9b334c9f2d055edfc1f1a7227 Mon Sep 17 00:00:00 2001 From: cpickett Date: Tue, 30 Dec 2008 21:45:26 +0000 Subject: [PATCH] * support running tests with multiple pthreads - protect write in ppack() using a pthread mutex - use ACX_PTHREAD for portability - tests/check_thread_stress will test this for now - fix due to Daniel Gollub - closes 1391527 git-svn-id: svn+ssh://svn.code.sf.net/p/check/code/trunk@495 64e312b2-a51f-0410-8e61-82d0ca0eb02a --- AUTHORS | 1 + configure.ac | 3 ++ src/Makefile.am | 6 +-- src/check_pack.c | 17 ++++++ tests/Makefile.am | 5 ++ tests/check_thread_stress.c | 103 ++++++++++++++++++++++++++++++++++++ 6 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 tests/check_thread_stress.c diff --git a/AUTHORS b/AUTHORS index ab56c07..f9ca3ca 100644 --- a/AUTHORS +++ b/AUTHORS @@ -17,6 +17,7 @@ Patches: Bernhard Reiter (configure issues) Roland Stigge (bug fix: allow fail inside setup) Torok Edwin (strsignal and build fixes) Roland Illig (varargs and strsignal portability fixes) + Daniel Gollub (pthreads support) Anybody who has contributed code to Check or Check's build system is considered an author. Send patches to this file to diff --git a/configure.ac b/configure.ac index 1c18641..36c6fab 100644 --- a/configure.ac +++ b/configure.ac @@ -120,6 +120,9 @@ AC_FUNC_REALLOC AC_REPLACE_FUNCS([fileno localtime_r pipe putenv setenv sleep strdup strsignal unsetenv]) AC_CHECK_DECLS([fileno, localtime_r, pipe, putenv, setenv, sleep, strdup, strsignal, unsetenv]) +# Checks for pthread implementation. +ACX_PTHREAD([CC="$PTHREAD_CC"]) + # Output files AC_CONFIG_HEADERS([config.h]) diff --git a/src/Makefile.am b/src/Makefile.am index 7808238..da781be 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ include_HEADERS = check.h EXTRA_DIST = check.h.in -AM_CFLAGS = @GCOV_CFLAGS@ +AM_CFLAGS = @GCOV_CFLAGS@ @PTHREAD_CFLAGS@ CFILES =\ check.c \ @@ -39,11 +39,11 @@ $(EXPORT_SYM): check.h.in libcheck_la_DEPENDENCIES= $(EXPORT_SYM) libcheck_la_LDFLAGS = -no-undefined -export-symbols $(EXPORT_SYM) libcheck_la_SOURCES = $(CFILES) $(HFILES) -libcheck_la_LIBADD = @GCOV_LIBS@ $(top_builddir)/lib/libcompat.la +libcheck_la_LIBADD = @GCOV_LIBS@ @PTHREAD_LIBS@ $(top_builddir)/lib/libcompat.la libcheckinternal_la_LDFLAGS = -no-undefined libcheckinternal_la_SOURCES = $(CFILES) $(HFILES) -libcheckinternal_la_LIBADD = @GCOV_LIBS@ $(top_builddir)/lib/libcompat.la +libcheckinternal_la_LIBADD = @GCOV_LIBS@ @PTHREAD_LIBS@ $(top_builddir)/lib/libcompat.la CLEANFILES = *~ *.gcno $(EXPORT_SYM) diff --git a/src/check_pack.c b/src/check_pack.c index 2d3861c..d2fd757 100644 --- a/src/check_pack.c +++ b/src/check_pack.c @@ -33,12 +33,23 @@ #include #endif +#ifdef HAVE_PTHREAD +#include +#endif + #include "check.h" #include "check_error.h" #include "check_list.h" #include "check_impl.h" #include "check_pack.h" +#ifdef HAVE_PTHREAD +pthread_mutex_t lock_mutex = PTHREAD_MUTEX_INITIALIZER; +#else +#define pthread_mutex_lock(arg) +#define pthread_mutex_unlock(arg) +#endif + /* typedef an unsigned int that has at least 4 bytes */ typedef uint32_t ck_uint32; @@ -251,6 +262,10 @@ static void check_type (int type, const char *file, int line) eprintf ("Bad message type arg", file, line); } +#ifdef HAVE_PTHREAD +pthread_mutex_t mutex_lock = PTHREAD_MUTEX_INITIALIZER; +#endif + void ppack (int fdes, enum ck_msg_type type, CheckMsg *msg) { char *buf; @@ -258,7 +273,9 @@ void ppack (int fdes, enum ck_msg_type type, CheckMsg *msg) ssize_t r; n = pack (type, &buf, msg); + pthread_mutex_lock(&mutex_lock); r = write (fdes, buf, n); + pthread_mutex_unlock(&mutex_lock); if (r == -1) eprintf ("Error in call to write:", __FILE__, __LINE__ - 2); diff --git a/tests/Makefile.am b/tests/Makefile.am index 1f9c31c..304fea0 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -11,6 +11,7 @@ noinst_PROGRAMS = \ check_check_export \ check_check \ check_stress \ + check_thread_stress \ ex_output \ ex_xml_output \ ex_log_output @@ -48,6 +49,10 @@ check_check_LDADD = $(top_builddir)/src/libcheckinternal.la $(top_builddir)/lib/ check_stress_SOURCES = check_stress.c check_stress_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la +check_thread_stress_SOURCES = check_thread_stress.c +check_thread_stress_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la @PTHREAD_LIBS@ +check_thread_stress_CFLAGS = @PTHREAD_CFLAGS@ + ex_output_SOURCES = ex_output.c ex_output_LDADD = $(top_builddir)/src/libcheck.la $(top_builddir)/lib/libcompat.la diff --git a/tests/check_thread_stress.c b/tests/check_thread_stress.c new file mode 100644 index 0000000..28bc51b --- /dev/null +++ b/tests/check_thread_stress.c @@ -0,0 +1,103 @@ +#include +#include +#include +#include + +#ifdef HAVE_PTHREAD +#include +#endif + +Suite *s; +TCase *tc; +SRunner *sr; + +void *sendinfo_thread(void *userdata) +{ + unsigned int i; + for (i=0; i < 100; i++) { + fail_unless(1,"Shouldn't see this message"); + } + + return NULL; +} + + +void *sendinfo_fail_thread(void *userdata) +{ + unsigned int i; + for (i=0; i < 100; i++) { + fail("This test fails"); + } + + return NULL; +} + +START_TEST(test_pass) +{ +#ifdef HAVE_PTHREAD + pthread_t a, b; + pthread_create(&a, NULL, sendinfo_thread, (void *) 0xa); + pthread_create(&b, NULL, sendinfo_thread, (void *) 0xb); + + pthread_join(a, NULL); + pthread_join(b, NULL); +#else + sendinfo_thread(0xa); + sendinfo_thread(0xb); +#endif +} +END_TEST + +START_TEST(test_fail) +{ +#ifdef HAVE_PTHREAD + pthread_t a, b; + pthread_create(&a, NULL, sendinfo_fail_thread, (void *) 0xa); + pthread_create(&b, NULL, sendinfo_fail_thread, (void *) 0xb); + + pthread_join(a, NULL); + pthread_join(b, NULL); +#else + sendinfo_fail_thread(0xa); + sendinfo_fail_thread(0xb); +#endif +} +END_TEST + +static void run (int num_iters) +{ + int i; + s = suite_create ("Stress"); + tc = tcase_create ("Stress"); + sr = srunner_create (s); + suite_add_tcase(s, tc); + + for (i = 0; i < num_iters; i++) { + tcase_add_test (tc, test_pass); + tcase_add_test (tc, test_fail); + } + + srunner_run_all(sr, CK_SILENT); + if (srunner_ntests_failed (sr) != num_iters) { + printf ("Error: expected %d failures, got %d\n", + num_iters, srunner_ntests_failed(sr)); + return; + } + + srunner_free(sr); +} + + +int main(void) +{ + int i; + time_t t1; + int iters[] = {1, 100, 1000, -1}; + + for (i = 0; iters[i] != -1; i++) { + t1 = time(NULL); + run(iters[i]); + printf ("%d, %d\n", iters[i], (int) difftime(time(NULL), t1)); + } + return 0; +} -- 2.40.0