Downgrade some frequently printed log's level
[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         if (!this->m_isTimedOut && !this->m_callbacks.empty())
74                 ERROR("mainloop registered callbacks should be empty except timed out case");
75
76         ::close(m_pollfd);
77 }
78
79 void NativeMainloop::run(int timeout)
80 {
81         this->m_isTimedOut = false;
82
83         while (!this->m_isTimedOut) {
84                 this->dispatch(timeout);
85         }
86
87         DEBUG("NativeMainloop run stopped");
88 }
89
90 void NativeMainloop::addEventSource(
91         int fd, Mainloop::Event event, Mainloop::Callback &&callback)
92 {
93         std::lock_guard<std::mutex> l(this->m_mutex);
94
95         if (this->m_callbacks.count(fd) != 0)
96                 ThrowExc(CSR_ERROR_SERVER, "event source on fd[" << fd << "] already added!");
97
98         DEBUG("Add event[" << static_cast<uint32_t>(event)
99                   << "] source on fd[" << fd << "]");
100
101         epoll_event e;
102
103         e.events = NativeMainloop::convertFlags(event);
104         e.data.fd = fd;
105
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.");
110
111         this->m_callbacks[fd] = std::move(callback);
112 }
113
114 void NativeMainloop::removeEventSource(int fd)
115 {
116         std::lock_guard<std::mutex> l(this->m_mutex);
117
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");
121
122         DEBUG("Remove event source on fd[" << fd << "]");
123
124         this->m_callbacks.erase(it);
125
126         if (::epoll_ctl(m_pollfd, EPOLL_CTL_DEL, fd, nullptr) == -1) {
127                 if (errno == ENOENT)
128                         ThrowExc(CSR_ERROR_SERVER, "Tried to delete epoll item which wasn't added");
129                 else
130                         throw std::system_error(
131                                 std::error_code(errno, std::generic_category()),
132                                 "epoll_ctl failed to EPOLL_CTL_DEL.");
133         }
134 }
135
136 void NativeMainloop::dispatch(int timeout)
137 {
138         int nfds = -1;
139         epoll_event event[MAX_EPOLL_EVENTS];
140
141         DEBUG("NativeMainloop dispatched with timeout: " << timeout);
142
143         do {
144                 nfds = ::epoll_wait(this->m_pollfd, event, MAX_EPOLL_EVENTS,
145                                                         ((timeout < 0) ? -1 : (timeout * 1000)));
146         } while ((nfds == -1) && (errno == EINTR));
147
148         if (nfds < 0)
149                 throw std::system_error(
150                         std::error_code(errno, std::generic_category()),
151                         "epoll_wait failed!");
152
153         if (nfds == 0) {
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. "
157                                  "Re-dispatch.");
158                         this->m_isTimedOut = false;
159                 } else {
160                         INFO("NativeMainloop timed out! stop the loop!");
161                         this->m_isTimedOut = true;
162                 }
163
164                 return;
165         }
166
167         for (int i = 0; i < nfds; i++) {
168                 int fd = event[i].data.fd;
169
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!");
174
175                 auto events = convertFlags(event[i].events);
176                 if ((events & Mainloop::Event::CLOSE) != Mainloop::Event::NONE) {
177                         DEBUG("peer connection closed on fd[" << fd << "]");
178                         events &= ~Mainloop::Event::READ;
179                 }
180
181                 DEBUG("event[" << static_cast<uint32_t>(events)
182                           << "] polled on fd[" << fd << "]");
183
184                 it->second(events);
185         }
186 }
187
188 }