Remove error log on NativeMainloop dtor
[platform/upstream/csr-framework.git] / src / framework / common / native-mainloop.cpp
1 /*
2  *  Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
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 /*
17  * @file        native-mainloop.cpp
18  * @author      Kyungwook Tak (k.tak@samsung.com)
19  * @version     1.0
20  * @brief       Mainloop of csr-server with epoll
21  */
22 #include "common/native-mainloop.h"
23
24 #include <system_error>
25 #include <sys/epoll.h>
26 #include <unistd.h>
27
28 #include "common/audit/logger.h"
29 #include "common/exception.h"
30
31 namespace Csr {
32
33 uint32_t NativeMainloop::convertFlags(Mainloop::Event events)
34 {
35         uint32_t flags = 0;
36
37         if ((events & Mainloop::Event::READ) != Mainloop::Event::NONE)
38                 flags |= EPOLLIN;
39         if ((events & Mainloop::Event::WRITE) != Mainloop::Event::NONE)
40                 flags |= EPOLLOUT;
41         if ((events & Mainloop::Event::CLOSE) != Mainloop::Event::NONE)
42                 flags |= (EPOLLHUP | EPOLLRDHUP);
43
44         return flags;
45 }
46
47 Mainloop::Event NativeMainloop::convertFlags(uint32_t events)
48 {
49         Mainloop::Event flags = Mainloop::Event::NONE;
50
51         if (events & EPOLLIN)
52                 flags |= Mainloop::Event::READ;
53         if (events & EPOLLOUT)
54                 flags |= Mainloop::Event::WRITE;
55         if (events & (EPOLLHUP | EPOLLRDHUP))
56                 flags |= Mainloop::Event::CLOSE;
57
58         return flags;
59 }
60
61 NativeMainloop::NativeMainloop() :
62         m_isTimedOut(false),
63         m_pollfd(::epoll_create1(EPOLL_CLOEXEC))
64 {
65         if (this->m_pollfd == -1)
66                 throw std::system_error(
67                         std::error_code(errno, std::generic_category()),
68                         "Failed to epoll_create1");
69 }
70
71 NativeMainloop::~NativeMainloop()
72 {
73         ::close(m_pollfd);
74 }
75
76 void NativeMainloop::run(int timeout)
77 {
78         this->m_isTimedOut = false;
79
80         while (!this->m_isTimedOut) {
81                 this->dispatch(timeout);
82         }
83
84         DEBUG("NativeMainloop run stopped");
85 }
86
87 void NativeMainloop::addEventSource(
88         int fd, Mainloop::Event event, Mainloop::Callback &&callback)
89 {
90         std::lock_guard<std::mutex> l(this->m_mutex);
91
92         if (this->m_callbacks.count(fd) != 0)
93                 ThrowExc(CSR_ERROR_SERVER, "event source on fd[" << fd << "] already added!");
94
95         DEBUG("Add event[" << static_cast<uint32_t>(event)
96                   << "] source on fd[" << fd << "]");
97
98         epoll_event e;
99
100         e.events = NativeMainloop::convertFlags(event);
101         e.data.fd = fd;
102
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.");
107
108         this->m_callbacks[fd] = std::move(callback);
109 }
110
111 void NativeMainloop::removeEventSource(int fd)
112 {
113         std::lock_guard<std::mutex> l(this->m_mutex);
114
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");
118
119         DEBUG("Remove event source on fd[" << fd << "]");
120
121         this->m_callbacks.erase(it);
122
123         if (::epoll_ctl(m_pollfd, EPOLL_CTL_DEL, fd, nullptr) == -1) {
124                 if (errno == ENOENT)
125                         ThrowExc(CSR_ERROR_SERVER, "Tried to delete epoll item which wasn't added");
126                 else
127                         throw std::system_error(
128                                 std::error_code(errno, std::generic_category()),
129                                 "epoll_ctl failed to EPOLL_CTL_DEL.");
130         }
131 }
132
133 void NativeMainloop::dispatch(int timeout)
134 {
135         int nfds = -1;
136         epoll_event event[MAX_EPOLL_EVENTS];
137
138         DEBUG("NativeMainloop dispatched with timeout: " << timeout);
139
140         do {
141                 nfds = ::epoll_wait(this->m_pollfd, event, MAX_EPOLL_EVENTS,
142                                                         ((timeout < 0) ? -1 : (timeout * 1000)));
143         } while ((nfds == -1) && (errno == EINTR));
144
145         if (nfds < 0)
146                 throw std::system_error(
147                         std::error_code(errno, std::generic_category()),
148                         "epoll_wait failed!");
149
150         if (nfds == 0) {
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. "
154                                  "Re-dispatch.");
155                         this->m_isTimedOut = false;
156                 } else {
157                         INFO("NativeMainloop timed out! stop the loop!");
158                         this->m_isTimedOut = true;
159                 }
160
161                 return;
162         }
163
164         for (int i = 0; i < nfds; i++) {
165                 int fd = event[i].data.fd;
166
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!");
171
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;
176                 }
177
178                 DEBUG("event[" << static_cast<uint32_t>(events)
179                           << "] polled on fd[" << fd << "]");
180
181                 it->second(events);
182         }
183 }
184
185 }