xref: /openbmc/sdbusplus/src/async/fdio.cpp (revision 2a12ae12)
1 #include <sdbusplus/async/fdio.hpp>
2 
3 namespace sdbusplus::async
4 {
fdio(context & ctx,int fd)5 fdio::fdio(context& ctx, int fd) : context_ref(ctx), fd(fd)
6 {
7     static auto eventHandler =
8         [](sd_event_source*, int, uint32_t, void* data) noexcept {
9             static_cast<fdio*>(data)->handleEvent();
10             return 0;
11         };
12 
13     try
14     {
15         source = event_loop().add_io(fd, EPOLLIN, eventHandler, this);
16     }
17     catch (...)
18     {
19         throw std::runtime_error("Failed to add fd to event loop");
20     }
21 }
22 
handleEvent()23 void fdio::handleEvent() noexcept
24 {
25     std::unique_lock l{lock};
26     if (complete == nullptr)
27     {
28         return;
29     }
30     auto c = std::exchange(complete, nullptr);
31     l.unlock();
32     c->complete();
33 }
34 
35 namespace fdio_ns
36 {
37 
~fdio_completion()38 fdio_completion::~fdio_completion()
39 {
40     std::unique_lock l{fdioInstance.lock};
41 
42     if (fdioInstance.complete == this)
43     {
44         std::exchange(fdioInstance.complete, nullptr);
45     }
46 }
47 
arm()48 void fdio_completion::arm() noexcept
49 {
50     // Set ourselves as the awaiting Receiver
51     std::unique_lock l{fdioInstance.lock};
52 
53     if (std::exchange(fdioInstance.complete, this) != nullptr)
54     {
55         // We do not support two awaiters; throw exception. Since we are in
56         // a noexcept context this will std::terminate anyhow, which is
57         // approximately the same as 'assert' but with better information.
58         try
59         {
60             throw std::logic_error(
61                 "fdio_completion started with another await already pending!");
62         }
63         catch (...)
64         {
65             std::terminate();
66         }
67     }
68 }
69 
70 } // namespace fdio_ns
71 
72 } // namespace sdbusplus::async
73