2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
17 * @file native-mainloop.cpp
18 * @author Kyungwook Tak (k.tak@samsung.com)
20 * @brief Mainloop of csr-server with epoll
22 #include "common/native-mainloop.h"
24 #include <system_error>
25 #include <sys/epoll.h>
28 #include "common/audit/logger.h"
29 #include "common/exception.h"
33 uint32_t NativeMainloop::convertFlags(Mainloop::Event events)
37 if ((events & Mainloop::Event::READ) != Mainloop::Event::NONE)
39 if ((events & Mainloop::Event::WRITE) != Mainloop::Event::NONE)
41 if ((events & Mainloop::Event::CLOSE) != Mainloop::Event::NONE)
42 flags |= (EPOLLHUP | EPOLLRDHUP);
47 Mainloop::Event NativeMainloop::convertFlags(uint32_t events)
49 Mainloop::Event flags = Mainloop::Event::NONE;
52 flags |= Mainloop::Event::READ;
53 if (events & EPOLLOUT)
54 flags |= Mainloop::Event::WRITE;
55 if (events & (EPOLLHUP | EPOLLRDHUP))
56 flags |= Mainloop::Event::CLOSE;
61 NativeMainloop::NativeMainloop() :
63 m_pollfd(::epoll_create1(EPOLL_CLOEXEC))
65 if (this->m_pollfd == -1)
66 throw std::system_error(
67 std::error_code(errno, std::generic_category()),
68 "Failed to epoll_create1");
71 NativeMainloop::~NativeMainloop()
73 if (!this->m_isTimedOut && !this->m_callbacks.empty())
74 ERROR("mainloop registered callbacks should be empty except timed out case");
79 void NativeMainloop::run(int timeout)
81 this->m_isTimedOut = false;
83 while (!this->m_isTimedOut) {
84 this->dispatch(timeout);
87 DEBUG("NativeMainloop run stopped");
90 void NativeMainloop::addEventSource(
91 int fd, Mainloop::Event event, Mainloop::Callback &&callback)
93 std::lock_guard<std::mutex> l(this->m_mutex);
95 if (this->m_callbacks.count(fd) != 0)
96 ThrowExc(CSR_ERROR_SERVER, "event source on fd[" << fd << "] already added!");
98 DEBUG("Add event[" << static_cast<uint32_t>(event)
99 << "] source on fd[" << fd << "]");
103 e.events = NativeMainloop::convertFlags(event);
106 if (::epoll_ctl(m_pollfd, EPOLL_CTL_ADD, fd, &e) == -1)
107 throw std::system_error(
108 std::error_code(errno, std::generic_category()),
109 "epoll_ctl failed to EPOLL_CTL_ADD.");
111 this->m_callbacks[fd] = std::move(callback);
114 void NativeMainloop::removeEventSource(int fd)
116 std::lock_guard<std::mutex> l(this->m_mutex);
118 auto it = this->m_callbacks.find(fd);
119 if (it == this->m_callbacks.end())
120 ThrowExc(CSR_ERROR_SERVER, "event source on fd[" << fd << "] isn't added at all");
122 DEBUG("Remove event source on fd[" << fd << "]");
124 this->m_callbacks.erase(it);
126 if (::epoll_ctl(m_pollfd, EPOLL_CTL_DEL, fd, nullptr) == -1) {
128 ThrowExc(CSR_ERROR_SERVER, "Tried to delete epoll item which wasn't added");
130 throw std::system_error(
131 std::error_code(errno, std::generic_category()),
132 "epoll_ctl failed to EPOLL_CTL_DEL.");
136 void NativeMainloop::dispatch(int timeout)
139 epoll_event event[MAX_EPOLL_EVENTS];
141 DEBUG("NativeMainloop dispatched with timeout: " << timeout);
144 nfds = ::epoll_wait(this->m_pollfd, event, MAX_EPOLL_EVENTS,
145 ((timeout < 0) ? -1 : (timeout * 1000)));
146 } while ((nfds == -1) && (errno == EINTR));
149 throw std::system_error(
150 std::error_code(errno, std::generic_category()),
151 "epoll_wait failed!");
154 DEBUG("NativeMainloop timed out!");
155 if (this->m_callbacks.size() > this->m_domainSourceNum) {
156 INFO("NativeMainloop timed out but there's running task on upper layer. "
158 this->m_isTimedOut = false;
160 INFO("NativeMainloop timed out! stop the loop!");
161 this->m_isTimedOut = true;
167 for (int i = 0; i < nfds; i++) {
168 int fd = event[i].data.fd;
170 auto it = this->m_callbacks.find(fd);
171 if (it == this->m_callbacks.end())
172 ThrowExc(CSR_ERROR_SERVER, "event in on fd[" << fd <<
173 "] but associated callback isn't exist!");
175 auto events = convertFlags(event[i].events);
176 if ((events & Mainloop::Event::CLOSE) != Mainloop::Event::NONE) {
177 INFO("peer connection closed on fd[" << fd << "]");
178 events &= ~Mainloop::Event::READ;
181 DEBUG("event[" << static_cast<uint32_t>(events)
182 << "] polled on fd[" << fd << "]");