diff --git a/sys/kern/kern_ffclock.c b/sys/kern/kern_ffclock.c --- a/sys/kern/kern_ffclock.c +++ b/sys/kern/kern_ffclock.c @@ -61,8 +61,11 @@ * various flavours of absolute time (e.g. with or without leap seconds taken * into account). If valid pointers are provided, the ffcounter value and an * upper bound on clock error associated with the bintime are provided. - * NOTE: use ffclock_convert_abs() to differ the conversion of a ffcounter value - * read earlier. + * The DIFF and MONO flags determining FFclock type are processed within + * ffclock_last_tick and ffclock_read_counter. + * Note that here ffclock_convert_abs() is used to read the FFclock `now', but + * the resulting timestamp corresponds to the event timestamped by the raw + * ffcounter read made earlier - this is a feature! */ void ffclock_abstime(ffcounter *ffcount, struct bintime *bt, diff --git a/sys/kern/kern_tc.c b/sys/kern/kern_tc.c --- a/sys/kern/kern_tc.c +++ b/sys/kern/kern_tc.c @@ -508,9 +508,10 @@ * avoid duplication of hardware access and tc-tick processing overheads. * However the FFclock code does not alter or interfere with FBclock operation. * - * Two forms of the FFclock are supported : + * Three forms of the FFclock are supported : * native [natFFC]: kernel version of the userland FF daemon's clock. * monotonic [monoFFC]: monotonic version of natFFC (resets aside). + * difference [diffFFC]: non-jumping for use as a difference-clock * Each of these clocks correspond to UTC at the time that the FFclock * daemon is started. Leap seconds subsequent to that time are added in * separately. @@ -527,6 +528,7 @@ struct ffclock_estimate cest; /* natFFC data */ struct bintime tick_time; /* natFFC */ struct bintime tick_time_mono; /* monoFFC */ + struct bintime tick_time_diff; /* diffFFC */ struct bintime tick_error; ffcounter tick_ffcount; uint64_t period_mono; @@ -626,11 +628,12 @@ /* * Update the fftimehands. The updated tick state is based on the previous tick. * If there has been no actionable update in the FFclock parameters during the - * current tick (ffclock_updated <= 0), then each of the natFFC and monoFFC - * clocks advance linearly. Otherwise it is based off the updated + * current tick (ffclock_updated <= 0), then each of the natFFC, monoFFC, and + * diffFFC clocks advance linearly. Otherwise it is based off the updated * parameters at the time of the update. The native FFclock natFFC will then - * jump, monoFFC will not (except under special conditions). - * The linear interpolation parameters of + * jump, monoFFC will not (except under special conditions). The diffFFC + * will never jump, to ensure its intended use as a difference clock, + * used to measure time differences. The linear interpolation parameters of * monoFFC ({tick_time,period}_mono) are recomputed for the new tick. * * The instant defining the start of the new tick is the delta=tc_delta call @@ -663,15 +666,17 @@ */ if (ffclock_updated <= 0) { - /* Update natFFC members {cest, tick_time, tick_error} */ + /* Update natFFC members {cest, tick_time{_diff}, tick_error} */ memcpy(cest, &fftimehands->cest,sizeof(struct ffclock_estimate)); - ffth->tick_time = fftimehands->tick_time; + ffth->tick_time = fftimehands->tick_time; + ffth->tick_time_diff = fftimehands->tick_time_diff; ffclock_convert_delta(ffdelta, cest->period, &bt); bintime_add(&ffth->tick_time, &bt); + bintime_add(&ffth->tick_time_diff, &bt); bintime_mul(&bt, cest->errb_rate * PS_AS_BINFRAC); bintime_add(&ffth->tick_error, &bt); - /* Update monoFFC members {period_mono, tick_time_mono} */ + /* Update monoFFC members {period_mono, tick_time_mono}. */ ffth->period_mono = fftimehands->period_mono; ffth->tick_time_mono = fftimehands->tick_time_mono; ffclock_convert_delta(ffdelta, ffth->period_mono, &bt); @@ -696,7 +701,7 @@ */ if (ffclock_updated > 0) { - /* Update natFFC members {cest, tick_time, tick_error} */ + /* Update natFFC members {cest, tick_time, tick_error}. */ memcpy(cest, &ffclock_estimate,sizeof(struct ffclock_estimate)); ffdelta = ffth->tick_ffcount - cest->update_ffcount; ffth->tick_time = cest->update_time; @@ -706,6 +711,14 @@ bintime_addx(&bt, cest->errb_abs * NS_AS_BINFRAC); ffth->tick_error = bt; + /* + * Update diffFFC clock member {tick_time_diff}, ensuring + * continuity over ticks. + */ + ffth->tick_time_diff = fftimehands->tick_time_diff; + ffclock_convert_delta((ffcounter)delta, cest->period, &bt); + bintime_add(&ffth->tick_time_diff, &bt); + /* * Update monoFFC member tick_time_mono, standard case. * ffclock_updated by ffclock_setto_rtc : re-initialize @@ -726,7 +739,7 @@ else forward_jump = 0; - /* Record magnitude of jump */ + /* Record magnitude of jump. */ bintime_clear(&gap); if (forward_jump) { // monoFFC < natFFC gap = ffth->tick_time; @@ -870,8 +883,9 @@ cest->status |= FFCLOCK_STA_UNSYNC; ffth->tick_time = fftimehands->tick_time; - ffth->tick_time_mono = fftimehands->tick_time_mono; ffth->tick_error = fftimehands->tick_error; + ffth->tick_time_diff = fftimehands->tick_time_diff; + ffth->tick_time_mono = fftimehands->tick_time_mono; ffth->period_mono = cest->period; /* Do not lock but ignore next update from synchronization daemon. */ @@ -904,6 +918,8 @@ gen = ffth->gen; if ((flags & FFCLOCK_MONO) == FFCLOCK_MONO) *bt = ffth->tick_time_mono; + else if ((flags & FFCLOCK_DIFF) == FFCLOCK_DIFF) + *bt = ffth->tick_time_diff; else *bt = ffth->tick_time; *ffcount = ffth->tick_ffcount; @@ -912,8 +928,7 @@ /* * Absolute clock conversion. Low level function to convert ffcounter to - * bintime. The ffcounter is converted using the current ffclock period estimate - * or the "interpolated period" to ensure monotonicity. + * bintime using the selected FFclock. * NOTE: this conversion may have been deferred, and the clock updated since the * hardware counter has been read. */ @@ -938,7 +953,10 @@ *bt = ffth->tick_time_mono; ffclock_convert_delta(ffdelta, ffth->period_mono, &bt2); } else { - *bt = ffth->tick_time; + if ((flags & FFCLOCK_DIFF) == FFCLOCK_DIFF) + *bt = ffth->tick_time_diff; + else + *bt = ffth->tick_time; ffclock_convert_delta(ffdelta, ffth->cest.period, &bt2); } @@ -1146,7 +1164,6 @@ #endif delta = 0; - do { th = timehands; gen = atomic_load_acq_int(&th->th_generation); @@ -1165,6 +1182,7 @@ ffi = &clock_snap->ff_info; ffth = fftimehands; ffi->tick_time = ffth->tick_time; + ffi->tick_time_diff = ffth->tick_time_diff; ffi->tick_time_mono = ffth->tick_time_mono; ffi->period = ffth->cest.period; ffi->period_mono = ffth->period_mono; @@ -1206,7 +1224,14 @@ /* * Convert a sysclock snapshot into a struct bintime based on the specified - * clock source and flags. + * clock paradigm, and flags. Not all flags combinations are compatible. + * The following are enforced for FFclocks: + * - UPTIME and MONO each supercede DIFF requests for diffFFC + * - UPTIME supercedes MONO + * - MONO implies LEAPSEC + * Default settings (no flags set): + * FBclock: the usual UTC clock (not FAST) + * FFclock: the natFFC UTC clock (not FAST) */ int sysclock_snap2bintime(struct sysclock_snap *cs, struct bintime *bt, @@ -1223,7 +1248,7 @@ *bt = cs->fb_info.tick_time; /* If snapshot was created with !fast, delta will be >0. */ - if (cs->delta > 0) + if (flags & FBCLOCK_FAST && cs->delta > 0) bintime_addx(bt, cs->fb_info.th_scale * cs->delta); if ((flags & FBCLOCK_UPTIME) == 0) { @@ -1237,23 +1262,26 @@ *bt = cs->ff_info.tick_time_mono; period = cs->ff_info.period_mono; } else { - *bt = cs->ff_info.tick_time; period = cs->ff_info.period; + if ((flags & FFCLOCK_DIFF) && !(flags & FFCLOCK_UPTIME)) + *bt = cs->ff_info.tick_time_diff; + else + *bt = cs->ff_info.tick_time; } /* If snapshot was created with !fast, delta will be >0. */ - if (cs->delta > 0) { + if (flags & FFCLOCK_FAST && cs->delta > 0) { ffclock_convert_delta((ffcounter)cs->delta,period,&bt2); bintime_add(bt, &bt2); } - /* Leap second adjustment. */ - if (flags & FFCLOCK_LEAPSEC) - bt->sec -= cs->ff_info.leapsec_adjustment; - - /* Boot time adjustment, for uptime/monotonic clocks. */ + /* Add appropriate const for Uptime, UTC, or diffFFC clock. */ if (flags & FFCLOCK_UPTIME) bintime_sub(bt, &ffclock_boottime); + else // UTC + if (!(flags & FFCLOCK_DIFF) || flags & FFCLOCK_MONO) + bt->sec -= cs->ff_info.leapsec_adjustment; + // else Diff break; #endif default: diff --git a/sys/sys/timeffc.h b/sys/sys/timeffc.h --- a/sys/sys/timeffc.h +++ b/sys/sys/timeffc.h @@ -98,19 +98,20 @@ * Flags for use by sysclock_snap2bintime() and various ffclock_ functions to * control how the timecounter hardware is read and how the hardware snapshot is * converted into absolute time. - * The flags all set independent bits and so are OR-able. - * {FB|FF}CLOCK_FAST: Do not read the hardware counter, instead using the - * value at last tick. The time returned has a resolution - * of the kernel tick timer (1/hz [s]). - * FFCLOCK_MONO: Linear interpolation of ffclock time to guarantee - * monotonic time. - * FFCLOCK_LEAPSEC: Include leap seconds. - * {FB|FF}CLOCK_UPTIME: Time stamp should be relative to system boot, not epoch. + * The flags all set independent bits and so are OR-able. However not + * all combinations are compatible with a meaningful clock. + * {FB|FF}CLOCK_FAST: Do not read the hardware counter, instead use the + * value recorded at the last tc-tick update + * FFCLOCK_DIFF: Read diffFFC (natFFC is the default) + * FFCLOCK_MONO: Read monoFFC (natFFC is the default) + * FFCLOCK_LEAPSEC: Include leap seconds seen since boot + * {FB|FF}CLOCK_UPTIME: Uptime since system boot (default is UTC) */ #define FFCLOCK_FAST 0x00000001 -#define FFCLOCK_MONO 0x00000002 -#define FFCLOCK_LEAPSEC 0x00000004 -#define FFCLOCK_UPTIME 0x00000008 +#define FFCLOCK_DIFF 0x00000002 +#define FFCLOCK_MONO 0x00000004 +#define FFCLOCK_LEAPSEC 0x00000008 +#define FFCLOCK_UPTIME 0x00000010 #define FFCLOCK_MASK 0x0000ffff #define FBCLOCK_FAST 0x00010000 /* Currently unused. */