From 215cbc90f8db3fc8a70af5572b156f49216c2f70 Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Tue, 16 Feb 2010 19:26:02 +0000 Subject: [PATCH] Add emulation of non-blocking sockets to the win32 socket/signal layer, and use this in pq_getbyte_if_available. It's only a limited implementation which swithes the whole emulation layer no non-blocking mode, but that's enough as long as non-blocking is only used during a short period of time, and only one socket is accessed during this time. --- src/backend/libpq/pqcomm.c | 14 +++++++++++++- src/backend/port/win32/socket.c | 25 ++++++++++++++++++++++++- src/include/port/win32.h | 4 +++- 3 files changed, 40 insertions(+), 3 deletions(-) diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c index f4e6974252..8f40c93d89 100644 --- a/src/backend/libpq/pqcomm.c +++ b/src/backend/libpq/pqcomm.c @@ -30,7 +30,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.202 2010/01/15 09:19:02 heikki Exp $ + * $PostgreSQL: pgsql/src/backend/libpq/pqcomm.c,v 1.203 2010/02/16 19:26:02 mha Exp $ * *------------------------------------------------------------------------- */ @@ -837,9 +837,13 @@ pq_getbyte_if_available(unsigned char *c) } /* Temporarily put the socket into non-blocking mode */ +#ifdef WIN32 + pgwin32_noblock = 1; +#else if (!pg_set_noblock(MyProcPort->sock)) ereport(ERROR, (errmsg("couldn't put socket to non-blocking mode: %m"))); +#endif MyProcPort->noblock = true; PG_TRY(); { @@ -851,16 +855,24 @@ pq_getbyte_if_available(unsigned char *c) * The rest of the backend code assumes the socket is in blocking * mode, so treat failure as FATAL. */ +#ifdef WIN32 + pgwin32_noblock = 0; +#else if (!pg_set_block(MyProcPort->sock)) ereport(FATAL, (errmsg("couldn't put socket to blocking mode: %m"))); +#endif MyProcPort->noblock = false; PG_RE_THROW(); } PG_END_TRY(); +#ifdef WIN32 + pgwin32_noblock = 0; +#else if (!pg_set_block(MyProcPort->sock)) ereport(FATAL, (errmsg("couldn't put socket to blocking mode: %m"))); +#endif MyProcPort->noblock = false; return r; diff --git a/src/backend/port/win32/socket.c b/src/backend/port/win32/socket.c index 8076b8caef..af42576cab 100644 --- a/src/backend/port/win32/socket.c +++ b/src/backend/port/win32/socket.c @@ -6,13 +6,26 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.23 2010/01/02 16:57:50 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/port/win32/socket.c,v 1.24 2010/02/16 19:26:02 mha Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +/* + * Indicate if pgwin32_recv() should operate in non-blocking mode. + * + * Since the socket emulation layer always sets the actual socket to + * non-blocking mode in order to be able to deliver signals, we must + * specify this in a separate flag if we actually need non-blocking + * operation. + * + * This flag changes the behaviour *globally* for all socket operations, + * so it should only be set for very short periods of time. + */ +int pgwin32_noblock = 0; + #undef socket #undef accept #undef connect @@ -310,6 +323,16 @@ pgwin32_recv(SOCKET s, char *buf, int len, int f) return -1; } + if (pgwin32_noblock) + { + /* + * No data received, and we are in "emulated non-blocking mode", so return + * indicating thta we'd block if we were to continue. + */ + errno = EWOULDBLOCK; + return -1; + } + /* No error, zero bytes (win2000+) or error+WSAEWOULDBLOCK (<=nt4) */ for (n = 0; n < 5; n++) diff --git a/src/include/port/win32.h b/src/include/port/win32.h index 3ec81c4f7e..6dbda80f4f 100644 --- a/src/include/port/win32.h +++ b/src/include/port/win32.h @@ -1,4 +1,4 @@ -/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.92 2010/02/13 02:34:14 tgl Exp $ */ +/* $PostgreSQL: pgsql/src/include/port/win32.h,v 1.93 2010/02/16 19:26:02 mha Exp $ */ #if defined(_MSC_VER) || defined(__BORLANDC__) #define WIN32_ONLY_COMPILER @@ -283,6 +283,8 @@ int pgwin32_send(SOCKET s, char *buf, int len, int flags); const char *pgwin32_socket_strerror(int err); int pgwin32_waitforsinglesocket(SOCKET s, int what, int timeout); +extern int pgwin32_noblock; + /* in backend/port/win32/security.c */ extern int pgwin32_is_admin(void); extern int pgwin32_is_service(void);