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

3 files changed

lines changed

Original file line number Diff line number Diff line change
@@ -490,6 +490,16 @@ def test_itimer_prof(self):
490 490 # and the handler should have been called
491 491 self.assertEqual(self.hndl_called, True)
492 492
493 +def test_setitimer_tiny(self):
494 +# bpo-30807: C setitimer() takes a microsecond-resolution interval.
495 +# Check that float -> timeval conversion doesn't round
496 +# the interval down to zero, which would disable the timer.
497 +self.itimer = signal.ITIMER_REAL
498 +signal.setitimer(self.itimer, 1e-6)
499 +time.sleep(1)
500 +self.assertEqual(self.hndl_called, True)
501 +
502 +
493 503 def test_main():
494 504 test_support.run_unittest(BasicSignalTests, InterProcessSignalTests,
495 505 WakeupFDTests, WakeupSignalTests,
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
@@ -111,6 +111,10 @@ timeval_from_double(double d, struct timeval *tv)
111 111 {
112 112 tv->tv_sec = floor(d);
113 113 tv->tv_usec = fmod(d, 1.0) * 1000000.0;
114 +/* Don't disable the timer if the computation above rounds down to zero. */
115 +if (d > 0.0 && tv->tv_sec == 0 && tv->tv_usec == 0) {
116 +tv->tv_usec = 1;
117 + }
114 118 }
115 119
116 120 Py_LOCAL_INLINE(double)