Timeout in read and write to a FDStore 17/30517/5
authorJan Olszak <j.olszak@samsung.com>
Wed, 19 Nov 2014 09:28:41 +0000 (10:28 +0100)
committerJan Olszak <j.olszak@samsung.com>
Mon, 24 Nov 2014 13:53:43 +0000 (14:53 +0100)
[Bug/Feature]   N/A
[Cause]         N/A
[Solution]      N/A
[Verification]  Build, install, run tests

Change-Id: I42a358ce87d1dd6e02030a0e0e2431838ddae29c

src/config/fdstore.cpp
src/config/fdstore.hpp

index 050e99f..7934893 100644 (file)
 #include <cstring>
 #include <cerrno>
 #include <unistd.h>
+#include <chrono>
+#include <poll.h>
 
 namespace config {
 
+namespace {
+
+void waitForEvent(int fd,
+                  short event,
+                  const std::chrono::high_resolution_clock::time_point deadline)
+{
+    // Wait for the rest of the data
+    struct pollfd fds[1];
+    fds[0].fd = fd;
+    fds[0].events = event | POLLHUP;
+
+    for (;;) {
+        std::chrono::milliseconds timeoutMS =
+            std::chrono::duration_cast<std::chrono::milliseconds>(deadline - std::chrono::high_resolution_clock::now());
+        if (timeoutMS.count() < 0) {
+            throw ConfigException("Timeout");
+        }
+
+        int ret = ::poll(fds, 1 /*fds size*/, timeoutMS.count());
+
+        if (ret == -1) {
+            if (errno == EINTR) {
+                continue;
+            }
+            throw ConfigException("Error in poll: " + std::string(strerror(errno)));
+        }
+
+        if (ret == 0) {
+            throw ConfigException("Timeout");
+        }
+
+        if (fds[0].revents & POLLHUP) {
+            throw ConfigException("Peer disconnected");
+        }
+
+        // Here Comes the Sun
+        break;
+    }
+}
+
+} // namespace
 
 FDStore::FDStore(int fd)
     : mFD(fd)
@@ -48,42 +91,57 @@ FDStore::~FDStore()
 {
 }
 
-void FDStore::write(const void* bufferPtr, const size_t size)
+void FDStore::write(const void* bufferPtr, const size_t size, const unsigned int timeoutMS)
 {
+    std::chrono::high_resolution_clock::time_point deadline = std::chrono::high_resolution_clock::now() +
+                                                              std::chrono::milliseconds(timeoutMS);
+
     size_t nTotal = 0;
-    int n;
+    for (;;) {
+        int n  = ::write(mFD,
+                         reinterpret_cast<const char*>(bufferPtr) + nTotal,
+                         size - nTotal);
+        if (n > 0) {
+            nTotal += n;
+        } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+            // Neglected errors
+        } else {
+            throw ConfigException("Error during reading: " + std::string(strerror(errno)));
+        }
 
-    do {
-        n  = ::write(mFD,
-                     reinterpret_cast<const char*>(bufferPtr) + nTotal,
-                     size - nTotal);
-        if (n < 0) {
-            if (errno == EINTR) {
-                continue;
-            }
-            throw ConfigException("Error during witting: " + std::string(strerror(errno)));
+        if (nTotal >= size) {
+            // All data is written, break loop
+            break;
+        } else {
+            waitForEvent(mFD, POLLOUT, deadline);
         }
-        nTotal += n;
-    } while (nTotal < size);
+    }
 }
 
-void FDStore::read(void* bufferPtr, const size_t size)
+void FDStore::read(void* bufferPtr, const size_t size, const unsigned int timeoutMS)
 {
-    size_t nTotal = 0;
-    int n;
+    std::chrono::high_resolution_clock::time_point deadline = std::chrono::high_resolution_clock::now() +
+                                                              std::chrono::milliseconds(timeoutMS);
 
-    do {
-        n  = ::read(mFD,
-                    reinterpret_cast<char*>(bufferPtr) + nTotal,
-                    size - nTotal);
-        if (n < 0) {
-            if (errno == EINTR) {
-                continue;
-            }
+    size_t nTotal = 0;
+    for (;;) {
+        int n  = ::read(mFD,
+                        reinterpret_cast<char*>(bufferPtr) + nTotal,
+                        size - nTotal);
+        if (n > 0) {
+            nTotal += n;
+        } else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+            // Neglected errors
+        } else {
             throw ConfigException("Error during reading: " + std::string(strerror(errno)));
         }
-        nTotal += n;
-    } while (nTotal < size);
-}
 
+        if (nTotal >= size) {
+            // All data is read, break loop
+            break;
+        } else {
+            waitForEvent(mFD, POLLIN, deadline);
+        }
+    }
+}
 } // namespace config
index d99971d..d34ea14 100644 (file)
@@ -48,16 +48,18 @@ public:
      *
      * @param bufferPtr buffer with the data
      * @param size size of the buffer
+     * @param timeoutMS timeout in milliseconds
      */
-    void write(const void* bufferPtr, const size_t size);
+    void write(const void* bufferPtr, const size_t size, const unsigned int timeoutMS = 500);
 
     /**
      * Reads a value of the given type.
      *
      * @param bufferPtr buffer with the data
      * @param size size of the buffer
+     * @param timeoutMS timeout in milliseconds
      */
-    void read(void* bufferPtr, const size_t size);
+    void read(void* bufferPtr, const size_t size, const unsigned int timeoutMS = 500);
 
 private:
     int mFD;