From d3ef8de5e99b03763ef2ddc9c6dd735f8c0a442b Mon Sep 17 00:00:00 2001 From: Mitchell Wills Date: Tue, 4 Mar 2014 16:00:04 -0500 Subject: [PATCH] Applied patch from Dustin Spicuzza to fix robot hang Change-Id: I273feafcad5c95de04a11bab64c2d5596f248662 --- .../networktables2/stream/FDIOStream.cpp | 44 +++++++++++++++---- .../networktables2/stream/FDIOStream.cpp | 44 +++++++++++++++---- .../networktables2/stream/FDIOStream.cpp | 43 +++++++++++++++--- .../networktables2/NetworkTableEntry.h | 1 + .../networktables2/NetworkTableEntry.cpp | 11 +++++ .../native/networktables2/WriteManager.cpp | 30 +++++++++---- 6 files changed, 142 insertions(+), 31 deletions(-) diff --git a/networktables/cpp/Athena/src/main/native/networktables2/stream/FDIOStream.cpp b/networktables/cpp/Athena/src/main/native/networktables2/stream/FDIOStream.cpp index 74fca50736..107e19593c 100644 --- a/networktables/cpp/Athena/src/main/native/networktables2/stream/FDIOStream.cpp +++ b/networktables/cpp/Athena/src/main/native/networktables2/stream/FDIOStream.cpp @@ -24,6 +24,13 @@ FDIOStream::FDIOStream(int _fd){ // f = fdopen(_fd, "rbwb"); // if(f==NULL) // throw IOException("Could not open stream from file descriptor", errno); + // Set the TCP socket to be non-blocking + int flags = fcntl(fd, F_GETFL, 0); + if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) + { + ::close(fd); + throw IOException("Could not set socket to non-blocking mode"); + } } FDIOStream::~FDIOStream(){ close(); @@ -66,14 +73,35 @@ int FDIOStream::read(void* ptr, int numbytes){ return totalRead; } int FDIOStream::write(const void* ptr, int numbytes){ - int numWrote = ::write(fd, (char*)ptr, numbytes);//TODO: this is bad - //int numWrote = fwrite(ptr, 1, numbytes, f); - if(numWrote==numbytes) - return numWrote; - perror("write error: "); - fflush(stderr); - throw IOException("Could not write all bytes to fd stream"); - + int numWrote = ::write(fd, (char*)ptr, numbytes); + if(numWrote==numbytes) + return numWrote; + + if (numWrote == -1 && (errno == EWOULDBLOCK || errno == EAGAIN)) + { + // see if write timeout expires + struct timeval timeout; + fd_set fdSet; + + FD_ZERO(&fdSet); + FD_SET(fd, &fdSet); + timeout.tv_sec = 1; // wait 1 second for the other side to connect + timeout.tv_usec = 0; + + int select_result = select(FD_SETSIZE, NULL, &fdSet, NULL, &timeout); + if ( select_result < 0) + throw IOException("Select returned an error on write"); + + if (FD_ISSET(fd, &fdSet)) { + numWrote = ::write(fd, (char*)ptr, numbytes); + if(numWrote==numbytes) + return numWrote; + } + } + + perror("write error: "); + fflush(stderr); + throw IOException("Could not write all bytes to fd stream"); } void FDIOStream::flush(){ //if(fflush(f)==EOF) diff --git a/networktables/cpp/Azalea/src/main/native/networktables2/stream/FDIOStream.cpp b/networktables/cpp/Azalea/src/main/native/networktables2/stream/FDIOStream.cpp index d0dd657c9b..f62b819b6b 100644 --- a/networktables/cpp/Azalea/src/main/native/networktables2/stream/FDIOStream.cpp +++ b/networktables/cpp/Azalea/src/main/native/networktables2/stream/FDIOStream.cpp @@ -22,6 +22,13 @@ FDIOStream::FDIOStream(int _fd){ // f = fdopen(_fd, "rbwb"); // if(f==NULL) // throw IOException("Could not open stream from file descriptor", errno); + // Set the TCP socket to be non-blocking + int on = 1; + if (ioctl(fd, FIONBIO, (char*)&on) < 0) + { + ::close(fd); + throw IOException("Could not set socket to non-blocking mode"); + } } FDIOStream::~FDIOStream(){ close(); @@ -64,14 +71,35 @@ int FDIOStream::read(void* ptr, int numbytes){ return totalRead; } int FDIOStream::write(const void* ptr, int numbytes){ - int numWrote = ::write(fd, (char*)ptr, numbytes);//TODO: this is bad - //int numWrote = fwrite(ptr, 1, numbytes, f); - if(numWrote==numbytes) - return numWrote; - perror("write error: "); - fflush(stderr); - throw IOException("Could not write all bytes to fd stream"); - + int numWrote = ::write(fd, (char*)ptr, numbytes); + if(numWrote==numbytes) + return numWrote; + + if (numWrote == -1 && (errno == EWOULDBLOCK || errno == EAGAIN)) + { + // see if write timeout expires + struct timeval timeout; + fd_set fdSet; + + FD_ZERO(&fdSet); + FD_SET(fd, &fdSet); + timeout.tv_sec = 1; // wait 1 second for the other side to connect + timeout.tv_usec = 0; + + int select_result = select(FD_SETSIZE, NULL, &fdSet, NULL, &timeout); + if ( select_result < 0) + throw IOException("Select returned an error on write"); + + if (FD_ISSET(fd, &fdSet)) { + numWrote = ::write(fd, (char*)ptr, numbytes); + if(numWrote==numbytes) + return numWrote; + } + } + + perror("write error: "); + fflush(stderr); + throw IOException("Could not write all bytes to fd stream"); } void FDIOStream::flush(){ //if(fflush(f)==EOF) diff --git a/networktables/cpp/Win32/src/main/native/networktables2/stream/FDIOStream.cpp b/networktables/cpp/Win32/src/main/native/networktables2/stream/FDIOStream.cpp index f1868ba330..0e8d23cf55 100644 --- a/networktables/cpp/Win32/src/main/native/networktables2/stream/FDIOStream.cpp +++ b/networktables/cpp/Win32/src/main/native/networktables2/stream/FDIOStream.cpp @@ -20,6 +20,13 @@ FDIOStream::FDIOStream(int _fd){ fd = _fd; + // Set the TCP socket to be non-blocking + u_long on = 1; + if (ioctlsocket(fd, FIONBIO, &on)) + { + ::close(fd); + throw IOException("Could not set socket to non-blocking mode"); + } } FDIOStream::~FDIOStream(){ @@ -79,13 +86,35 @@ int Send( int sockfd,char* Data, size_t sizeData ) int FDIOStream::write(const void* ptr, int numbytes) { - int numWrote = Send(fd,(char *)ptr,numbytes); - if(numWrote==numbytes) - return numWrote; - perror("write error: "); - fflush(stderr); - throw IOException("Could not write all bytes to fd stream"); - + int numWrote = ::write(fd, (char*)ptr, numbytes); + if(numWrote==numbytes) + return numWrote; + + if (numWrote == -1 && (errno == EWOULDBLOCK || errno == EAGAIN)) + { + // see if write timeout expires + struct timeval timeout; + fd_set fdSet; + + FD_ZERO(&fdSet); + FD_SET(fd, &fdSet); + timeout.tv_sec = 1; // wait 1 second for the other side to connect + timeout.tv_usec = 0; + + int select_result = select(FD_SETSIZE, NULL, &fdSet, NULL, &timeout); + if ( select_result < 0) + throw IOException("Select returned an error on write"); + + if (FD_ISSET(fd, &fdSet)) { + numWrote = ::write(fd, (char*)ptr, numbytes); + if(numWrote==numbytes) + return numWrote; + } + } + + perror("write error: "); + fflush(stderr); + throw IOException("Could not write all bytes to fd stream"); } void FDIOStream::flush(){ diff --git a/networktables/cpp/include/src/main/include/networktables2/NetworkTableEntry.h b/networktables/cpp/include/src/main/include/networktables2/NetworkTableEntry.h index 2a2900435e..27223e4c53 100644 --- a/networktables/cpp/include/src/main/include/networktables2/NetworkTableEntry.h +++ b/networktables/cpp/include/src/main/include/networktables2/NetworkTableEntry.h @@ -42,6 +42,7 @@ public: NetworkTableEntry(std::string& name, NetworkTableEntryType* type, EntryValue value); NetworkTableEntry(EntryId id, std::string& name, SequenceNumber sequenceNumber, NetworkTableEntryType* type, EntryValue value); + NetworkTableEntry(const NetworkTableEntry &); virtual ~NetworkTableEntry(); EntryId GetId(); diff --git a/networktables/cpp/parent/src/main/native/networktables2/NetworkTableEntry.cpp b/networktables/cpp/parent/src/main/native/networktables2/NetworkTableEntry.cpp index 9538c91df6..658c7c7a85 100644 --- a/networktables/cpp/parent/src/main/native/networktables2/NetworkTableEntry.cpp +++ b/networktables/cpp/parent/src/main/native/networktables2/NetworkTableEntry.cpp @@ -20,6 +20,17 @@ NetworkTableEntry::NetworkTableEntry(EntryId _id, std::string& _name, SequenceNu m_isDirty = false; } +NetworkTableEntry::NetworkTableEntry(const NetworkTableEntry &other) : + name(other.name), + id(other.id), + sequenceNumber(other.sequenceNumber), + type(other.type), + m_isNew(other.m_isNew), + m_isDirty(other.m_isDirty) +{ + value = type->copyValue(other.value); +} + NetworkTableEntry::~NetworkTableEntry(){ type->deleteValue(value); } diff --git a/networktables/cpp/parent/src/main/native/networktables2/WriteManager.cpp b/networktables/cpp/parent/src/main/native/networktables2/WriteManager.cpp index bbe08f504d..c8eb8fee46 100644 --- a/networktables/cpp/parent/src/main/native/networktables2/WriteManager.cpp +++ b/networktables/cpp/parent/src/main/native/networktables2/WriteManager.cpp @@ -97,10 +97,17 @@ void WriteManager::run() { entry = ((std::queue*)outgoingAssignmentQueue)->front(); ((std::queue*)outgoingAssignmentQueue)->pop(); { - NTSynchronized sync(entryStore.LOCK); - entry->MakeClean(); - wrote = true; - receiver.offerOutgoingAssignment(entry); + NetworkTableEntry * entryCopy; + + { + NTSynchronized sync(entryStore.LOCK); + entry->MakeClean(); + wrote = true; + entryCopy = new NetworkTableEntry(*entry); + } + + receiver.offerOutgoingAssignment(entryCopy); + delete entryCopy; } } @@ -108,10 +115,17 @@ void WriteManager::run() { entry = ((std::queue*)outgoingUpdateQueue)->front(); ((std::queue*)outgoingUpdateQueue)->pop(); { - NTSynchronized sync(entryStore.LOCK); - entry->MakeClean(); - wrote = true; - receiver.offerOutgoingUpdate(entry); + NetworkTableEntry * entryCopy; + + { + NTSynchronized sync(entryStore.LOCK); + entry->MakeClean(); + wrote = true; + entryCopy = new NetworkTableEntry(*entry); + } + + receiver.offerOutgoingUpdate(entryCopy); + delete entryCopy; } }