>From 19fb8b2915e5d918a6c1e98f265ab89bd373fea7 Mon Sep 17 00:00:00 2001 From: Akira Yokosawa <akiyks@xxxxxxxxx> Date: Sat, 6 Oct 2018 23:47:44 +0900 Subject: [PATCH 3/5] count: Tweak counttorture.h to avoid segfault As has been mentioned in comment to count_read(), count_tstat sometimes fails. The cause is the use of count_read() in counttorture.h after wait_all_threads() returns. Because __thread variables are freed when owning threads exit, count_read() would access nonexistent variables. As a workaround, add #ifndef KEEP_GCC_THREAD_LOCAL in counttorture.h and define _wait_all_thread(), _count_unregister_thread(), and final_wait_all_thread() as macros which change behavior when KEEP_GCC_THREAD_LOCAL is defined. They permit counttorture's controlling thread to participate in the thread group to be kept alive. Signed-off-by: Akira Yokosawa <akiyks@xxxxxxxxx> --- CodeSamples/count/count_tstat.c | 3 ++- CodeSamples/count/counttorture.h | 21 ++++++++++++++++++--- count/count.tex | 4 ++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/CodeSamples/count/count_tstat.c b/CodeSamples/count/count_tstat.c index 4b99415..d30ee48 100644 --- a/CodeSamples/count/count_tstat.c +++ b/CodeSamples/count/count_tstat.c @@ -34,7 +34,7 @@ static __inline__ void inc_count(void) } static __inline__ unsigned long read_count(void) - /* known failure with counttorture! */ + /* need to tweak counttorture! */ { int t; unsigned long sum = 0; @@ -69,4 +69,5 @@ void count_cleanup(void) } #define NEED_REGISTER_THREAD +#define KEEP_GCC_THREAD_LOCAL #include "counttorture.h" diff --git a/CodeSamples/count/counttorture.h b/CodeSamples/count/counttorture.h index bdfc7d4..60d1d11 100644 --- a/CodeSamples/count/counttorture.h +++ b/CodeSamples/count/counttorture.h @@ -64,6 +64,20 @@ int goflag __attribute__((__aligned__(CACHE_LINE_SIZE))) = GOFLAG_INIT; #define count_unregister_thread(n) do ; while (0) #endif /* #ifndef NEED_REGISTER_THREAD */ +#ifndef KEEP_GCC_THREAD_LOCAL +#define _wait_all_threads() wait_all_threads() +#define _count_unregister_thread(n) count_unregister_thread(n) +#define final_wait_all_threads() +#else /* #ifndef KEEP_GCC_THREAD_LOCAL */ +#define _wait_all_threads() { \ + while (READ_ONCE(finalthreadcount) < nthreadsexpected) \ + poll(NULL, 0, 1);} +#define _count_unregister_thread(n) count_unregister_thread(n + 1) +#define final_wait_all_threads() { \ + WRITE_ONCE(finalthreadcount, nthreadsexpected + 1); \ + wait_all_threads();} +#endif /* #ifndef KEEP_GCC_THREAD_LOCAL */ + unsigned long garbage = 0; /* disable compiler optimizations. */ /* @@ -90,7 +104,7 @@ void *count_read_perf_test(void *arg) n_reads_local += COUNT_READ_RUN; } __get_thread_var(n_reads_pt) += n_reads_local; - count_unregister_thread(nthreadsexpected); + _count_unregister_thread(nthreadsexpected); garbage += j; return (NULL); @@ -113,7 +127,7 @@ void *count_update_perf_test(void *arg) n_updates_local += COUNT_UPDATE_RUN; } __get_thread_var(n_updates_pt) += n_updates_local; - count_unregister_thread(nthreadsexpected); + _count_unregister_thread(nthreadsexpected); return NULL; } @@ -139,7 +153,7 @@ void perftestrun(int nthreads, int nreaders, int nupdaters) smp_mb(); goflag = GOFLAG_STOP; smp_mb(); - wait_all_threads(); + _wait_all_threads(); count_cleanup(); for_each_thread(t) { n_reads += per_thread(n_reads_pt, t); @@ -159,6 +173,7 @@ void perftestrun(int nthreads, int nreaders, int nupdaters) (double)n_reads), ((duration * 1000*1000.*(double)nupdaters) / (double)n_updates)); + final_wait_all_threads(); exit(EXIT_SUCCESS); } diff --git a/count/count.tex b/count/count.tex index a4e9c7f..b008a19 100644 --- a/count/count.tex +++ b/count/count.tex @@ -1127,9 +1127,9 @@ variables vanish when that thread exits. Listing~\ref{lst:count:Per-Thread Statistical Counters With Lockless Summation} (\path{count_tstat.c}). Analysis of this code is left as an exercise to the reader, - however, please note that it does not fit well into the + however, please note that it requires tweaks in the \path{counttorture.h} counter-evaluation scheme. - (Why not?) + (Hint: See \co{#ifndef KEEP_GCC_THREAD_LOCAL}.) Chapter~\ref{chp:Deferred Processing} will introduce synchronization mechanisms that handle this situation in a much more graceful manner. -- 2.7.4