add support for timed fdio

For certain operations such as reading and writing to a fd for request
response flows, the fd needs to have a timeout to avoid everlasting
hangs in case of a unresponsive responder. To support this, the fdio has
been extended to add timeout support by throwing an exception in case of
timeout.

Tested: Unit Test
```
1/1 test_async_fdio_timed OK             10.03s

Ok:                 1
Expected Fail:      0
Fail:               0
Unexpected Pass:    0
Skipped:            0
Timeout:            0
```

Change-Id: Ib219e4a4c55125785e6c1571488e445ba3379244
Signed-off-by: Jagpal Singh Gill <paligill@gmail.com>
diff --git a/src/async/fdio.cpp b/src/async/fdio.cpp
index e1c3ddc..94c79d1 100644
--- a/src/async/fdio.cpp
+++ b/src/async/fdio.cpp
@@ -2,7 +2,9 @@
 
 namespace sdbusplus::async
 {
-fdio::fdio(context& ctx, int fd) : context_ref(ctx)
+fdio::fdio(context& ctx, int fd, std::chrono::microseconds timeout) :
+    context_ref(ctx),
+    timeout(std::chrono::duration_cast<event_t::time_resolution>(timeout))
 {
     static auto eventHandler =
         [](sd_event_source*, int, uint32_t, void* data) noexcept {
@@ -32,6 +34,18 @@
     c->complete();
 }
 
+void fdio::handleTimeout() noexcept
+{
+    std::unique_lock l{lock};
+    if (complete == nullptr)
+    {
+        return;
+    }
+    auto c = std::exchange(complete, nullptr);
+    l.unlock();
+    c->error(std::make_exception_ptr(fdio_timeout_exception()));
+}
+
 namespace fdio_ns
 {
 
@@ -65,6 +79,28 @@
             std::terminate();
         }
     }
+
+    l.unlock();
+
+    // Schedule the timeout
+    if (fdioInstance.timeout != event_t::time_resolution::zero())
+    {
+        static auto eventHandler =
+            [](sd_event_source*, uint64_t, void* data) noexcept {
+                static_cast<fdio*>(data)->handleTimeout();
+                return 0;
+            };
+
+        try
+        {
+            source = fdioInstance.event_loop().add_oneshot_timer(
+                eventHandler, &fdioInstance, fdioInstance.timeout);
+        }
+        catch (...)
+        {
+            error(std::current_exception());
+        }
+    }
 }
 
 } // namespace fdio_ns