Skip to content

Commit 47df6e7

Browse files
committed
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
1 parent efa0e86 commit 47df6e7

File tree

1 file changed

+81
-25
lines changed

1 file changed

+81
-25
lines changed

src/backend/port/win32/socket.c

Lines changed: 81 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
77
*
88
* IDENTIFICATION
9-
* $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.13 2006/10/04 00:29:56 momjian Exp $
9+
* $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.14 2006/10/13 13:59:47 teodor Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -102,11 +102,23 @@ pgwin32_poll_signals(void)
102102
return 0;
103103
}
104104

105+
static int
106+
isDataGram(SOCKET s) {
107+
int type;
108+
int typelen = sizeof(type);
109+
110+
if ( getsockopt(s, SOL_SOCKET, SO_TYPE, (char*)&type, &typelen) )
111+
return 1;
112+
113+
return ( type == SOCK_DGRAM ) ? 1 : 0;
114+
}
115+
105116
int
106117
pgwin32_waitforsinglesocket(SOCKET s, int what)
107118
{
108119
static HANDLE waitevent = INVALID_HANDLE_VALUE;
109120
static SOCKET current_socket = -1;
121+
static int isUDP = 0;
110122
HANDLE events[2];
111123
int r;
112124

@@ -127,8 +139,12 @@ pgwin32_waitforsinglesocket(SOCKET s, int what)
127139
* socket from a previous call
128140
*/
129141

130-
if (current_socket != s && current_socket != -1)
131-
WSAEventSelect(current_socket, waitevent, 0);
142+
if (current_socket != s)
143+
{
144+
if ( current_socket != -1 )
145+
WSAEventSelect(current_socket, waitevent, 0);
146+
isUDP = isDataGram(s);
147+
}
132148

133149
current_socket = s;
134150

@@ -140,7 +156,46 @@ pgwin32_waitforsinglesocket(SOCKET s, int what)
140156

141157
events[0] = pgwin32_signal_event;
142158
events[1] = waitevent;
143-
r = WaitForMultipleObjectsEx(2, events, FALSE, INFINITE, TRUE);
159+
160+
/*
161+
* Just a workaround of unknown locking problem with writing
162+
* in UDP socket under high load:
163+
* Client's pgsql backend sleeps infinitely in
164+
* WaitForMultipleObjectsEx, pgstat process sleeps in
165+
* pgwin32_select(). So, we will wait with small
166+
* timeout(0.1 sec) and if sockect is still blocked,
167+
* try WSASend (see comments in pgwin32_select) and wait again.
168+
*/
169+
if ((what & FD_WRITE) && isUDP)
170+
{
171+
for(;;)
172+
{
173+
r = WaitForMultipleObjectsEx(2, events, FALSE, 100, TRUE);
174+
175+
if ( r == WAIT_TIMEOUT )
176+
{
177+
char c;
178+
WSABUF buf;
179+
DWORD sent;
180+
181+
buf.buf = &c;
182+
buf.len = 0;
183+
184+
r = WSASend(s, &buf, 1, &sent, 0, NULL, NULL);
185+
if (r == 0) /* Completed - means things are fine! */
186+
return 1;
187+
else if ( WSAGetLastError() != WSAEWOULDBLOCK )
188+
{
189+
TranslateSocketError();
190+
return 0;
191+
}
192+
}
193+
else
194+
break;
195+
}
196+
}
197+
else
198+
r = WaitForMultipleObjectsEx(2, events, FALSE, INFINITE, TRUE);
144199

145200
if (r == WAIT_OBJECT_0 || r == WAIT_IO_COMPLETION)
146201
{
@@ -280,30 +335,31 @@ pgwin32_send(SOCKET s, char *buf, int len, int flags)
280335
wbuf.len = len;
281336
wbuf.buf = buf;
282337

283-
r = WSASend(s, &wbuf, 1, &b, flags, NULL, NULL);
284-
if (r != SOCKET_ERROR && b > 0)
285-
/* Write succeeded right away */
286-
return b;
287-
288-
if (r == SOCKET_ERROR &&
289-
WSAGetLastError() != WSAEWOULDBLOCK)
290-
{
291-
TranslateSocketError();
292-
return -1;
293-
}
294-
295-
/* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */
338+
/*
339+
* Readiness of socket to send data to UDP socket
340+
* may be not true: socket can become busy again! So loop
341+
* until send or error occurs.
342+
*/
343+
for(;;) {
344+
r = WSASend(s, &wbuf, 1, &b, flags, NULL, NULL);
345+
if (r != SOCKET_ERROR && b > 0)
346+
/* Write succeeded right away */
347+
return b;
348+
349+
if (r == SOCKET_ERROR &&
350+
WSAGetLastError() != WSAEWOULDBLOCK)
351+
{
352+
TranslateSocketError();
353+
return -1;
354+
}
296355

297-
if (pgwin32_waitforsinglesocket(s, FD_WRITE | FD_CLOSE) == 0)
298-
return -1;
356+
/* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */
299357

300-
r = WSASend(s, &wbuf, 1, &b, flags, NULL, NULL);
301-
if (r == SOCKET_ERROR)
302-
{
303-
TranslateSocketError();
304-
return -1;
358+
if (pgwin32_waitforsinglesocket(s, FD_WRITE | FD_CLOSE) == 0)
359+
return -1;
305360
}
306-
return b;
361+
362+
return -1;
307363
}
308364

309365

0 commit comments

Comments
 (0)