/* normalize delay */
if (stp->delay_div) {
+ /*
+ * Scale the complete duration as a single value in
+ * microseconds, then split the result back into seconds and
+ * microseconds. Dividing tv_sec and tv_usec independently
+ * truncates the fractional part of the whole-seconds field
+ * instead of carrying it into microseconds, so for example a
+ * 1.000000 s delay scaled by divisor 2 became 0.000000 s rather
+ * than the expected 0.500000 s.
+ */
+ double total = (double) step->delay.tv_sec * 1000000.0
+ + (double) step->delay.tv_usec;
+
DBG(TIMING, ul_debug(" normalize delay: divide"));
- step->delay.tv_sec /= stp->delay_div;
- step->delay.tv_usec /= stp->delay_div;
+ total /= stp->delay_div;
+ step->delay.tv_sec = (time_t) (total / 1000000.0);
+ step->delay.tv_usec = (suseconds_t) (total
+ - (double) step->delay.tv_sec * 1000000.0);
}
if (timerisset(&stp->delay_max) &&
timercmp(&step->delay, &stp->delay_max, >)) {
ts_finalize_subtest
+#
+# Divisor must scale the complete delay, not divide tv_sec and tv_usec
+# independently (see https://github.com/util-linux/util-linux/issues/4500).
+# A 1.000000 s delay with divisor 2 has to become ~0.5 s; the old per-field
+# division truncated the whole-seconds field and collapsed it to 0 s.
+#
+ts_init_subtest "divisor-fractional"
+printf '1.000000 1\n' >"$TS_OUTDIR/${TS_TESTNAME}-div-timing"
+printf 'Script started\nX' >"$TS_OUTDIR/${TS_TESTNAME}-div-typescript"
+
+start=$(date +%s.%N)
+$TS_CMD_SCRIPTREPLAY \
+ --divisor 2 \
+ "$TS_OUTDIR/${TS_TESTNAME}-div-timing" \
+ "$TS_OUTDIR/${TS_TESTNAME}-div-typescript" \
+ </dev/null >/dev/null 2>>"$TS_ERRLOG"
+end=$(date +%s.%N)
+elapsed=$(awk -v e="$end" -v s="$start" 'BEGIN{printf "%.3f", e - s}')
+
+# The fix sleeps ~0.5 s; the bug returned in ~0 s. Use a window that is
+# robust to scheduler jitter but excludes both 0 s (bug) and 1 s (no scaling).
+awk -v t="$elapsed" 'BEGIN{exit (t < 0.20 || t > 0.90) ? 1 : 0}' || {
+ echo "elapsed=${elapsed}s (expected ~0.5s)" >>"$TS_OUTPUT"
+ ts_failed "divisor collapsed delay (elapsed=${elapsed}s)"
+}
+ts_finalize_subtest
+
+
#
# New command line format
#