Coloring compiler's output
[platform/core/security/vasum.git] / common / epoll / event-poll.cpp
1 /*
2  *  Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  Contact: Piotr Bartosiewicz <p.bartosiewi@partner.samsung.com>
5  *
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
9  *
10  *      http://www.apache.org/licenses/LICENSE-2.0
11  *
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
17  */
18
19 /**
20  * @file
21  * @author  Piotr Bartosiewicz (p.bartosiewi@partner.samsung.com)
22  * @brief   C++ epoll wrapper
23  */
24
25 #include "config.hpp"
26 #include "epoll/event-poll.hpp"
27 #include "utils/fd-utils.hpp"
28 #include "utils/exception.hpp"
29 #include "logger/logger.hpp"
30
31 #include <sys/epoll.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <assert.h>
35
36 namespace vasum {
37 namespace epoll {
38
39 EventPoll::EventPoll()
40     : mPollFD(::epoll_create1(EPOLL_CLOEXEC))
41 {
42     if (mPollFD == -1) {
43         LOGE("Failed to create epoll: " << getSystemErrorMessage());
44         throw UtilsException("Could not create epoll");
45     }
46 }
47
48 EventPoll::~EventPoll()
49 {
50     if (!mCallbacks.empty()) {
51         LOGW("Not removed callbacks: " << mCallbacks.size());
52         assert(0 && "Not removed callbacks left");
53     }
54     utils::close(mPollFD);
55 }
56
57 int EventPoll::getPollFD() const
58 {
59     return mPollFD;
60 }
61
62 void EventPoll::addFD(const int fd, const Events events, Callback&& callback)
63 {
64     std::lock_guard<Mutex> lock(mMutex);
65
66     if (mCallbacks.find(fd) != mCallbacks.end()) {
67         LOGW("Already added fd: " << fd);
68         throw UtilsException("FD already added");
69     }
70
71     if (!addFDInternal(fd, events)) {
72         throw UtilsException("Could not add fd");
73     }
74
75     mCallbacks.insert({fd, std::make_shared<Callback>(std::move(callback))});
76     LOGT("Callback added for " << fd);
77 }
78
79 void EventPoll::removeFD(const int fd)
80 {
81     std::lock_guard<Mutex> lock(mMutex);
82
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");
87     }
88     mCallbacks.erase(iter);
89     removeFDInternal(fd);
90     LOGT("Callback removed for " << fd);
91 }
92
93 bool EventPoll::dispatchIteration(const int timeoutMs)
94 {
95     for (;;) {
96         epoll_event event;
97         int num = epoll_wait(mPollFD, &event, 1, timeoutMs);
98         if (num == 0) {
99             return false; // timeout
100         }
101         if (num < 0) {
102             if (errno == EINTR) {
103                 continue;
104             }
105             LOGE("Failed to wait on epoll: " << getSystemErrorMessage());
106             throw UtilsException("Could not wait for event");
107         }
108
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()) {
113             continue;
114         }
115
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);
119     }
120 }
121
122 void EventPoll::dispatchLoop()
123 {
124     while (dispatchIteration(-1)) {}
125 }
126
127 bool EventPoll::addFDInternal(const int fd, const Events events)
128 {
129     epoll_event event;
130     memset(&event, 0, sizeof(event));
131     event.events = events;
132     event.data.fd = fd;
133
134     if (epoll_ctl(mPollFD, EPOLL_CTL_ADD, fd, &event) == -1) {
135         LOGE("Failed to add fd to poll: " << getSystemErrorMessage());
136         return false;
137     }
138     return true;
139 }
140
141 void EventPoll::removeFDInternal(const int fd)
142 {
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());
147     }
148 }
149
150 } // namespace epoll
151 } // namespace vasum