From 47df6e7e2d754c6330e85d247987352f0a25e60a Mon Sep 17 00:00:00 2001 From: Teodor Sigaev Date: Fri, 13 Oct 2006 13:59:47 +0000 Subject: [PATCH] Fix infinite sleep and failes of send in Win32. 1) pgwin32_waitforsinglesocket(): WaitForMultipleObjectsEx now called with finite timeout (100ms) in case of FP_WRITE and UDP socket. If timeout occurs then pgwin32_waitforsinglesocket() tries to write empty packet goes to WaitForMultipleObjectsEx again. 2) pgwin32_send(): add loop around WSASend and pgwin32_waitforsinglesocket(). The reason is: for overlapped socket, 'ok' result from pgwin32_waitforsinglesocket() isn't guarantee that socket is still free, it can become busy again and following WSASend call will fail with WSAEWOULDBLOCK error. See http://archives.postgresql.org/pgsql-hackers/2006-10/msg00561.php --- src/backend/port/win32/socket.c | 106 ++++++++++++++++++++++++-------- 1 file changed, 81 insertions(+), 25 deletions(-) diff --git a/src/backend/port/win32/socket.c b/src/backend/port/win32/socket.c index 47bb0d9cb8..6489c64dae 100644 --- a/src/backend/port/win32/socket.c +++ b/src/backend/port/win32/socket.c @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.13 2006/10/04 00:29:56 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.14 2006/10/13 13:59:47 teodor Exp $ * *------------------------------------------------------------------------- */ @@ -102,11 +102,23 @@ pgwin32_poll_signals(void) return 0; } +static int +isDataGram(SOCKET s) { + int type; + int typelen = sizeof(type); + + if ( getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&type, &typelen) ) + return 1; + + return ( type == SOCK_DGRAM ) ? 1 : 0; +} + int pgwin32_waitforsinglesocket(SOCKET s, int what) { static HANDLE waitevent = INVALID_HANDLE_VALUE; static SOCKET current_socket = -1; + static int isUDP = 0; HANDLE events[2]; int r; @@ -127,8 +139,12 @@ pgwin32_waitforsinglesocket(SOCKET s, int what) * socket from a previous call */ - if (current_socket != s && current_socket != -1) - WSAEventSelect(current_socket, waitevent, 0); + if (current_socket != s) + { + if ( current_socket != -1 ) + WSAEventSelect(current_socket, waitevent, 0); + isUDP = isDataGram(s); + } current_socket = s; @@ -140,7 +156,46 @@ pgwin32_waitforsinglesocket(SOCKET s, int what) events[0] = pgwin32_signal_event; events[1] = waitevent; - r = WaitForMultipleObjectsEx(2, events, FALSE, INFINITE, TRUE); + + /* + * Just a workaround of unknown locking problem with writing + * in UDP socket under high load: + * Client's pgsql backend sleeps infinitely in + * WaitForMultipleObjectsEx, pgstat process sleeps in + * pgwin32_select(). So, we will wait with small + * timeout(0.1 sec) and if sockect is still blocked, + * try WSASend (see comments in pgwin32_select) and wait again. + */ + if ((what & FD_WRITE) && isUDP) + { + for(;;) + { + r = WaitForMultipleObjectsEx(2, events, FALSE, 100, TRUE); + + if ( r == WAIT_TIMEOUT ) + { + char c; + WSABUF buf; + DWORD sent; + + buf.buf = &c; + buf.len = 0; + + r = WSASend(s, &buf, 1, &sent, 0, NULL, NULL); + if (r == 0) /* Completed - means things are fine! */ + return 1; + else if ( WSAGetLastError() != WSAEWOULDBLOCK ) + { + TranslateSocketError(); + return 0; + } + } + else + break; + } + } + else + r = WaitForMultipleObjectsEx(2, events, FALSE, INFINITE, TRUE); if (r == WAIT_OBJECT_0 || r == WAIT_IO_COMPLETION) { @@ -280,30 +335,31 @@ pgwin32_send(SOCKET s, char *buf, int len, int flags) wbuf.len = len; wbuf.buf = buf; - r = WSASend(s, &wbuf, 1, &b, flags, NULL, NULL); - if (r != SOCKET_ERROR && b > 0) - /* Write succeeded right away */ - return b; - - if (r == SOCKET_ERROR && - WSAGetLastError() != WSAEWOULDBLOCK) - { - TranslateSocketError(); - return -1; - } - - /* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */ + /* + * Readiness of socket to send data to UDP socket + * may be not true: socket can become busy again! So loop + * until send or error occurs. + */ + for(;;) { + r = WSASend(s, &wbuf, 1, &b, flags, NULL, NULL); + if (r != SOCKET_ERROR && b > 0) + /* Write succeeded right away */ + return b; + + if (r == SOCKET_ERROR && + WSAGetLastError() != WSAEWOULDBLOCK) + { + TranslateSocketError(); + return -1; + } - if (pgwin32_waitforsinglesocket(s, FD_WRITE | FD_CLOSE) == 0) - return -1; + /* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */ - r = WSASend(s, &wbuf, 1, &b, flags, NULL, NULL); - if (r == SOCKET_ERROR) - { - TranslateSocketError(); - return -1; + if (pgwin32_waitforsinglesocket(s, FD_WRITE | FD_CLOSE) == 0) + return -1; } - return b; + + return -1; } -- 2.40.0