| /* |
| Copyright (c) 2018-2019 Nokia. |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| #include "private/eventfd.hpp" |
| #include <sys/eventfd.h> |
| #include "private/abort.hpp" |
| #include "private/engine.hpp" |
| #include "private/system.hpp" |
| |
| using namespace shareddatalayer; |
| |
| namespace |
| { |
| /* |
| * Simple wrapper for executing the given callback without expecting |
| * exceptions. If callback throws, we'll crash. |
| */ |
| void execute(const EventFD::Callback& callback) noexcept |
| { |
| callback(); |
| } |
| } |
| |
| EventFD::EventFD(Engine& engine): |
| EventFD(System::getSystem(), engine) |
| { |
| } |
| |
| EventFD::EventFD(System& system, Engine& engine): |
| system(system), |
| fd(system, system.eventfd(0U, EFD_CLOEXEC | EFD_NONBLOCK)) |
| { |
| engine.addMonitoredFD(fd, Engine::EVENT_IN, std::bind(&EventFD::handleEvents, this)); |
| } |
| |
| EventFD::~EventFD() |
| { |
| } |
| |
| void EventFD::post(const Callback& callback) |
| { |
| if (!callback) |
| SHAREDDATALAYER_ABORT("A null callback was provided"); |
| |
| atomicPushBack(callback); |
| static const uint64_t value(1U); |
| system.write(fd, &value, sizeof(value)); |
| } |
| |
| void EventFD::atomicPushBack(const Callback& callback) |
| { |
| std::lock_guard<std::mutex> guard(callbacksMutex); |
| callbacks.push_back(callback); |
| } |
| |
| EventFD::Callbacks EventFD::atomicPopAll() |
| { |
| std::lock_guard<std::mutex> guard(callbacksMutex); |
| Callbacks extractedCallbacks; |
| std::swap(callbacks, extractedCallbacks); |
| return extractedCallbacks; |
| } |
| |
| void EventFD::handleEvents() |
| { |
| uint64_t value; |
| system.read(fd, &value, sizeof(value)); |
| executeCallbacks(); |
| } |
| |
| void EventFD::executeCallbacks() |
| { |
| Callbacks callbacks(atomicPopAll()); |
| while (!callbacks.empty()) |
| popAndExecuteFirstCallback(callbacks); |
| } |
| |
| void EventFD::popAndExecuteFirstCallback(Callbacks& callbacks) |
| { |
| const auto callback(callbacks.front()); |
| callbacks.pop_front(); |
| execute(callback); |
| } |