mirror of
https://github.com/postgres/postgres.git
synced 2025-11-21 00:42:43 +03:00
Simplify waiting logic in reading from / writing to client.
The client socket is always in non-blocking mode, and if we actually want blocking behaviour, we emulate it by sleeping and retrying. But we have retry loops at different layers for reads and writes, which was confusing. To simplify, remove all the sleeping and retrying code from the lower levels, from be_tls_read and secure_raw_read and secure_raw_write, and put all the logic in secure_read() and secure_write().
This commit is contained in:
@@ -127,30 +127,45 @@ ssize_t
|
||||
secure_read(Port *port, void *ptr, size_t len)
|
||||
{
|
||||
ssize_t n;
|
||||
int waitfor;
|
||||
|
||||
retry:
|
||||
#ifdef USE_SSL
|
||||
waitfor = 0;
|
||||
if (port->ssl_in_use)
|
||||
{
|
||||
n = be_tls_read(port, ptr, len);
|
||||
n = be_tls_read(port, ptr, len, &waitfor);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
n = secure_raw_read(port, ptr, len);
|
||||
waitfor = WL_SOCKET_READABLE;
|
||||
}
|
||||
|
||||
/* retry after processing interrupts */
|
||||
if (n < 0 && errno == EINTR)
|
||||
/* In blocking mode, wait until the socket is ready */
|
||||
if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
|
||||
{
|
||||
/*
|
||||
* We tried to read data, the socket was empty, and we were
|
||||
* interrupted while waiting for readability. We only process
|
||||
* interrupts if we got interrupted while reading and when in blocking
|
||||
* mode. In other cases it's better to allow the interrupts to be
|
||||
* handled at higher layers.
|
||||
*/
|
||||
ProcessClientReadInterrupt(!port->noblock); /* preserves errno */
|
||||
int w;
|
||||
|
||||
Assert(waitfor);
|
||||
|
||||
w = WaitLatchOrSocket(MyLatch,
|
||||
WL_LATCH_SET | waitfor,
|
||||
port->sock, 0);
|
||||
|
||||
/* Handle interrupt. */
|
||||
if (w & WL_LATCH_SET)
|
||||
{
|
||||
ResetLatch(MyLatch);
|
||||
ProcessClientReadInterrupt(true);
|
||||
|
||||
/*
|
||||
* We'll retry the read. Most likely it will return immediately
|
||||
* because there's still no data available, and we'll wait
|
||||
* for the socket to become ready again.
|
||||
*/
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
@@ -173,7 +188,6 @@ secure_raw_read(Port *port, void *ptr, size_t len)
|
||||
* Try to read from the socket without blocking. If it succeeds we're
|
||||
* done, otherwise we'll wait for the socket using the latch mechanism.
|
||||
*/
|
||||
rloop:
|
||||
#ifdef WIN32
|
||||
pgwin32_noblock = true;
|
||||
#endif
|
||||
@@ -182,37 +196,6 @@ rloop:
|
||||
pgwin32_noblock = false;
|
||||
#endif
|
||||
|
||||
if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
|
||||
{
|
||||
int w;
|
||||
int save_errno = errno;
|
||||
|
||||
w = WaitLatchOrSocket(MyLatch,
|
||||
WL_LATCH_SET | WL_SOCKET_READABLE,
|
||||
port->sock, 0);
|
||||
|
||||
if (w & WL_LATCH_SET)
|
||||
{
|
||||
ResetLatch(MyLatch);
|
||||
/*
|
||||
* Force a return, so interrupts can be processed when not
|
||||
* (possibly) underneath a ssl library.
|
||||
*/
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
else if (w & WL_SOCKET_READABLE)
|
||||
{
|
||||
goto rloop;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore errno, clobbered by WaitLatchOrSocket, so the caller can
|
||||
* react properly.
|
||||
*/
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -224,33 +207,54 @@ ssize_t
|
||||
secure_write(Port *port, void *ptr, size_t len)
|
||||
{
|
||||
ssize_t n;
|
||||
int waitfor;
|
||||
|
||||
retry:
|
||||
waitfor = 0;
|
||||
#ifdef USE_SSL
|
||||
if (port->ssl_in_use)
|
||||
{
|
||||
n = be_tls_write(port, ptr, len);
|
||||
n = be_tls_write(port, ptr, len, &waitfor);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
n = secure_raw_write(port, ptr, len);
|
||||
waitfor = WL_SOCKET_WRITEABLE;
|
||||
}
|
||||
|
||||
/* retry after processing interrupts */
|
||||
if (n < 0 && errno == EINTR)
|
||||
if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
|
||||
{
|
||||
/*
|
||||
* We tried to send data, the socket was full, and we were interrupted
|
||||
* while waiting for writability. We only process interrupts if we got
|
||||
* interrupted while writing and when in blocking mode. In other cases
|
||||
* it's better to allow the interrupts to be handled at higher layers.
|
||||
*/
|
||||
ProcessClientWriteInterrupt(!port->noblock);
|
||||
int w;
|
||||
|
||||
Assert(waitfor);
|
||||
|
||||
w = WaitLatchOrSocket(MyLatch,
|
||||
WL_LATCH_SET | waitfor,
|
||||
port->sock, 0);
|
||||
|
||||
/* Handle interrupt. */
|
||||
if (w & WL_LATCH_SET)
|
||||
{
|
||||
ResetLatch(MyLatch);
|
||||
ProcessClientWriteInterrupt(true);
|
||||
|
||||
/*
|
||||
* We'll retry the write. Most likely it will return immediately
|
||||
* because there's still no data available, and we'll wait
|
||||
* for the socket to become ready again.
|
||||
*/
|
||||
}
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process interrupts that happened while (or before) sending. Note that
|
||||
* we signal that we're not blocking, which will prevent some types of
|
||||
* interrupts from being processed.
|
||||
*/
|
||||
ProcessClientWriteInterrupt(false);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
@@ -259,8 +263,6 @@ secure_raw_write(Port *port, const void *ptr, size_t len)
|
||||
{
|
||||
ssize_t n;
|
||||
|
||||
wloop:
|
||||
|
||||
#ifdef WIN32
|
||||
pgwin32_noblock = true;
|
||||
#endif
|
||||
@@ -269,36 +271,5 @@ wloop:
|
||||
pgwin32_noblock = false;
|
||||
#endif
|
||||
|
||||
if (n < 0 && !port->noblock && (errno == EWOULDBLOCK || errno == EAGAIN))
|
||||
{
|
||||
int w;
|
||||
int save_errno = errno;
|
||||
|
||||
w = WaitLatchOrSocket(MyLatch,
|
||||
WL_LATCH_SET | WL_SOCKET_WRITEABLE,
|
||||
port->sock, 0);
|
||||
|
||||
if (w & WL_LATCH_SET)
|
||||
{
|
||||
ResetLatch(MyLatch);
|
||||
/*
|
||||
* Force a return, so interrupts can be processed when not
|
||||
* (possibly) underneath a ssl library.
|
||||
*/
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
else if (w & WL_SOCKET_WRITEABLE)
|
||||
{
|
||||
goto wloop;
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore errno, clobbered by WaitLatchOrSocket, so the caller can
|
||||
* react properly.
|
||||
*/
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user