Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpo-31786: Make select.poll.poll block if ms < 0 for every value of ms #4003

Merged
merged 14 commits into from
Oct 17, 2017

Conversation

pablogsal
Copy link
Member

@pablogsal pablogsal commented Oct 15, 2017

Acording to the documentation select.poll.poll() is blocked for infinite timeout if the timeout argument is negative but:

>>> import select
>>> poll = select.poll()
>>> poll.poll(-0.000000000000000001)
[]

This is due to rounding issues when making the syscall. This PR fixes that so the call to poll.poll will block if the argument is negative.

https://bugs.python.org/issue31786

@pablogsal
Copy link
Member Author

pablogsal commented Oct 15, 2017

Following @Haypo and @serhiy-storchaka discussion in the issue: Please, if you prefer a better/different way of dealing with this issue, I am more than happy to update the PR with the required changes.

Copy link
Member

@vstinner vstinner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ms > 0 doesn't seem to be correct to me.

I prefer to fix the rouding and fix all functions.

@bedevere-bot
Copy link

A Python core developer has requested some changes be made to your pull request before we can consider merging it. If you could please address their requests along with any other requests in other reviews from core developers that would be appreciated.

Once you have made the requested changes, please leave a comment on this pull request containing the phrase I have made the requested changes; please review again. I will then notify any core developers who have left a review that you're ready for them to take another look at this pull request.

@serhiy-storchaka
Copy link
Member

This part doesn't look correct to me too. But the test may be useful if make it testing other infinity timeout values. They are not tested explicitly.

@pablogsal
Copy link
Member Author

@Haypo I have implemented ROUND_UP in pytime.h and pytime.c following your instructions and substitute the usage of ROUND_CEILING in the select module. Please, if you are happy with this implementation, check that the usage of the new ROUND_UP is correct (I think it is but maybe I am missing something).

@serhiy-storchaka I have updated the test so it takes into account more infinite timeout values.

If you prefer a different implementation or use this in more/less places, say so and I will update this PR.

Thank you for your time reviewing this PR! 😄

@pablogsal
Copy link
Member Author

I have made the requested changes; please review again

@bedevere-bot
Copy link

Thanks for making the requested changes!

@Haypo: please review the changes made to this pull request.

Python/pytime.c Outdated
d = floor(d);
}
else {
d = (d < 0.0) ? floor(d) : ceil(d);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add assert(round == _PyTime_ROUND_UP).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5c58695

@unittest.skipUnless(threading, 'Threading required for this test.')
@reap_threads
def test_poll_blocks_with_negative_ms(self):

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are too much empty lines. I think the code would look better without them. Empty lines should be used for separating functions, classes, and, sparingly, to indicate logical sections in functions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5c58695


for timeout_ms in [None, -1, -1.0, -0.1, -1e-100]:

# GIVEN
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, but I don't understand what mean these GIVEN/WHEN/THEN.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I add then for clarity when testing (example).

I will delete them if you want.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5c58695

# Create two file descriptors. This will be used to unlock
# the blocking call to poll.poll inside the thread

r, w = os.pipe()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A pair of descriptors is created for every timeout_ms value, but they are closed only after finishing the test.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5c58695

@@ -594,7 +594,7 @@ poll_poll(pollObject *self, PyObject *args)
poll_result = 0;
break;
}
ms = _PyTime_AsMilliseconds(timeout, _PyTime_ROUND_CEILING);
ms = _PyTime_AsMilliseconds(timeout, _PyTime_ROUND_UP);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since timeout >= 0, there is no difference between _PyTime_ROUND_CEILING and _PyTime_ROUND_UP here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5c96cd6

@@ -282,7 +282,7 @@ select_select(PyObject *self, PyObject *args)
n = 0;
break;
}
_PyTime_AsTimeval_noraise(timeout, &tv, _PyTime_ROUND_CEILING);
_PyTime_AsTimeval_noraise(timeout, &tv, _PyTime_ROUND_UP);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since timeout >= 0, there is no difference between _PyTime_ROUND_CEILING and _PyTime_ROUND_UP here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5c96cd6

@@ -221,7 +221,7 @@ select_select(PyObject *self, PyObject *args)
return NULL;
}

if (_PyTime_AsTimeval(timeout, &tv, _PyTime_ROUND_CEILING) == -1)
if (_PyTime_AsTimeval(timeout, &tv, _PyTime_ROUND_UP) == -1)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

timeout above is rounded with _PyTime_ROUND_CEILING. Negative values between -1e-9 and 0 already are rounded to 0.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 5c96cd6

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't _PyTime_ROUND_UP be used instead in _PyTime_FromSecondsObject()?

Copy link
Member Author

@pablogsal pablogsal Oct 15, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! Corrected in 3f1f553. I am sorry if I miss a few places. A combination of ROUND_CEILING and ROUND_UP was causing a rounding error in test.eintrdata.eintr_tester.TimeEINTRTest and I was a bit paranoid and disoriented when changing these. 😞

@pablogsal
Copy link
Member Author

Should I add a NEWS entry?

@serhiy-storchaka
Copy link
Member

Yes, this change requires a NEWS entry.

