[3.6] bpo-30807: signal.setitimer() may disable the timer by mistake … · python/cpython@6f3cb05 (original) (raw)

3 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -611,6 +611,15 @@ def test_itimer_prof(self):
611 611 # and the handler should have been called
612 612 self.assertEqual(self.hndl_called, True)
613 613
614 +def test_setitimer_tiny(self):
615 +# bpo-30807: C setitimer() takes a microsecond-resolution interval.
616 +# Check that float -> timeval conversion doesn't round
617 +# the interval down to zero, which would disable the timer.
618 +self.itimer = signal.ITIMER_REAL
619 +signal.setitimer(self.itimer, 1e-6)
620 +time.sleep(1)
621 +self.assertEqual(self.hndl_called, True)
622 +
614 623
615 624 class PendingSignalsTests(unittest.TestCase):
616 625 """
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
1 +signal.setitimer() may disable the timer when passed a tiny value.
2 +
3 +Tiny values (such as 1e-6) are valid non-zero values for setitimer(), which
4 +is specified as taking microsecond-resolution intervals. However, on some
5 +platform, our conversion routine could convert 1e-6 into a zero interval,
6 +therefore disabling the timer instead of (re-)scheduling it.
Original file line number Diff line number Diff line change
@@ -139,6 +139,10 @@ timeval_from_double(double d, struct timeval *tv)
139 139 {
140 140 tv->tv_sec = floor(d);
141 141 tv->tv_usec = fmod(d, 1.0) * 1000000.0;
142 +/* Don't disable the timer if the computation above rounds down to zero. */
143 +if (d > 0.0 && tv->tv_sec == 0 && tv->tv_usec == 0) {
144 +tv->tv_usec = 1;
145 + }
142 146 }
143 147
144 148 Py_LOCAL_INLINE(double)