1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 #pragma once 17 18 #include <systemd/sd-event.h> 19 20 #include <boost/asio/io_context.hpp> 21 #include <boost/asio/posix/stream_descriptor.hpp> 22 #include <boost/asio/post.hpp> 23 #include <boost/system/error_code.hpp> 24 25 namespace sdbusplus 26 { 27 28 namespace asio 29 { 30 /* A simple class to integrate the sd_event_loop into the boost::asio io_context 31 * in case a boost::asio user needs sd_events 32 */ 33 class sd_event_wrapper 34 { 35 public: 36 sd_event_wrapper(boost::asio::io_context& io) : 37 evt(nullptr), descriptor(io), io(io) 38 { 39 sd_event_default(&evt); 40 if (evt) 41 { 42 descriptor.assign(sd_event_get_fd(evt)); 43 async_run(); 44 } 45 } 46 sd_event_wrapper(sd_event* evt, boost::asio::io_context& io) : 47 evt(evt), descriptor(io), io(io) 48 { 49 if (evt) 50 { 51 sd_event_ref(evt); 52 descriptor.assign(sd_event_get_fd(evt)); 53 async_run(); 54 } 55 } 56 ~sd_event_wrapper() 57 { 58 // sd_event really wants to close the descriptor on its own 59 // so this class must merely release it 60 descriptor.release(); 61 sd_event_unref(evt); 62 } 63 // process one event step in the queue 64 // return true if the queue is still alive 65 void run() 66 { 67 int ret; 68 int state = sd_event_get_state(evt); 69 switch (state) 70 { 71 case SD_EVENT_INITIAL: 72 ret = sd_event_prepare(evt); 73 if (ret > 0) 74 { 75 async_run(); 76 } 77 else if (ret == 0) 78 { 79 async_wait(); 80 } 81 break; 82 case SD_EVENT_ARMED: 83 ret = sd_event_wait(evt, 0); 84 if (ret >= 0) 85 { 86 async_run(); 87 } 88 break; 89 case SD_EVENT_PENDING: 90 ret = sd_event_dispatch(evt); 91 if (ret > 0) 92 { 93 async_run(); 94 } 95 break; 96 case SD_EVENT_FINISHED: 97 break; 98 default: 99 // throw something? 100 // doing nothing will break out of the async loop 101 break; 102 } 103 } 104 sd_event* get() const 105 { 106 return evt; 107 } 108 109 private: 110 void async_run() 111 { 112 boost::asio::post(io, [this]() { run(); }); 113 } 114 void async_wait() 115 { 116 descriptor.async_wait(boost::asio::posix::stream_descriptor::wait_read, 117 [this](const boost::system::error_code& error) { 118 if (!error) 119 { 120 run(); 121 } 122 }); 123 } 124 sd_event* evt; 125 boost::asio::posix::stream_descriptor descriptor; 126 boost::asio::io_context& io; 127 }; 128 129 } // namespace asio 130 131 } // namespace sdbusplus 132