On Wed, Jun 3, 2015 at 7:57 AM, Sebastian Huber <sebastian.hu...@embedded-brains.de> wrote: > The compiler is free to re-order load/store instructions to non-volatile > variables around a load/store of a volatile variable. So the volatile > generation counter is insufficent. In addition tests on a Freescale > T4240 platform with 24 PowerPC processors showed that real memory > barriers are required. Compiler memory barriers are not enough. > > For the test the timehand count was reduced to one with 10000 > tc_windup() calls per second. The timehand memory location was adjusted > so that the th_generation field was on its own cache line. > > Close #2356. > --- > cpukit/score/src/kern_tc.c | 115 > +++++++++++++-------- > testsuites/sptests/Makefile.am | 1 + > testsuites/sptests/configure.ac | 1 + > testsuites/sptests/sptimecounter03/Makefile.am | 19 ++++ > testsuites/sptests/sptimecounter03/init.c | 110 ++++++++++++++++++++ > .../sptests/sptimecounter03/sptimecounter03.doc | 11 ++ > .../sptests/sptimecounter03/sptimecounter03.scn | 2 + > 7 files changed, 216 insertions(+), 43 deletions(-) > create mode 100644 testsuites/sptests/sptimecounter03/Makefile.am > create mode 100644 testsuites/sptests/sptimecounter03/init.c > create mode 100644 testsuites/sptests/sptimecounter03/sptimecounter03.doc > create mode 100644 testsuites/sptests/sptimecounter03/sptimecounter03.scn > > diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c > index 5479927..6693fe8 100644 > --- a/cpukit/score/src/kern_tc.c > +++ b/cpukit/score/src/kern_tc.c > @@ -66,7 +66,8 @@ __FBSDID("$FreeBSD r277406 2015-01-20T03:54:30Z$"); > #include <sys/vdso.h> > #endif /* __rtems__ */ > #ifdef __rtems__ > -#include <rtems.h> > +#include <rtems/rtems/clock.h> > +#include <rtems/score/atomic.h> > ISR_LOCK_DEFINE(static, _Timecounter_Lock, "Timecounter"); > #define hz rtems_clock_get_ticks_per_second() > #define printf(...) > @@ -76,6 +77,16 @@ fls(int x) > { > return x ? sizeof(x) * 8 - __builtin_clz(x) : 0; > } > +static void Any good reason none of the functions suggest inline?
> +rmb(void) > +{ > + _Atomic_Fence(ATOMIC_ORDER_ACQUIRE); > +} > +static void > +wmb(void) > +{ > + _Atomic_Fence(ATOMIC_ORDER_RELEASE); > +} > /* FIXME: https://devel.rtems.org/ticket/2348 */ > #define ntp_update_second(a, b) do { (void) a; (void) b; } while (0) > #endif /* __rtems__ */ > @@ -120,7 +131,7 @@ struct timehands { > struct timeval th_microtime; > struct timespec th_nanotime; > /* Fields not to be copied in tc_windup start with th_generation. */ > - volatile uint32_t th_generation; > + uint32_t th_generation; > struct timehands *th_next; > }; > > @@ -252,6 +263,24 @@ tc_delta(struct timehands *th) > tc->tc_counter_mask); > } > > +static uint32_t > +tc_getgen(struct timehands *th) > +{ > + uint32_t gen; > + > + gen = th->th_generation; > + rmb(); > + return (gen); > +} > + > +static void > +tc_setgen(struct timehands *th, uint32_t newgen) > +{ > + > + wmb(); > + th->th_generation = newgen; > +} > + > /* > * Functions for reading the time. We have to loop until we are sure that > * the timehands that we operated on was not updated under our feet. See > @@ -267,10 +296,10 @@ fbclock_binuptime(struct bintime *bt) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > *bt = th->th_offset; > bintime_addx(bt, th->th_scale * tc_delta(th)); > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > } > > void > @@ -325,9 +354,9 @@ fbclock_getbinuptime(struct bintime *bt) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > *bt = th->th_offset; > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > } > > void > @@ -338,9 +367,9 @@ fbclock_getnanouptime(struct timespec *tsp) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > bintime2timespec(&th->th_offset, tsp); > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > } > > void > @@ -351,9 +380,9 @@ fbclock_getmicrouptime(struct timeval *tvp) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > bintime2timeval(&th->th_offset, tvp); > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > } > > void > @@ -364,9 +393,9 @@ fbclock_getbintime(struct bintime *bt) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > *bt = th->th_offset; > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > bintime_add(bt, &boottimebin); > } > > @@ -378,9 +407,9 @@ fbclock_getnanotime(struct timespec *tsp) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > *tsp = th->th_nanotime; > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > } > > void > @@ -391,9 +420,9 @@ fbclock_getmicrotime(struct timeval *tvp) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > *tvp = th->th_microtime; > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > } > #else /* !FFCLOCK */ > void > @@ -404,10 +433,10 @@ binuptime(struct bintime *bt) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > *bt = th->th_offset; > bintime_addx(bt, th->th_scale * tc_delta(th)); > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > } > > void > @@ -462,9 +491,9 @@ getbinuptime(struct bintime *bt) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > *bt = th->th_offset; > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > } > > void > @@ -475,9 +504,9 @@ getnanouptime(struct timespec *tsp) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > bintime2timespec(&th->th_offset, tsp); > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > } > > void > @@ -488,9 +517,9 @@ getmicrouptime(struct timeval *tvp) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > bintime2timeval(&th->th_offset, tvp); > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > } > > void > @@ -501,9 +530,9 @@ getbintime(struct bintime *bt) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > *bt = th->th_offset; > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > bintime_add(bt, &boottimebin); > } > > @@ -515,9 +544,9 @@ getnanotime(struct timespec *tsp) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > *tsp = th->th_nanotime; > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > } > > void > @@ -528,9 +557,9 @@ getmicrotime(struct timeval *tvp) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > *tvp = th->th_microtime; > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > } > #endif /* FFCLOCK */ > > @@ -943,11 +972,11 @@ ffclock_read_counter(ffcounter *ffcount) > */ > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > ffth = fftimehands; > delta = tc_delta(th); > *ffcount = ffth->tick_ffcount; > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > > *ffcount += delta; > } > @@ -1052,9 +1081,9 @@ dtrace_getnanotime(struct timespec *tsp) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > *tsp = th->th_nanotime; > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > } > #endif /* __rtems__ */ > > @@ -1096,7 +1125,7 @@ sysclock_getsnapshot(struct sysclock_snap *clock_snap, > int fast) > > do { > th = timehands; > - gen = th->th_generation; > + gen = tc_getgen(th); > fbi->th_scale = th->th_scale; > fbi->tick_time = th->th_offset; > #ifdef FFCLOCK > @@ -1110,7 +1139,7 @@ sysclock_getsnapshot(struct sysclock_snap *clock_snap, > int fast) > #endif > if (!fast) > delta = tc_delta(th); > - } while (gen == 0 || gen != th->th_generation); > + } while (gen == 0 || gen != tc_getgen(th)); > > clock_snap->delta = delta; > #ifdef FFCLOCK > @@ -1358,7 +1387,7 @@ tc_windup(void) > tho = timehands; > th = tho->th_next; > ogen = th->th_generation; > - th->th_generation = 0; > + tc_setgen(th, 0); > bcopy(tho, th, offsetof(struct timehands, th_generation)); > > /* > @@ -1479,7 +1508,7 @@ tc_windup(void) > */ > if (++ogen == 0) > ogen = 1; > - th->th_generation = ogen; > + tc_setgen(th, ogen); > > /* Go live with the new struct timehands. */ > #ifdef FFCLOCK > @@ -1727,13 +1756,13 @@ pps_capture(struct pps_state *pps) > > KASSERT(pps != NULL, ("NULL pps pointer in pps_capture")); > th = timehands; > - pps->capgen = th->th_generation; > + pps->capgen = tc_getgen(th); > pps->capth = th; > #ifdef FFCLOCK > pps->capffth = fftimehands; > #endif > pps->capcount = th->th_counter->tc_get_timecount(th->th_counter); > - if (pps->capgen != th->th_generation) > + if (pps->capgen != tc_getgen(th)) > pps->capgen = 0; > } > > @@ -1753,7 +1782,7 @@ pps_event(struct pps_state *pps, int event) > > KASSERT(pps != NULL, ("NULL pps pointer in pps_event")); > /* If the timecounter was wound up underneath us, bail out. */ > - if (pps->capgen == 0 || pps->capgen != pps->capth->th_generation) > + if (pps->capgen == 0 || pps->capgen != tc_getgen(pps->capth)) > return; > > /* Things would be easier with arrays. */ > @@ -1803,7 +1832,7 @@ pps_event(struct pps_state *pps, int event) > bintime2timespec(&bt, &ts); > > /* If the timecounter was wound up underneath us, bail out. */ > - if (pps->capgen != pps->capth->th_generation) > + if (pps->capgen != tc_getgen(pps->capth)) > return; > > *pcount = pps->capcount; > @@ -1921,7 +1950,7 @@ _Timecounter_Tick_simple(uint32_t delta, uint32_t > offset) > */ > if (++ogen == 0) > ogen = 1; > - th->th_generation = ogen; > + tc_setgen(th, ogen); > > /* Go live with the new struct timehands. */ > time_second = th->th_microtime.tv_sec; > diff --git a/testsuites/sptests/Makefile.am b/testsuites/sptests/Makefile.am > index c3fc443..948a8f0 100644 > --- a/testsuites/sptests/Makefile.am > +++ b/testsuites/sptests/Makefile.am > @@ -40,6 +40,7 @@ endif > _SUBDIRS += spintrcritical23 > _SUBDIRS += sptimecounter01 > _SUBDIRS += sptimecounter02 > +_SUBDIRS += sptimecounter03 > _SUBDIRS += spatomic01 > _SUBDIRS += spintrcritical22 > _SUBDIRS += spsem03 > diff --git a/testsuites/sptests/configure.ac b/testsuites/sptests/configure.ac > index b8287a4..a16ab3e 100644 > --- a/testsuites/sptests/configure.ac > +++ b/testsuites/sptests/configure.ac > @@ -43,6 +43,7 @@ AC_CONFIG_FILES([Makefile > spintrcritical23/Makefile > sptimecounter01/Makefile > sptimecounter02/Makefile > +sptimecounter03/Makefile > spatomic01/Makefile > spglobalcon01/Makefile > spintrcritical22/Makefile > diff --git a/testsuites/sptests/sptimecounter03/Makefile.am > b/testsuites/sptests/sptimecounter03/Makefile.am > new file mode 100644 > index 0000000..28209fa > --- /dev/null > +++ b/testsuites/sptests/sptimecounter03/Makefile.am > @@ -0,0 +1,19 @@ > +rtems_tests_PROGRAMS = sptimecounter03 > +sptimecounter03_SOURCES = init.c > + > +dist_rtems_tests_DATA = sptimecounter03.scn sptimecounter03.doc > + > +include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg > +include $(top_srcdir)/../automake/compile.am > +include $(top_srcdir)/../automake/leaf.am > + > +AM_CPPFLAGS += -I$(top_srcdir)/../support/include > + > +LINK_OBJS = $(sptimecounter03_OBJECTS) > +LINK_LIBS = $(sptimecounter03_LDLIBS) > + > +sptimecounter03$(EXEEXT): $(sptimecounter03_OBJECTS) > $(sptimecounter03_DEPENDENCIES) > + @rm -f sptimecounter03$(EXEEXT) > + $(make-exe) > + > +include $(top_srcdir)/../automake/local.am > diff --git a/testsuites/sptests/sptimecounter03/init.c > b/testsuites/sptests/sptimecounter03/init.c > new file mode 100644 > index 0000000..2595c7d > --- /dev/null > +++ b/testsuites/sptests/sptimecounter03/init.c > @@ -0,0 +1,110 @@ > +/* > + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. > + * > + * embedded brains GmbH > + * Dornierstr. 4 > + * 82178 Puchheim > + * Germany > + * <rt...@embedded-brains.de> > + * > + * The license and distribution terms for this file may be > + * found in the file LICENSE in this distribution or at > + * http://www.rtems.org/license/LICENSE. > + */ > + > +#ifdef HAVE_CONFIG_H > + #include "config.h" > +#endif > + > +#include <rtems/test.h> > + > +#include <rtems/bsd.h> > + > +#include <test_support.h> > + > +#include "tmacros.h" > + > +const char rtems_test_name[] = "SPTIMECOUNTER 3"; > + > +#define CPU_COUNT 32 > + > +static rtems_test_parallel_context ctx;; > + > +static rtems_interval test_binuptime_init( > + rtems_test_parallel_context *ctx, > + void *arg, > + size_t active_workers > +) > +{ > + return 10 * rtems_clock_get_ticks_per_second(); > +} > + > +static void test_binuptime_body( > + rtems_test_parallel_context *ctx, > + void *arg, > + size_t active_workers, > + size_t worker_index > +) > +{ > + struct bintime start; > + struct bintime end; > + > + rtems_bsd_binuptime(&start); > + > + do { > + rtems_bsd_binuptime(&end); > + rtems_test_assert( > + end.sec > start.sec > + || (end.sec == start.sec && end.frac >= start.frac) > + ); > + start = end; > + } while (!rtems_test_parallel_stop_job(ctx)); > +} > + > +static void test_binuptime_fini( > + rtems_test_parallel_context *ctx, > + void *arg, > + size_t active_workers > +) > +{ > + /* Nothing to do */ > +} > + > +static const rtems_test_parallel_job jobs[] = { > + { > + .init = test_binuptime_init, > + .body = test_binuptime_body, > + .fini = test_binuptime_fini, > + .cascade = false > + } > +}; > + > +static void Init(rtems_task_argument arg) > +{ > + TEST_BEGIN(); > + > + rtems_test_parallel(&ctx, NULL, &jobs[0], RTEMS_ARRAY_SIZE(jobs)); > + > + TEST_END(); > + rtems_test_exit(0); > +} > + > +#define CONFIGURE_MICROSECONDS_PER_TICK 1000 > + > +#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER > +#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER > + > +#define CONFIGURE_MAXIMUM_TASKS CPU_COUNT > +#define CONFIGURE_MAXIMUM_TIMERS 1 > + > +#define CONFIGURE_SMP_APPLICATION > + > +#define CONFIGURE_SMP_MAXIMUM_PROCESSORS CPU_COUNT > + > +#define CONFIGURE_RTEMS_INIT_TASKS_TABLE > + > +#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION > + > +#define CONFIGURE_INIT > + > +#include <rtems/confdefs.h> > diff --git a/testsuites/sptests/sptimecounter03/sptimecounter03.doc > b/testsuites/sptests/sptimecounter03/sptimecounter03.doc > new file mode 100644 > index 0000000..f978e56 > --- /dev/null > +++ b/testsuites/sptests/sptimecounter03/sptimecounter03.doc > @@ -0,0 +1,11 @@ > +This file describes the directives and concepts tested by this test set. > + > +test set name: sptimecounter03 > + > +directives: > + > + - rtems_bsd_binuptime > + > +concepts: > + > + - Ensure that the binuptime is monotonic within a certain time frame. > diff --git a/testsuites/sptests/sptimecounter03/sptimecounter03.scn > b/testsuites/sptests/sptimecounter03/sptimecounter03.scn > new file mode 100644 > index 0000000..fb249e5 > --- /dev/null > +++ b/testsuites/sptests/sptimecounter03/sptimecounter03.scn > @@ -0,0 +1,2 @@ > +*** BEGIN OF TEST SPTIMECOUNTER 3 *** > +*** END OF TEST SPTIMECOUNTER 3 *** > -- > 1.8.4.5 > > _______________________________________________ > devel mailing list > devel@rtems.org > http://lists.rtems.org/mailman/listinfo/devel _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel