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/system/error_code.hpp> 23 24 namespace sdbusplus 25 { 26 27 namespace asio 28 { 29 /* A simple class to integrate the sd_event_loop into the boost::asio io_context 30 * in case a boost::asio user needs sd_events 31 */ 32 class sd_event_wrapper 33 { 34 public: 35 sd_event_wrapper(boost::asio::io_context& io) : 36 evt(nullptr), descriptor(io), io(io) 37 { 38 sd_event_default(&evt); 39 if (evt) 40 { 41 descriptor.assign(sd_event_get_fd(evt)); 42 async_run(); 43 } 44 } 45 sd_event_wrapper(sd_event* evt, boost::asio::io_context& io) : 46 evt(evt), descriptor(io), io(io) 47 { 48 if (evt) 49 { 50 sd_event_ref(evt); 51 descriptor.assign(sd_event_get_fd(evt)); 52 async_run(); 53 } 54 } 55 ~sd_event_wrapper() 56 { 57 // sd_event really wants to close the descriptor on its own 58 // so this class must merely release it 59 descriptor.release(); 60 sd_event_unref(evt); 61 } 62 // process one event step in the queue 63 // return true if the queue is still alive 64 void run() 65 { 66 int ret; 67 int state = sd_event_get_state(evt); 68 switch (state) 69 { 70 case SD_EVENT_INITIAL: 71 ret = sd_event_prepare(evt); 72 if (ret > 0) 73 { 74 async_run(); 75 } 76 else if (ret == 0) 77 { 78 async_wait(); 79 } 80 break; 81 case SD_EVENT_ARMED: 82 ret = sd_event_wait(evt, 0); 83 if (ret >= 0) 84 { 85 async_run(); 86 } 87 break; 88 case SD_EVENT_PENDING: 89 ret = sd_event_dispatch(evt); 90 if (ret > 0) 91 { 92 async_run(); 93 } 94 break; 95 case SD_EVENT_FINISHED: 96 break; 97 default: 98 // throw something? 99 // doing nothing will break out of the async loop 100 break; 101 } 102 } 103 sd_event* get() const 104 { 105 return evt; 106 } 107 108 private: 109 void async_run() 110 { 111 boost::asio::post(io, [this]() { run(); }); 112 } 113 void async_wait() 114 { 115 descriptor.async_wait(boost::asio::posix::stream_descriptor::wait_read, 116 [this](const boost::system::error_code& error) { 117 if (!error) 118 { 119 run(); 120 } 121 }); 122 } 123 sd_event* evt; 124 boost::asio::posix::stream_descriptor descriptor; 125 boost::asio::io_context& io; 126 }; 127 128 } // namespace asio 129 130 } // namespace sdbusplus 131