From 79ee8c1c814a156a9460dff29e77f83d7dd8d875 Mon Sep 17 00:00:00 2001 From: "Peter S. May" Date: Thu, 23 Apr 2015 12:50:28 -0400 Subject: [PATCH] Block+timeout CanRead/CanWrite/DataAvailable EzSockets methods. A minor change to the code exposes the timeout parameter of `select()`, which was already in use for CanRead()/CanWrite(). The timeout parameter is used to block the current thread until data (for read) or space (for write) is available on the underlying socket. A timeout of 0 suppresses any blocking (the original methods fix the timeout to 0). The timeout value is supplied in milliseconds as an `unsigned int`; this is converted internally to the equivalent `timeval`. An in-progress addition to my SextetStream input driver is implemented with non-blocking reads on a TCP socket. Without the block+timeout functionality, it must busy-wait for new input. Changing the reads to blocking works during a game but can cause the program to hang when exiting. The changes in this commit provide a solution to both issues without disrupting any existing code. --- src/ezsockets.cpp | 46 ++++++++++++++++++++++++++++++++++++++++------ src/ezsockets.h | 3 +++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/ezsockets.cpp b/src/ezsockets.cpp index 5b3bc56423..18a4d8ee3e 100644 --- a/src/ezsockets.cpp +++ b/src/ezsockets.cpp @@ -33,6 +33,16 @@ #define INVALID_SOCKET -1 #endif +// Returns a timeval set to the given number of milliseconds. +inline timeval timevalFromMs(unsigned int ms) +{ + timeval tv; + tv.tv_sec = ms / 1000; + tv.tv_usec = (ms % 1000) * 1000; + return tv; +} + + EzSockets::EzSockets() { MAXCON = 5; @@ -185,12 +195,24 @@ bool EzSockets::connect(const std::string& host, unsigned short port) return true; } +inline bool checkCanRead(int sock, timeval& timeout) +{ + fd_set fds; + FD_ZERO(&fds); + FD_SET((unsigned)sock, &fds); + + return select(sock+1, &fds, NULL, NULL, &timeout) > 0; +} + bool EzSockets::CanRead() { - FD_ZERO(scks); - FD_SET((unsigned)sock, scks); + return checkCanRead(sock, *times); +} - return select(sock+1,scks,NULL,NULL,times) > 0; +bool EzSockets::CanRead(unsigned int msTimeout) +{ + timeval tv = timevalFromMs(msTimeout); + return checkCanRead(sock, tv); } bool EzSockets::IsError() @@ -208,12 +230,24 @@ bool EzSockets::IsError() return true; } +inline bool checkCanWrite(int sock, timeval& timeout) +{ + fd_set fds; + FD_ZERO(&fds); + FD_SET((unsigned)sock, &fds); + + return select(sock+1, NULL, &fds, NULL, &timeout) > 0; +} + bool EzSockets::CanWrite() { - FD_ZERO(scks); - FD_SET((unsigned)sock, scks); + return checkCanWrite(sock, *times); +} - return select(sock+1, NULL, scks, NULL, times) > 0; +bool EzSockets::CanWrite(unsigned int msTimeout) +{ + timeval tv = timevalFromMs(msTimeout); + return checkCanWrite(sock, tv); } void EzSockets::update() diff --git a/src/ezsockets.h b/src/ezsockets.h index 6e90313d67..a679cd4e94 100644 --- a/src/ezsockets.h +++ b/src/ezsockets.h @@ -60,9 +60,12 @@ public: long uAddr(); bool CanRead(); + bool CanRead(unsigned int msTimeout); bool DataAvailable() { return ( ( inBuffer.length()>0 ) || CanRead() ); } + bool DataAvailable(unsigned int msTimeout) { return ( ( inBuffer.length()>0 ) || CanRead(msTimeout) ); } bool IsError(); bool CanWrite(); + bool CanWrite(unsigned int msTimeout); void update();