Skip to content

Commit 62e44e4

Browse files
Pull up following revision(s) (requested by riastradh in ticket #57):
sys/kern/subr_time.c: revision 1.42 tests/kernel/t_time_arith.c: revision 1.4 tests/kernel/t_time_arith.c: revision 1.5 tests/kernel/t_time_arith.c: revision 1.6 tests/kernel/t_time_arith.c: revision 1.7 sys/kern/subr_time_arith.c: revision 1.4 sys/kern/subr_time_arith.c: revision 1.5 tvtohz(9): Add some automatic tests. Preparation for: PR kern/59691: tstohz(9) fails to round up on some inputs tstohz(9): Add some automatic tests. Move this from subr_time.c to subr_time_arith.c to facilitate them. PR kern/59691: tstohz(9) fails to round up on some inputs tstohz(9): Round up, not down. This is used for timeouts, and it is bad if it returns a timeout that is too short, particularly if it rounds `wait a little' to `don't wait at all'. This still has some substantial rounding errors, e.g. at hz=8191 with a period of just over 122 085 ns, tstohz(122 084 ns) this returns 3 when it should return 2 because it rounds up to tvtohz(123 us) for which 3 is the correct answer -- but at least it's still rounding up. I'll leave those as xfail for now. PR kern/59691: tstohz(9) fails to round up on some inputs This was likely the underlying cause of various heartbeat panics users have been seeing -- I hypothesize that for short timeouts that reschedule themselves, the itimer callout would call itself in a loop and never return from callout_softclock because of this rounding down: PR kern/59339: heartbeat watchdog fires since 10.99.14 PR kern/59465: Recurring kernel panic with -current (10.99.14): "heart stopped beating" PR kern/59679: Multiple "heart stopped beating" / "softints stuck for 16 seconds" panics tstohz(9): Fix missing digit in three test cases. Tripped on i386 testbed but not on amd64, and generally on LP32 but not on LP64, because tvohz chooses branches differently depending on LONG_MAX. PR kern/59691: tstohz(9) fails to round up on some inputs
1 parent 93c906c commit 62e44e4

File tree

3 files changed

+783
-22
lines changed

3 files changed

+783
-22
lines changed

sys/kern/subr_time.c

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: subr_time.c,v 1.41 2024/12/22 23:24:20 riastradh Exp $ */
1+
/* $NetBSD: subr_time.c,v 1.41.2.1 2025/10/19 09:41:04 martin Exp $ */
22

33
/*
44
* Copyright (c) 1982, 1986, 1989, 1993
@@ -33,7 +33,7 @@
3333
*/
3434

3535
#include <sys/cdefs.h>
36-
__KERNEL_RCSID(0, "$NetBSD: subr_time.c,v 1.41 2024/12/22 23:24:20 riastradh Exp $");
36+
__KERNEL_RCSID(0, "$NetBSD: subr_time.c,v 1.41.2.1 2025/10/19 09:41:04 martin Exp $");
3737

3838
#include <sys/param.h>
3939
#include <sys/types.h>
@@ -84,22 +84,6 @@ tshztoup(const struct timespec *tsp)
8484
return tstohz(&ts);
8585
}
8686

87-
/*
88-
* Compute number of ticks in the specified amount of time.
89-
*/
90-
int
91-
tstohz(const struct timespec *ts)
92-
{
93-
struct timeval tv;
94-
95-
/*
96-
* usec has great enough resolution for hz, so convert to a
97-
* timeval and use tvtohz() above.
98-
*/
99-
TIMESPEC_TO_TIMEVAL(&tv, ts);
100-
return tvtohz(&tv);
101-
}
102-
10387
int
10488
inittimeleft(struct timespec *ts, struct timespec *sleepts)
10589
{

sys/kern/subr_time_arith.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $NetBSD: subr_time_arith.c,v 1.3 2025/04/01 23:14:23 riastradh Exp $ */
1+
/* $NetBSD: subr_time_arith.c,v 1.3.2.1 2025/10/19 09:41:04 martin Exp $ */
22

33
/*-
44
* Copyright (c) 2000, 2004, 2005, 2007, 2008, 2009, 2020
@@ -63,7 +63,7 @@
6363
*/
6464

6565
#include <sys/cdefs.h>
66-
__KERNEL_RCSID(0, "$NetBSD: subr_time_arith.c,v 1.3 2025/04/01 23:14:23 riastradh Exp $");
66+
__KERNEL_RCSID(0, "$NetBSD: subr_time_arith.c,v 1.3.2.1 2025/10/19 09:41:04 martin Exp $");
6767

6868
#include <sys/types.h>
6969

@@ -155,6 +155,34 @@ tvtohz(const struct timeval *tv)
155155
return ((int)ticks);
156156
}
157157

158+
/*
159+
* Compute number of ticks in the specified amount of time.
160+
*
161+
* Round up, clamped to INT_MAX. Return 0 iff ts <= 0.
162+
*/
163+
int
164+
tstohz(const struct timespec *ts)
165+
{
166+
struct timeval tv;
167+
168+
KASSERT(ts->tv_nsec >= 0);
169+
KASSERT(ts->tv_nsec < 1000000000);
170+
171+
/*
172+
* usec has great enough resolution for hz, so convert to a
173+
* timeval and use tvtohz() above.
174+
*/
175+
tv.tv_sec = ts->tv_sec;
176+
tv.tv_usec = (ts->tv_nsec + 999)/1000;
177+
if (tv.tv_usec >= 1000000) {
178+
if (__predict_false(tv.tv_sec == __type_max(time_t)))
179+
return INT_MAX;
180+
tv.tv_sec++;
181+
tv.tv_usec -= 1000000;
182+
}
183+
return tvtohz(&tv);
184+
}
185+
158186
/*
159187
* Check that a proposed value to load into the .it_value or
160188
* .it_interval part of an interval timer is acceptable, and

0 commit comments

Comments
 (0)