2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
21 * @author Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
22 * @brief C++ epoll wrapper
26 #include "epoll/event-poll.hpp"
27 #include "utils/fd-utils.hpp"
28 #include "utils/exception.hpp"
29 #include "logger/logger.hpp"
31 #include <sys/epoll.h>
39 EventPoll::EventPoll()
40 : mPollFD(::epoll_create1(EPOLL_CLOEXEC))
43 LOGE("Failed to create epoll: " << getSystemErrorMessage());
44 throw UtilsException("Could not create epoll");
48 EventPoll::~EventPoll()
50 if (!mCallbacks.empty()) {
51 LOGW("Not removed callbacks: " << mCallbacks.size());
52 assert(0 && "Not removed callbacks left");
54 utils::close(mPollFD);
57 int EventPoll::getPollFD() const
62 void EventPoll::addFD(const int fd, const Events events, Callback&& callback)
64 std::lock_guard<Mutex> lock(mMutex);
66 if (mCallbacks.find(fd) != mCallbacks.end()) {
67 LOGW("Already added fd: " << fd);
68 throw UtilsException("FD already added");
71 if (!addFDInternal(fd, events)) {
72 throw UtilsException("Could not add fd");
75 mCallbacks.insert({fd, std::make_shared<Callback>(std::move(callback))});
76 LOGT("Callback added for " << fd);
79 void EventPoll::removeFD(const int fd)
81 std::lock_guard<Mutex> lock(mMutex);
83 auto iter = mCallbacks.find(fd);
84 if (iter == mCallbacks.end()) {
85 LOGW("Failed to remove nonexistent fd: " << fd);
86 throw UtilsException("FD does not exist");
88 mCallbacks.erase(iter);
90 LOGT("Callback removed for " << fd);
93 bool EventPoll::dispatchIteration(const int timeoutMs)
97 int num = epoll_wait(mPollFD, &event, 1, timeoutMs);
99 return false; // timeout
102 if (errno == EINTR) {
105 LOGE("Failed to wait on epoll: " << getSystemErrorMessage());
106 throw UtilsException("Could not wait for event");
109 // callback could be removed in the meantime, so be careful, find it inside lock
110 std::lock_guard<Mutex> lock(mMutex);
111 auto iter = mCallbacks.find(event.data.fd);
112 if (iter == mCallbacks.end()) {
116 // add ref because removeFD(self) can be called inside callback
117 std::shared_ptr<Callback> callback(iter->second);
118 return (*callback)(event.data.fd, event.events);
122 void EventPoll::dispatchLoop()
124 while (dispatchIteration(-1)) {}
127 bool EventPoll::addFDInternal(const int fd, const Events events)
130 memset(&event, 0, sizeof(event));
131 event.events = events;
134 if (epoll_ctl(mPollFD, EPOLL_CTL_ADD, fd, &event) == -1) {
135 LOGE("Failed to add fd to poll: " << getSystemErrorMessage());
141 void EventPoll::removeFDInternal(const int fd)
143 if (epoll_ctl(mPollFD, EPOLL_CTL_DEL, fd, NULL) == -1) {
144 assert(errno != EBADF); // always removeFD before closing fd locally!
145 // this is important because linux will reuse this fd number
146 LOGE("Failed to remove fd from poll: " << getSystemErrorMessage());