NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/59339: heartbeat watchdog fires since 10.99.14



The following reply was made to PR kern/59339; it has been noted by GNATS.

From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
To: Thomas Klausner <wiz%NetBSD.org@localhost>, Patrick Welche <prlw1%welche.eu@localhost>
Cc: gnats-bugs%NetBSD.org@localhost, netbsd-bugs%NetBSD.org@localhost
Subject: Re: kern/59339: heartbeat watchdog fires since 10.99.14
Date: Mon, 12 May 2025 02:27:35 +0000

 This is a multi-part message in MIME format.
 --=_9mocicosntHKdkPBqLK6zsx2at0gzuB8
 
 Sixth time's the charm, right?  (This time I checked to make sure all
 the printfs end with \n!  And I have removed the noisy one which is
 evidently no longer valuable.)
 
 --=_9mocicosntHKdkPBqLK6zsx2at0gzuB8
 Content-Type: text/plain; charset="ISO-8859-1"; name="pr59339-itimercalloutassert-v6"
 Content-Transfer-Encoding: quoted-printable
 Content-Disposition: attachment; filename="pr59339-itimercalloutassert-v6.patch"
 
 diff -r 55a6ded9e19e -r 3a9986775d9a sys/kern/kern_time.c
 --- a/sys/kern/kern_time.c	Thu May 08 20:51:40 2025 +0000
 +++ b/sys/kern/kern_time.c	Sun May 11 23:38:46 2025 +0000
 @@ -837,6 +837,91 @@ itimer_arm_real(struct itimer * const it
  }
 =20
  /*
 + * itimer_rearm_real:
 + *
 + *	Re-arm a non-virtual timer, given the current clock readout.
 + */
 +static void
 +itimer_rearm_real(struct itimer * const it, const struct timespec * const =
 now,
 +    const struct timespec * const last)
 +{
 +	const struct timespec * const interval =3D &it->it_time.it_interval;
 +	const struct timespec * const next =3D &it->it_time.it_value;
 +	struct timespec delta;
 +	int ticks;
 +
 +	KASSERT(!it->it_dying);
 +	KASSERT(!CLOCK_VIRTUAL_P(it->it_clockid));
 +	KASSERT(!callout_pending(&it->it_ch));
 +
 +	if (__predict_true(timespecisset(next))) {
 +		struct timespec now1;
 +
 +		if (it->it_clockid =3D=3D CLOCK_MONOTONIC) {
 +			getnanouptime(&now1);
 +		} else {
 +			getnanotime(&now1);
 +		}
 +		if (timespeccmp(next, &now1, <=3D)) {
 +			printf("PR kern/59339 (heartbeat watchdog fires"
 +			    " since 10.99.14) would fire:"
 +			    " [clock %u]"
 +			    " [now=3D%lld.%09ld -> %lld.%09ld],"
 +			    " last=3D%lld.%09ld + interval=3D%lld.%09ld"
 +			    " -> next=3D%lld.%09ld\n",
 +			    it->it_clockid,
 +			    (long long)now->tv_sec, (long)now->tv_nsec,
 +			    (long long)now1.tv_sec, (long)now1.tv_nsec,
 +			    (long long)last->tv_sec, (long)last->tv_nsec,
 +			    (long long)interval->tv_sec,
 +			    (long)interval->tv_nsec,
 +			    (long long)next->tv_sec, (long)next->tv_nsec);
 +		}
 +
 +		KASSERTMSG(timespeccmp(now, next, <),
 +		    "[clock %u]"
 +		    " now=3D%lld.%09ld,"
 +		    " last=3D%lld.%09ld + interval=3D%lld.%09ld"
 +		    " -> next=3D%lld.%09ld",
 +		    it->it_clockid,
 +		    (long long)now->tv_sec, (long)now->tv_nsec,
 +		    (long long)last->tv_sec, (long)last->tv_nsec,
 +		    (long long)interval->tv_sec, (long)interval->tv_nsec,
 +		    (long long)next->tv_sec, (long)next->tv_nsec);
 +		timespecsub(next, now, &delta);
 +	} else {
 +		/*
 +		 * If the arithmetic overflowed, just take the interval
 +		 * as the time to wait.  This is unlikely to happen
 +		 * unless you are messing with your clock to set it
 +		 * ahead by hundreds of years.
 +		 */
 +		printf("[clock %u]"
 +		    " itimer arithmetic overflowed:"
 +		    " now=3D%lld.%09ld, last=3D%lld.%09ld + interval=3D%lld.%09ld\n",
 +		    it->it_clockid,
 +		    (long long)now->tv_sec, (long)now->tv_nsec,
 +		    (long long)last->tv_sec, (long)last->tv_nsec,
 +		    (long long)interval->tv_sec, (long)interval->tv_nsec);
 +		delta =3D it->it_time.it_interval; /* overflow */
 +	}
 +	ticks =3D tstohz(&delta);
 +	KASSERTMSG(ticks > 0,
 +	    "[clock %u]"
 +	    " now=3D%lld.%09ld,"
 +	    " last=3D%lld.%09ld + interval=3D%lld.%09ld -> next=3D%lld.%09ld;"
 +	    " delta=3D%lld.%09ld ticks=3D%d",
 +	    it->it_clockid,
 +	    (long long)now->tv_sec, (long)now->tv_nsec,
 +	    (long long)last->tv_sec, (long)last->tv_nsec,
 +	    (long long)interval->tv_sec, (long)interval->tv_nsec,
 +	    (long long)next->tv_sec, (long)next->tv_nsec,
 +	    (long long)delta.tv_sec, (long)delta.tv_nsec,
 +	    ticks);
 +	callout_schedule(&it->it_ch, ticks);
 +}
 +
 +/*
   * itimer_callout:
   *
   *	Callout to expire a non-virtual timer.  Queue it up for processing,
 @@ -848,7 +933,7 @@ itimer_arm_real(struct itimer * const it
  static void
  itimer_callout(void *arg)
  {
 -	struct timespec now, next;
 +	struct timespec last, now, next;
  	struct itimer * const it =3D arg;
  	int overruns;
 =20
 @@ -871,7 +956,20 @@ itimer_callout(void *arg)
  	 * Given the current itimer value and interval and the time
  	 * now, compute the next itimer value and count overruns.
  	 */
 +	last =3D it->it_time.it_value;
  	itimer_transition(&it->it_time, &now, &next, &overruns);
 +	KASSERTMSG(timespeccmp(&now, &next, <),
 +	    "[clock %u]"
 +	    " it->it_time.it_value=3D%lld.%09ld"
 +	    " it->it_time.it_interval=3D%lld.%09ld"
 +	    " now=3D%lld.%09ld next=3D%lld.%09ld",
 +	    it->it_clockid,
 +	    (long long)it->it_time.it_value.tv_sec,
 +	    (long)it->it_time.it_value.tv_nsec,
 +	    (long long)it->it_time.it_interval.tv_sec,
 +	    (long)it->it_time.it_interval.tv_nsec,
 +	    (long long)now.tv_sec, (long)now.tv_nsec,
 +	    (long long)next.tv_sec, (long)next.tv_nsec);
  	it->it_time.it_value =3D next;
  	it->it_overruns +=3D overruns;
 =20
 @@ -879,7 +977,7 @@ itimer_callout(void *arg)
  	 * Reset the callout, if it's not going away.
  	 */
  	if (!it->it_dying)
 -		itimer_arm_real(it);
 +		itimer_rearm_real(it, &now, &last);
  	itimer_unlock();
  }
 =20
 diff -r 55a6ded9e19e -r 3a9986775d9a sys/kern/subr_time.c
 --- a/sys/kern/subr_time.c	Thu May 08 20:51:40 2025 +0000
 +++ b/sys/kern/subr_time.c	Sun May 11 23:38:46 2025 +0000
 @@ -86,17 +86,29 @@ tshztoup(const struct timespec *tsp)
 =20
  /*
   * Compute number of ticks in the specified amount of time.
 + *
 + * Round up, clamped to INT_MAX.  Return 0 iff ts <=3D 0.
   */
  int
  tstohz(const struct timespec *ts)
  {
  	struct timeval tv;
 =20
 +	KASSERT(ts->tv_nsec >=3D 0);
 +	KASSERT(ts->tv_nsec < 1000000000);
 +
  	/*
  	 * usec has great enough resolution for hz, so convert to a
  	 * timeval and use tvtohz() above.
  	 */
 -	TIMESPEC_TO_TIMEVAL(&tv, ts);
 +	tv.tv_sec =3D ts->tv_sec;
 +	tv.tv_usec =3D (ts->tv_nsec + 999)/1000;
 +	if (tv.tv_usec >=3D 1000000) {
 +		if (__predict_false(tv.tv_sec =3D=3D __type_max(time_t)))
 +			return INT_MAX;
 +		tv.tv_sec++;
 +		tv.tv_usec -=3D 1000000;
 +	}
  	return tvtohz(&tv);
  }
 =20
 @@ -248,7 +260,8 @@ ts2timo(clockid_t clock_id, int flags, s
  		return ETIMEDOUT;
 =20
  	*timo =3D tstohz(ts);
 -	KASSERT(*timo > 0);
 +	KASSERTMSG(*timo > 0, "ts=3D%lld.%09ld *timo=3D%d",
 +	    (long long)ts->tv_sec, (long)ts->tv_nsec, *timo);
 =20
  	return 0;
  }
 
 --=_9mocicosntHKdkPBqLK6zsx2at0gzuB8--
 


Home | Main Index | Thread Index | Old Index