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()
76 void NativeMainloop::run(int timeout)
78 this->m_isTimedOut = false;
80 while (!this->m_isTimedOut) {
81 this->dispatch(timeout);
84 DEBUG("NativeMainloop run stopped");
87 void NativeMainloop::addEventSource(
88 int fd, Mainloop::Event event, Mainloop::Callback &&callback)
90 std::lock_guard<std::mutex> l(this->m_mutex);
92 if (this->m_callbacks.count(fd) != 0)
93 ThrowExc(CSR_ERROR_SERVER, "event source on fd[" << fd << "] already added!");
95 DEBUG("Add event[" << static_cast<uint32_t>(event)
96 << "] source on fd[" << fd << "]");
100 e.events = NativeMainloop::convertFlags(event);
103 if (::epoll_ctl(m_pollfd, EPOLL_CTL_ADD, fd, &e) == -1)
104 throw std::system_error(
105 std::error_code(errno, std::generic_category()),
106 "epoll_ctl failed to EPOLL_CTL_ADD.");
108 this->m_callbacks[fd] = std::move(callback);
111 void NativeMainloop::removeEventSource(int fd)
113 std::lock_guard<std::mutex> l(this->m_mutex);
115 auto it = this->m_callbacks.find(fd);
116 if (it == this->m_callbacks.end())
117 ThrowExc(CSR_ERROR_SERVER, "event source on fd[" << fd << "] isn't added at all");
119 DEBUG("Remove event source on fd[" << fd << "]");
121 this->m_callbacks.erase(it);
123 if (::epoll_ctl(m_pollfd, EPOLL_CTL_DEL, fd, nullptr) == -1) {
125 ThrowExc(CSR_ERROR_SERVER, "Tried to delete epoll item which wasn't added");
127 throw std::system_error(
128 std::error_code(errno, std::generic_category()),
129 "epoll_ctl failed to EPOLL_CTL_DEL.");
133 void NativeMainloop::dispatch(int timeout)
136 epoll_event event[MAX_EPOLL_EVENTS];
138 DEBUG("NativeMainloop dispatched with timeout: " << timeout);
141 nfds = ::epoll_wait(this->m_pollfd, event, MAX_EPOLL_EVENTS,
142 ((timeout < 0) ? -1 : (timeout * 1000)));
143 } while ((nfds == -1) && (errno == EINTR));
146 throw std::system_error(
147 std::error_code(errno, std::generic_category()),
148 "epoll_wait failed!");
151 DEBUG("NativeMainloop timed out!");
152 if (this->m_callbacks.size() > this->m_domainSourceNum) {
153 INFO("NativeMainloop timed out but there's running task on upper layer. "
155 this->m_isTimedOut = false;
157 INFO("NativeMainloop timed out! stop the loop!");
158 this->m_isTimedOut = true;
164 for (int i = 0; i < nfds; i++) {
165 int fd = event[i].data.fd;
167 auto it = this->m_callbacks.find(fd);
168 if (it == this->m_callbacks.end())
169 ThrowExc(CSR_ERROR_SERVER, "event in on fd[" << fd <<
170 "] but associated callback isn't exist!");
172 auto events = convertFlags(event[i].events);
173 if ((events & Mainloop::Event::CLOSE) != Mainloop::Event::NONE) {
174 DEBUG("peer connection closed on fd[" << fd << "]");
175 events &= ~Mainloop::Event::READ;
178 DEBUG("event[" << static_cast<uint32_t>(events)
179 << "] polled on fd[" << fd << "]");