| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -29,9 +29,20 @@ typedef enum { | |||
| 29 | 29 | _PyTime_ROUND_CEILING=1, | |
| 30 | 30 | /* Round to nearest with ties going to nearest even integer. | |
| 31 | 31 | For example, used to round from a Python float. */ | |
| 32 | - _PyTime_ROUND_HALF_EVEN | ||
| 32 | + _PyTime_ROUND_HALF_EVEN=2, | ||
| 33 | + /* Round away from zero | ||
| 34 | + For example, used for timeout. _PyTime_ROUND_CEILING rounds | ||
| 35 | + -1e-9 to 0 milliseconds which causes bpo-31786 issue. | ||
| 36 | + _PyTime_ROUND_UP rounds -1e-9 to -1 millisecond which keeps | ||
| 37 | + the timeout sign as expected. select.poll(timeout) must block | ||
| 38 | + for negative values." */ | ||
| 39 | + _PyTime_ROUND_UP=3, | ||
| 40 | + /* _PyTime_ROUND_TIMEOUT (an alias for _PyTime_ROUND_UP) should be | ||
| 41 | + used for timeouts. */ | ||
| 42 | + _PyTime_ROUND_TIMEOUT = _PyTime_ROUND_UP | ||
| 33 | 43 | } _PyTime_round_t; | |
| 34 | 44 | ||
| 45 | + | ||
| 35 | 46 | /* Convert a time_t to a PyLong. */ | |
| 36 | 47 | PyAPI_FUNC(PyObject *) _PyLong_FromTime_t( | |
| 37 | 48 | time_t sec); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -208,6 +208,28 @@ def test_threaded_poll(self): | |||
| 208 | 208 | os.write(w, b'spam') | |
| 209 | 209 | t.join() | |
| 210 | 210 | ||
| 211 | + @unittest.skipUnless(threading, 'Threading required for this test.') | ||
| 212 | + @reap_threads | ||
| 213 | + def test_poll_blocks_with_negative_ms(self): | ||
| 214 | + for timeout_ms in [None, -1, -1.0, -0.1, -1e-100]: | ||
| 215 | + # Create two file descriptors. This will be used to unlock | ||
| 216 | + # the blocking call to poll.poll inside the thread | ||
| 217 | + r, w = os.pipe() | ||
| 218 | + pollster = select.poll() | ||
| 219 | + pollster.register(r, select.POLLIN) | ||
| 220 | + | ||
| 221 | + poll_thread = threading.Thread(target=pollster.poll, args=(timeout_ms,)) | ||
| 222 | + poll_thread.start() | ||
| 223 | + poll_thread.join(timeout=0.1) | ||
| 224 | + self.assertTrue(poll_thread.is_alive()) | ||
| 225 | + | ||
| 226 | + # Write to the pipe so pollster.poll unblocks and the thread ends. | ||
| 227 | + os.write(w, b'spam') | ||
| 228 | + poll_thread.join() | ||
| 229 | + self.assertFalse(poll_thread.is_alive()) | ||
| 230 | + os.close(r) | ||
| 231 | + os.close(w) | ||
| 232 | + | ||
| 211 | 233 | ||
| 212 | 234 | def test_main(): | |
| 213 | 235 | run_unittest(PollTests) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -36,13 +36,16 @@ class _PyTime(enum.IntEnum): | |||
| 36 | 36 | ROUND_CEILING = 1 | |
| 37 | 37 | # Round to nearest with ties going to nearest even integer | |
| 38 | 38 | ROUND_HALF_EVEN = 2 | |
| 39 | + # Round away from zero | ||
| 40 | + ROUND_UP = 3 | ||
| 39 | 41 | ||
| 40 | 42 | # Rounding modes supported by PyTime | |
| 41 | 43 | ROUNDING_MODES = ( | |
| 42 | 44 | # (PyTime rounding method, decimal rounding method) | |
| 43 | 45 | (_PyTime.ROUND_FLOOR, decimal.ROUND_FLOOR), | |
| 44 | 46 | (_PyTime.ROUND_CEILING, decimal.ROUND_CEILING), | |
| 45 | 47 | (_PyTime.ROUND_HALF_EVEN, decimal.ROUND_HALF_EVEN), | |
| 48 | + (_PyTime.ROUND_UP, decimal.ROUND_UP), | ||
| 46 | 49 | ) | |
| 47 | 50 | ||
| 48 | 51 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,3 @@ | |||
| 1 | + Fix timeout rounding in the select module to round correctly negative timeouts between -1.0 and 0.0. | ||
| 2 | + The functions now block waiting for events as expected. Previously, the call was incorrectly non-blocking. | ||
| 3 | + Patch by Pablo Galindo. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -3016,7 +3016,8 @@ check_time_rounding(int round) | |||
| 3016 | 3016 | { | |
| 3017 | 3017 | if (round != _PyTime_ROUND_FLOOR | |
| 3018 | 3018 | && round != _PyTime_ROUND_CEILING | |
| 3019 | - && round != _PyTime_ROUND_HALF_EVEN) { | ||
| 3019 | + && round != _PyTime_ROUND_HALF_EVEN | ||
| 3020 | + && round != _PyTime_ROUND_UP) { | ||
| 3020 | 3021 | PyErr_SetString(PyExc_ValueError, "invalid rounding"); | |
| 3021 | 3022 | return -1; | |
| 3022 | 3023 | } | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -213,15 +213,15 @@ select_select(PyObject *self, PyObject *args) | |||
| 213 | 213 | tvp = (struct timeval *)NULL; | |
| 214 | 214 | else { | |
| 215 | 215 | if (_PyTime_FromSecondsObject(&timeout, timeout_obj, | |
| 216 | - _PyTime_ROUND_CEILING) < 0) { | ||
| 216 | + _PyTime_ROUND_TIMEOUT) < 0) { | ||
| 217 | 217 | if (PyErr_ExceptionMatches(PyExc_TypeError)) { | |
| 218 | 218 | PyErr_SetString(PyExc_TypeError, | |
| 219 | 219 | "timeout must be a float or None"); | |
| 220 | 220 | } | |
| 221 | 221 | return NULL; | |
| 222 | 222 | } | |
| 223 | 223 | ||
| 224 | - if (_PyTime_AsTimeval(timeout, &tv, _PyTime_ROUND_CEILING) == -1) | ||
| 224 | + if (_PyTime_AsTimeval(timeout, &tv, _PyTime_ROUND_TIMEOUT) == -1) | ||
| 225 | 225 | return NULL; | |
| 226 | 226 | if (tv.tv_sec < 0) { | |
| 227 | 227 | PyErr_SetString(PyExc_ValueError, "timeout must be non-negative"); | |
@@ -543,15 +543,15 @@ poll_poll(pollObject *self, PyObject *args) | |||
| 543 | 543 | } | |
| 544 | 544 | else { | |
| 545 | 545 | if (_PyTime_FromMillisecondsObject(&timeout, timeout_obj, | |
| 546 | - _PyTime_ROUND_CEILING) < 0) { | ||
| 546 | + _PyTime_ROUND_TIMEOUT) < 0) { | ||
| 547 | 547 | if (PyErr_ExceptionMatches(PyExc_TypeError)) { | |
| 548 | 548 | PyErr_SetString(PyExc_TypeError, | |
| 549 | 549 | "timeout must be an integer or None"); | |
| 550 | 550 | } | |
| 551 | 551 | return NULL; | |
| 552 | 552 | } | |
| 553 | 553 | ||
| 554 | - ms = _PyTime_AsMilliseconds(timeout, _PyTime_ROUND_CEILING); | ||
| 554 | + ms = _PyTime_AsMilliseconds(timeout, _PyTime_ROUND_TIMEOUT); | ||
| 555 | 555 | if (ms < INT_MIN || ms > INT_MAX) { | |
| 556 | 556 | PyErr_SetString(PyExc_OverflowError, "timeout is too large"); | |
| 557 | 557 | return NULL; | |
@@ -899,15 +899,15 @@ devpoll_poll(devpollObject *self, PyObject *args) | |||
| 899 | 899 | } | |
| 900 | 900 | else { | |
| 901 | 901 | if (_PyTime_FromMillisecondsObject(&timeout, timeout_obj, | |
| 902 | - _PyTime_ROUND_CEILING) < 0) { | ||
| 902 | + _PyTime_ROUND_TIMEOUT) < 0) { | ||
| 903 | 903 | if (PyErr_ExceptionMatches(PyExc_TypeError)) { | |
| 904 | 904 | PyErr_SetString(PyExc_TypeError, | |
| 905 | 905 | "timeout must be an integer or None"); | |
| 906 | 906 | } | |
| 907 | 907 | return NULL; | |
| 908 | 908 | } | |
| 909 | 909 | ||
| 910 | - ms = _PyTime_AsMilliseconds(timeout, _PyTime_ROUND_CEILING); | ||
| 910 | + ms = _PyTime_AsMilliseconds(timeout, _PyTime_ROUND_TIMEOUT); | ||
| 911 | 911 | if (ms < -1 || ms > INT_MAX) { | |
| 912 | 912 | PyErr_SetString(PyExc_OverflowError, "timeout is too large"); | |
| 913 | 913 | return NULL; | |
@@ -1514,7 +1514,7 @@ pyepoll_poll(pyEpoll_Object *self, PyObject *args, PyObject *kwds) | |||
| 1514 | 1514 | /* epoll_wait() has a resolution of 1 millisecond, round towards | |
| 1515 | 1515 | infinity to wait at least timeout seconds. */ | |
| 1516 | 1516 | if (_PyTime_FromSecondsObject(&timeout, timeout_obj, | |
| 1517 | - _PyTime_ROUND_CEILING) < 0) { | ||
| 1517 | + _PyTime_ROUND_TIMEOUT) < 0) { | ||
| 1518 | 1518 | if (PyErr_ExceptionMatches(PyExc_TypeError)) { | |
| 1519 | 1519 | PyErr_SetString(PyExc_TypeError, | |
| 1520 | 1520 | "timeout must be an integer or None"); | |
@@ -2129,7 +2129,7 @@ kqueue_queue_control(kqueue_queue_Object *self, PyObject *args) | |||
| 2129 | 2129 | } | |
| 2130 | 2130 | else { | |
| 2131 | 2131 | if (_PyTime_FromSecondsObject(&timeout, | |
| 2132 | - otimeout, _PyTime_ROUND_CEILING) < 0) { | ||
| 2132 | + otimeout, _PyTime_ROUND_TIMEOUT) < 0) { | ||
| 2133 | 2133 | PyErr_Format(PyExc_TypeError, | |
| 2134 | 2134 | "timeout argument must be a number " | |
| 2135 | 2135 | "or None, got %.200s", | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -84,12 +84,19 @@ _PyTime_Round(double x, _PyTime_round_t round) | |||
| 84 | 84 | volatile double d; | |
| 85 | 85 | ||
| 86 | 86 | d = x; | |
| 87 | - if (round == _PyTime_ROUND_HALF_EVEN) | ||
| 87 | + if (round == _PyTime_ROUND_HALF_EVEN){ | ||
| 88 | 88 | d = _PyTime_RoundHalfEven(d); | |
| 89 | - else if (round == _PyTime_ROUND_CEILING) | ||
| 89 | + } | ||
| 90 | + else if (round == _PyTime_ROUND_CEILING){ | ||
| 90 | 91 | d = ceil(d); | |
| 91 | - else | ||
| 92 | + } | ||
| 93 | + else if (round == _PyTime_ROUND_FLOOR) { | ||
| 92 | 94 | d = floor(d); | |
| 95 | + } | ||
| 96 | + else { | ||
| 97 | + assert(round == _PyTime_ROUND_UP); | ||
| 98 | + d = (d >= 0.0) ? ceil(d) : floor(d); | ||
| 99 | + } | ||
| 93 | 100 | return d; | |
| 94 | 101 | } | |
| 95 | 102 | ||
@@ -395,16 +402,29 @@ _PyTime_Divide(const _PyTime_t t, const _PyTime_t k, | |||
| 395 | 402 | return x; | |
| 396 | 403 | } | |
| 397 | 404 | else if (round == _PyTime_ROUND_CEILING) { | |
| 398 | - if (t >= 0) | ||
| 405 | + if (t >= 0){ | ||
| 399 | 406 | return (t + k - 1) / k; | |
| 400 | - else | ||
| 407 | + } | ||
| 408 | + else{ | ||
| 401 | 409 | return t / k; | |
| 410 | + } | ||
| 402 | 411 | } | |
| 403 | - else { | ||
| 404 | - if (t >= 0) | ||
| 412 | + else if (round == _PyTime_ROUND_FLOOR){ | ||
| 413 | + if (t >= 0) { | ||
| 405 | 414 | return t / k; | |
| 406 | - else | ||
| 415 | + } | ||
| 416 | + else{ | ||
| 407 | 417 | return (t - (k - 1)) / k; | |
| 418 | + } | ||
| 419 | + } | ||
| 420 | + else { | ||
| 421 | + assert(round == _PyTime_ROUND_UP); | ||
| 422 | + if (t >= 0) { | ||
| 423 | + return (t + k - 1) / k; | ||
| 424 | + } | ||
| 425 | + else { | ||
| 426 | + return (t - (k - 1)) / k; | ||
| 427 | + } | ||
| 408 | 428 | } | |
| 409 | 429 | } | |
| 410 | 430 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments