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