@@ -213,7 +213,7 @@ select_select(PyObject *self, PyObject *args)
tvp = (struct timeval *)NULL;
else {
if (_PyTime_FromSecondsObject(&timeout, timeout_obj,
_PyTime_ROUND_CEILING) < 0) {
_PyTime_ROUND_UP) < 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Different direction of rounding shouldn't be mixed. Use _PyTime_ROUND_UP in _PyTime_AsTimeval() below, otherwise the timeout from -999 to -1 nanoseconds will be rounded to 0.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solved in 3f7ccda.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this is not needed. At line 285 the value is not negative.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👌

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the patience!

@miss-islington
Copy link
Contributor

Thanks @pablogsal for the PR, and @serhiy-storchaka for merging it 🌮🎉.. I'm working now to backport this PR to: 2.7, 3.6.
🐍🍒⛏🤖

@miss-islington
Copy link
Contributor

Sorry, @pablogsal and @serhiy-storchaka, I could not cleanly backport this to 3.6 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker 2c15b29aea5d6b9c61aa42d2c24a07ff1edb4b46 3.6

@serhiy-storchaka serhiy-storchaka added the type-bug An unexpected behavior, bug, or error label Oct 17, 2017
@miss-islington
Copy link
Contributor

Thanks @pablogsal for the PR, and @serhiy-storchaka for merging it 🌮🎉.. I'm working now to backport this PR to: 2.7, 3.6.
🐍🍒⛏🤖

@miss-islington
Copy link
Contributor

Sorry, @pablogsal and @serhiy-storchaka, I could not cleanly backport this to 2.7 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker 2c15b29aea5d6b9c61aa42d2c24a07ff1edb4b46 2.7

2 similar comments
@miss-islington
Copy link
Contributor

Sorry, @pablogsal and @serhiy-storchaka, I could not cleanly backport this to 2.7 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker 2c15b29aea5d6b9c61aa42d2c24a07ff1edb4b46 2.7

@miss-islington
Copy link
Contributor

Sorry, @pablogsal and @serhiy-storchaka, I could not cleanly backport this to 2.7 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker 2c15b29aea5d6b9c61aa42d2c24a07ff1edb4b46 2.7

@miss-islington
Copy link
Contributor

Sorry, @pablogsal and @serhiy-storchaka, I could not cleanly backport this to 3.6 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker 2c15b29aea5d6b9c61aa42d2c24a07ff1edb4b46 3.6

1 similar comment
@miss-islington
Copy link
Contributor

Sorry, @pablogsal and @serhiy-storchaka, I could not cleanly backport this to 3.6 due to a conflict.
Please backport using cherry_picker on command line.
cherry_picker 2c15b29aea5d6b9c61aa42d2c24a07ff1edb4b46 3.6

@serhiy-storchaka
Copy link
Member

@Mariatta, seems @miss-islington tries to create backports again and again.

@vstinner
Copy link
Member

@Mariatta, seems @miss-islington tries to create backports again and again.

I removed the "needs backport" labels to prevent the issue.

@serhiy-storchaka
Copy link
Member

Do you mind to backport this to 3.6 and 2.7 @pablogsal?

@pablogsal
Copy link
Member Author

@serhiy-storchaka No problem! Should I do this before fixing the other functions?

Thank you very much for your patience and time, @Haypo and @serhiy-storchaka ! 😄

@serhiy-storchaka
Copy link
Member

Please do this before #3277 be merged.

@Mariatta
Copy link
Member

😕 Thanks for the ping! I'll take a look at miss-islington's logs to see what's going on.

@Mariatta
Copy link
Member

I opened a bug 🐛 python/miss-islington#35

pablogsal added a commit to pablogsal/cpython that referenced this pull request Oct 17, 2017
…meout is a small negative value. (pythonGH-4003).

(cherry picked from commit 2c15b29)
@pablogsal
Copy link
Member Author

pablogsal commented Oct 17, 2017

@Haypo, @serhiy-storchaka: I have backported this to 3.6: #4022 .

I am wondering if this can be packported directly to 2.7... The reason is that /Modules/selectmodule.c doesn't use any rounding method from pytime among other major differences. Am I missing something?

@serhiy-storchaka
Copy link
Member

If this is not relevant to 2.7, it is worth to backport just tests.

@pablogsal
Copy link
Member Author

pablogsal commented Oct 17, 2017

Sorry, I did not explain correctly: 2.7 still has the same issue, but this cannot be backported directly to 2.7 due to very different strucutres. For example, /Modules/selectmodule.c doesn't use any rounding method from pytime.In order to backport this to 2.7 bigger changes should be performed (at least I don't know how to measure how many things should be changed).

serhiy-storchaka pushed a commit to serhiy-storchaka/cpython that referenced this pull request Oct 18, 2017
…meout is a small negative value. (pythonGH-4003).

(cherry picked from commit 2c15b29)
serhiy-storchaka pushed a commit that referenced this pull request Oct 18, 2017
…meout is a small negative value. (GH-4003). (#4022)

(cherry picked from commit 2c15b29)
serhiy-storchaka added a commit that referenced this pull request Oct 18, 2017
…meout is a small negative value. (GH-4003). (#4031)

(cherry picked from commit 2c15b29)
@serhiy-storchaka
Copy link
Member

The test is backported by #4031.

@pablogsal pablogsal deleted the 31786 branch October 18, 2017 08:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug An unexpected behavior, bug, or error
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants