[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) |