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
Patch selectmodule.c to support WSAPoll on Windows #60711
Comments
Attached patch adds select.poll() support on Windows via WSAPoll. It's hacky; I was curious to see whether or not it could be done, and whether or not tulip's pollster would work with it. It compiles and works, but doesn't play very nicely with tulip. Also, just about every lick of code that tests poll() does so in a UNIX-specific way, so it's hard to test. As with select, WSAPoll() will barf if you feed it anything other than SOCKETs (i.e. it doesn't work against non-socket file descriptors). |
Related post: |
On Sun, Nov 18, 2012 at 03:19:19PM -0800, Antoine Pitrou wrote:
|
Attached is an alternative patch which only touches selectmodule.c. It still does not support WinXP. Note that in this version register() and modify() do not ignore the POLLPRI flag if it was *explicitly* passed. But I am not sure how best to deal with POLLPRI. |
Here is a version which loads WSAPoll at runtime. Still no tests or docs. |
It seems that the return code of WSAPoll() does not include the count of array items with revents == POLLNVAL. In the case where all of them are POLLNVAL, instead of returning 0 (which usually indicates a timeout) it returns -1 and WSAGetLastError() == WSAENOTSOCK. This does not match the MSDN documentation which claims that the return code is the number of descriptors for which revents is non-zero. But it arguably does agree with the FreeBSD and MacOSX man pages which say that it returns the number of descriptors that are "ready for I/O". BTW, the implementation of select_poll() assumes that the return code of poll() (if non-negative) is equal to the number of non-zero revents fields. But select_have_broken_poll() considers a MacOSX poll() implementation to be good even in cases where this assumption is not true: static int select_have_broken_poll(void)
{
int poll_test;
int filedes[2];
struct pollfd poll_struct = { 0, POLLIN|POLLPRI|POLLOUT, 0 };
if (pipe(filedes) < 0) {
return 1;
}
poll_struct.fd = filedes[0];
close(filedes[0]);
close(filedes[1]);
poll_test = poll(&poll_struct, 1, 0);
if (poll_test < 0) {
return 1;
} else if (poll_test == 0 && poll_struct.revents != POLLNVAL) {
return 1;
}
return 0;
} Note that select_have_broken_poll() == FALSE if poll_test == 0 and poll_struct.revents == POLLNVAL. |
Here is a new version with tests and docs. Note that the docs do not mention the bug mentioned in http://daniel.haxx.se/blog/2012/10/10/wsapoll-is-broken/ Maybe they should? Note that that bug makes it a bit difficult to use poll with tulip on Windows. (But one could restrict timeouts to one second and always check outstanding connect attempts using select() when poll() returns.) |
This works well enough (tested in old version of Tulip), right? What's holding it up? |
Oh, it needs a new patch -- the patch fails to apply in the 3.4 |
Here's a new version of the patch. (Will test on Windows next.) |
That compiles (after hacking the line endings). One Tulip test fails, PollEventLooptests.testSockClientFail. But that's probably because the PollSelector class hasn't been adjusted for Windows yet (need to dig this out of the Pollster code that was deleted when switching to neologix's Selector). |
1 similar comment
That compiles (after hacking the line endings). One Tulip test fails, PollEventLooptests.testSockClientFail. But that's probably because the PollSelector class hasn't been adjusted for Windows yet (need to dig this out of the Pollster code that was deleted when switching to neologix's Selector). |
Sorry I did not deal with this earlier. I can make the modifications to PollSelector tommorrow. Just to describe the horrible hack: every time poll() needs to be called we first check if there are any registered async connects. If so then I first use select([], [], connectors) to detect any failed connections, and then use poll() normally. This does mean that to detect failed connections we must never use too large a timeout with poll() when there are outstanding connects. Of course one must decide what is an acceptable maximum timeout -- too short and you might damage battery life, too long and you will not get prompt notification of failures. |
Ow. How painful. I'll leave this for you to do. Note that this also |
(FWIW, I've got the EVENT_CONNECT separation done.) |
Time for a stupid question from someone who doesn't know anything about Windows: if WSAPoll() is really terminally broken, is it really worth the hassle exposing it and warping the API? |
This is a very good question to which I have no good answer. If it weren't for this, we could probably do away with the distinction between add_writer and add_connector, and a lot of code could be simpler. (Or is that distinction also needed for IOCP?) |
On 21/01/2013 5:38pm, Guido van Rossum wrote:
The distinction is not needed by IOCP. I am also not too sure that OFF-TOPIC: Although it is not the optimal way of running tulip with I did have to make some changes to the tests: selectors have a I also had to make the unittests behave gracefully if there is a It would be possible to make IocpSelector deal with pipe handles too. |
Thanks -- I am now close to rejecting the WSAPoll() patch, and even Regarding your IOCP changes, that sounds pretty exciting. Richard, |
On 21/01/2013 7:00pm, Guido van Rossum wrote:
OK. It may take me a while to rebase them. |
I have created an iocp branch. |
You could probably report the fixes for spurious notifications in the |
It appears that Linux's "spurious readiness notifications" are a deliberate deviation from the POSIX standard. (They are mentioned in the BUGS section of the man page for select.) Should I just apply the following patch to the default branch? diff -r 3ef7f1fe286c tulip/events_test.py
--- a/tulip/events_test.py Mon Jan 21 18:55:29 2013 -0800
+++ b/tulip/events_test.py Tue Jan 22 12:09:21 2013 +0000
@@ -200,7 +200,12 @@
r, w = unix_events.socketpair()
bytes_read = []
def reader():
- data = r.recv(1024)
+ try:
+ data = r.recv(1024)
+ except BlockingIOError:
+ # Spurious readiness notifications are possible
+ # at least on Linux -- see man select.
+ return
if data:
bytes_read.append(data)
else:
@@ -218,7 +223,12 @@
r, w = unix_events.socketpair()
bytes_read = []
def reader():
- data = r.recv(1024)
+ try:
+ data = r.recv(1024)
+ except BlockingIOError:
+ # Spurious readiness notifications are possible
+ # at least on Linux -- see man select.
+ return
if data:
bytes_read.append(data)
else: |
I don't think it's a deliberate deviation, but really bugs/limitations That's something we have to live with (like pthread condition spurious Also, in real code you have to be prepared to catch EAGAIN regardless So if you want to receive e.g. a large amount of data and the FD is """ if data is None:
break
buffer += data
""" Otherwise, you'd have to read() only one byte at a time, and go back (For write ready, you can obviously have "spurious" notifications if
LGTM. |
If only one byte is available, recv(4096) should simply return a partial result. |
According to Alan Cox
See https://lkml.org/lkml/2011/6/18/103
Wouldn't you just get a partial write (assuming an AF_INET, SOCK_STREAM socket)? |
Of course, but how do you know if there's data left to read without
For SOCK_STREAM, yes, not for SOCK_DGRAM (or for a pipe when trying to
Yes, he's referring to the fact that there are cases where you could But there are been various fixes in the past years to avoid spurious I'm 99% sure that Linux isn't the only OS allowing spurious wakeups, |
That should be of course "when trying to write LESS than PIPE_BUF", |
Short reads/writes are orthogonal to EAGAIN. All the mainline code treats --Guido van Rossum (sent from Android phone) |
I thought SOCK_DGRAM messages just got truncated at the receiving end. |
You were referring to partial writes: for a datagram-oriented Going back to the subject: so what do we say, let's just forget about If we ever choose to export it, I think the least we should do would When I see the hoops Richard had to go through to make WSAPoll usable |
Agreed, it does not sound very useful to support WSAPoll(), neither in |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: