Hi,
I am looking at bug #12048 http://bugs.winehq.org/show_bug.cgi?id=12048
From a relay trace it is easy enough to find where the app is getting
dead-locked and why it should not.
It is calling recv() on a socket that was previously: 1) set to blocking with a WS_ioctlsock() call with cmd WS_FIONBIO 2) AsyncSelect()'ed that should make the socket non-blocking.
The first call set the unix file descriptor to blocking:
fcntl( fd, F_SETFL, 0 );
while the second does not touch the unix fd. This leaves the unix file descriptor in the blocking state and the unix recvmsg() call will not terminate.
I thought the unix file descriptor should always by non-blocking, but it is a while since I was looking at socket code. Hopefully someone can tell me if I am barking up the right tree.
Is what I think correct, and should the fcntl()'s simply go. Or should AsyncSelect() set the unix fd to non blocking instead?
Rein.
It is calling recv() on a socket that was previously:
- set to blocking with a WS_ioctlsock() call with cmd WS_FIONBIO
- AsyncSelect()'ed that should make the socket non-blocking.
(snip)
while the second does not touch the unix fd. This leaves the unix file descriptor in the blocking state and the unix recvmsg() call will not terminate.
I thought the unix file descriptor should always by non-blocking, but it is a while since I was looking at socket code.
No, it's possible to make blocking socket calls in Windows too. If you've left a socket in blocking mode, and call one of the blocking Winsock functions, like send() or recv(), Wine will call a Unix library function, like sendmsg() or recvmsg(), that will block too.
Is what I think correct, and should the fcntl()'s simply go. Or should AsyncSelect() set the unix fd to non blocking instead?
I guess you need tests to confirm that calling WSAAsyncSelect causes a socket to become nonblocking.. --Juan
On Thu, Jul 23, 2009 at 1:50 PM, Juan Langjuan.lang@gmail.com wrote:
It is calling recv() on a socket that was previously:
- set to blocking with a WS_ioctlsock() call with cmd WS_FIONBIO
- AsyncSelect()'ed that should make the socket non-blocking.
(snip)
while the second does not touch the unix fd. This leaves the unix file descriptor in the blocking state and the unix recvmsg() call will not terminate.
I thought the unix file descriptor should always by non-blocking, but it is a while since I was looking at socket code.
No, it's possible to make blocking socket calls in Windows too. If you've left a socket in blocking mode, and call one of the blocking Winsock functions, like send() or recv(), Wine will call a Unix library function, like sendmsg() or recvmsg(), that will block too.
Is what I think correct, and should the fcntl()'s simply go. Or should AsyncSelect() set the unix fd to non blocking instead?
I guess you need tests to confirm that calling WSAAsyncSelect causes a socket to become nonblocking.. --Juan
I think what Rein means is that the unix socket fd backing the windows socket handle is always non-blocking - and if he is, he may be correct:
http://source.winehq.org/source/server/sock.c#L578 && http://source.winehq.org/source/server/sock.c#L663
Any socket created by the wine server is automatically made non-blocking. In order to block on windows sockets, we have a function called do_block: http://source.winehq.org/source/dlls/ws2_32/socket.c#L645 and _is_blocking to do the actual blocking for us. An easy example of why we do this is WS_accept. If we make the listening socket blocking, we can "freeze" the wineserver.
I don't think we need to actually set the unix fd to non-blocking during ioctlsocket, so just removing those fcntl's should work. Just tested this and ws2_32&wininet tests still pass.
Should probably consult Alexandre though.
Mike.
I think what Rein means is that the unix socket fd backing the windows socket handle is always non-blocking - and if he is, he may be correct:
http://source.winehq.org/source/server/sock.c#L578 && http://source.winehq.org/source/server/sock.c#L663
That's true, but it depends on whether the blocking state is transferred across a dup() call. The file descriptor used in a dll comes from wine_server_handle_to_fd: http://source.winehq.org/source/dlls/ntdll/server.c#L635
I confess I don't know whether it is. But the existence of the do_blocking call strongly implies that it is, doesn't it? --Juan
On Thu, Jul 23, 2009 at 10:28 PM, Juan Langjuan.lang@gmail.com wrote:
I think what Rein means is that the unix socket fd backing the windows socket handle is always non-blocking - and if he is, he may be correct:
http://source.winehq.org/source/server/sock.c#L578 && http://source.winehq.org/source/server/sock.c#L663
That's true, but it depends on whether the blocking state is transferred across a dup() call. The file descriptor used in a dll comes from wine_server_handle_to_fd: http://source.winehq.org/source/dlls/ntdll/server.c#L635
I confess I don't know whether it is. But the existence of the do_blocking call strongly implies that it is, doesn't it? --Juan
It definitely seems that way. Also, if the blocking state is not transferred then those fcntl's wouldn't have any effect and hence we wouldn't have the bug. But I agree with you that the documentation is incredibly vague (what is "state"?) with regards to what the implemented behavior should be. It seems it is just a hard link for handles. Besides if the state is not transferred, those fcntl's wouldn't have any effect as the duped socket is closed when released.
Rein, I think you can safely make a patch for this bug. In the worst case Alexandre will just not take it. ;)
Mike.
Responding to all your comments:
On Fri, 24 Jul 2009 00:02:01 -0400, you wrote:
On Thu, Jul 23, 2009 at 10:28 PM, Juan Langjuan.lang@gmail.com wrote:
I think what Rein means is that the unix socket fd backing the windows socket handle is always non-blocking - and if he is, he may be correct:
Yes, that is exactly what I meant.
http://source.winehq.org/source/server/sock.c#L578 && http://source.winehq.org/source/server/sock.c#L663
That's true, but it depends on whether the blocking state is transferred across a dup() call. The file descriptor used in a dll comes from wine_server_handle_to_fd: http://source.winehq.org/source/dlls/ntdll/server.c#L635
I confess I don't know whether it is. But the existence of the do_blocking call strongly implies that it is, doesn't it? --Juan
AFAIK, the only flag that is not preserved across a dup call is the close-on-exit flag.
It definitely seems that way. Also, if the blocking state is not transferred then those fcntl's wouldn't have any effect and hence we wouldn't have the bug. But I agree with you that the documentation is incredibly vague (what is "state"?) with regards to what the implemented behavior should be. It seems it is just a hard link for handles. Besides if the state is not transferred, those fcntl's wouldn't have any effect as the duped socket is closed when released.
I think it is agreed that the socket code in wine is not entirely consistent in this respect.
Rein, I think you can safely make a patch for this bug. In the worst case Alexandre will just not take it. ;)
I am used to that, I think I will.
Thank you both for your thoughts.
Rein.