xref: /aosp_15_r20/system/core/init/epoll.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
1*00c7fec1SAndroid Build Coastguard Worker /*
2*00c7fec1SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*00c7fec1SAndroid Build Coastguard Worker  *
4*00c7fec1SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*00c7fec1SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*00c7fec1SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*00c7fec1SAndroid Build Coastguard Worker  *
8*00c7fec1SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*00c7fec1SAndroid Build Coastguard Worker  *
10*00c7fec1SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*00c7fec1SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*00c7fec1SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*00c7fec1SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*00c7fec1SAndroid Build Coastguard Worker  * limitations under the License.
15*00c7fec1SAndroid Build Coastguard Worker  */
16*00c7fec1SAndroid Build Coastguard Worker 
17*00c7fec1SAndroid Build Coastguard Worker #include "epoll.h"
18*00c7fec1SAndroid Build Coastguard Worker 
19*00c7fec1SAndroid Build Coastguard Worker #include <stdint.h>
20*00c7fec1SAndroid Build Coastguard Worker #include <sys/epoll.h>
21*00c7fec1SAndroid Build Coastguard Worker 
22*00c7fec1SAndroid Build Coastguard Worker #include <chrono>
23*00c7fec1SAndroid Build Coastguard Worker #include <functional>
24*00c7fec1SAndroid Build Coastguard Worker #include <map>
25*00c7fec1SAndroid Build Coastguard Worker 
26*00c7fec1SAndroid Build Coastguard Worker #include <android-base/logging.h>
27*00c7fec1SAndroid Build Coastguard Worker 
28*00c7fec1SAndroid Build Coastguard Worker namespace android {
29*00c7fec1SAndroid Build Coastguard Worker namespace init {
30*00c7fec1SAndroid Build Coastguard Worker 
Epoll()31*00c7fec1SAndroid Build Coastguard Worker Epoll::Epoll() {}
32*00c7fec1SAndroid Build Coastguard Worker 
Open()33*00c7fec1SAndroid Build Coastguard Worker Result<void> Epoll::Open() {
34*00c7fec1SAndroid Build Coastguard Worker     if (epoll_fd_ >= 0) return {};
35*00c7fec1SAndroid Build Coastguard Worker     epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC));
36*00c7fec1SAndroid Build Coastguard Worker 
37*00c7fec1SAndroid Build Coastguard Worker     if (epoll_fd_ == -1) {
38*00c7fec1SAndroid Build Coastguard Worker         return ErrnoError() << "epoll_create1 failed";
39*00c7fec1SAndroid Build Coastguard Worker     }
40*00c7fec1SAndroid Build Coastguard Worker     return {};
41*00c7fec1SAndroid Build Coastguard Worker }
42*00c7fec1SAndroid Build Coastguard Worker 
RegisterHandler(int fd,Handler handler,uint32_t events)43*00c7fec1SAndroid Build Coastguard Worker Result<void> Epoll::RegisterHandler(int fd, Handler handler, uint32_t events) {
44*00c7fec1SAndroid Build Coastguard Worker     if (!events) {
45*00c7fec1SAndroid Build Coastguard Worker         return Error() << "Must specify events";
46*00c7fec1SAndroid Build Coastguard Worker     }
47*00c7fec1SAndroid Build Coastguard Worker 
48*00c7fec1SAndroid Build Coastguard Worker     auto [it, inserted] = epoll_handlers_.emplace(
49*00c7fec1SAndroid Build Coastguard Worker             fd, Info{
50*00c7fec1SAndroid Build Coastguard Worker                         .handler = std::move(handler),
51*00c7fec1SAndroid Build Coastguard Worker                         .events = events,
52*00c7fec1SAndroid Build Coastguard Worker                 });
53*00c7fec1SAndroid Build Coastguard Worker     if (!inserted) {
54*00c7fec1SAndroid Build Coastguard Worker         return Error() << "Cannot specify two epoll handlers for a given FD";
55*00c7fec1SAndroid Build Coastguard Worker     }
56*00c7fec1SAndroid Build Coastguard Worker     epoll_event ev = {
57*00c7fec1SAndroid Build Coastguard Worker             .events = events,
58*00c7fec1SAndroid Build Coastguard Worker             .data.fd = fd,
59*00c7fec1SAndroid Build Coastguard Worker     };
60*00c7fec1SAndroid Build Coastguard Worker     if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_ADD, fd, &ev) == -1) {
61*00c7fec1SAndroid Build Coastguard Worker         Result<void> result = ErrnoError() << "epoll_ctl failed to add fd";
62*00c7fec1SAndroid Build Coastguard Worker         epoll_handlers_.erase(fd);
63*00c7fec1SAndroid Build Coastguard Worker         return result;
64*00c7fec1SAndroid Build Coastguard Worker     }
65*00c7fec1SAndroid Build Coastguard Worker     return {};
66*00c7fec1SAndroid Build Coastguard Worker }
67*00c7fec1SAndroid Build Coastguard Worker 
UnregisterHandler(int fd)68*00c7fec1SAndroid Build Coastguard Worker Result<void> Epoll::UnregisterHandler(int fd) {
69*00c7fec1SAndroid Build Coastguard Worker     if (epoll_ctl(epoll_fd_.get(), EPOLL_CTL_DEL, fd, nullptr) == -1) {
70*00c7fec1SAndroid Build Coastguard Worker         return ErrnoError() << "epoll_ctl failed to remove fd";
71*00c7fec1SAndroid Build Coastguard Worker     }
72*00c7fec1SAndroid Build Coastguard Worker     auto it = epoll_handlers_.find(fd);
73*00c7fec1SAndroid Build Coastguard Worker     if (it == epoll_handlers_.end()) {
74*00c7fec1SAndroid Build Coastguard Worker         return Error() << "Attempting to remove epoll handler for FD without an existing handler";
75*00c7fec1SAndroid Build Coastguard Worker     }
76*00c7fec1SAndroid Build Coastguard Worker     to_remove_.insert(it->first);
77*00c7fec1SAndroid Build Coastguard Worker     return {};
78*00c7fec1SAndroid Build Coastguard Worker }
79*00c7fec1SAndroid Build Coastguard Worker 
SetFirstCallback(std::function<void ()> first_callback)80*00c7fec1SAndroid Build Coastguard Worker void Epoll::SetFirstCallback(std::function<void()> first_callback) {
81*00c7fec1SAndroid Build Coastguard Worker     first_callback_ = std::move(first_callback);
82*00c7fec1SAndroid Build Coastguard Worker }
83*00c7fec1SAndroid Build Coastguard Worker 
Wait(std::optional<std::chrono::milliseconds> timeout)84*00c7fec1SAndroid Build Coastguard Worker Result<int> Epoll::Wait(std::optional<std::chrono::milliseconds> timeout) {
85*00c7fec1SAndroid Build Coastguard Worker     int timeout_ms = -1;
86*00c7fec1SAndroid Build Coastguard Worker     if (timeout && timeout->count() < INT_MAX) {
87*00c7fec1SAndroid Build Coastguard Worker         timeout_ms = timeout->count();
88*00c7fec1SAndroid Build Coastguard Worker     }
89*00c7fec1SAndroid Build Coastguard Worker     const auto max_events = epoll_handlers_.size();
90*00c7fec1SAndroid Build Coastguard Worker     epoll_event ev[max_events];
91*00c7fec1SAndroid Build Coastguard Worker     auto num_events = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_.get(), ev, max_events, timeout_ms));
92*00c7fec1SAndroid Build Coastguard Worker     if (num_events == -1) {
93*00c7fec1SAndroid Build Coastguard Worker         return ErrnoError() << "epoll_wait failed";
94*00c7fec1SAndroid Build Coastguard Worker     }
95*00c7fec1SAndroid Build Coastguard Worker     if (num_events > 0 && first_callback_) {
96*00c7fec1SAndroid Build Coastguard Worker         first_callback_();
97*00c7fec1SAndroid Build Coastguard Worker     }
98*00c7fec1SAndroid Build Coastguard Worker     for (int i = 0; i < num_events; ++i) {
99*00c7fec1SAndroid Build Coastguard Worker         const auto it = epoll_handlers_.find(ev[i].data.fd);
100*00c7fec1SAndroid Build Coastguard Worker         if (it == epoll_handlers_.end()) {
101*00c7fec1SAndroid Build Coastguard Worker             continue;
102*00c7fec1SAndroid Build Coastguard Worker         }
103*00c7fec1SAndroid Build Coastguard Worker         const Info& info = it->second;
104*00c7fec1SAndroid Build Coastguard Worker         if ((info.events & (EPOLLIN | EPOLLPRI)) == (EPOLLIN | EPOLLPRI) &&
105*00c7fec1SAndroid Build Coastguard Worker             (ev[i].events & EPOLLIN) != ev[i].events) {
106*00c7fec1SAndroid Build Coastguard Worker             // This handler wants to know about exception events, and just got one.
107*00c7fec1SAndroid Build Coastguard Worker             // Log something informational.
108*00c7fec1SAndroid Build Coastguard Worker             LOG(ERROR) << "Received unexpected epoll event set: " << ev[i].events;
109*00c7fec1SAndroid Build Coastguard Worker         }
110*00c7fec1SAndroid Build Coastguard Worker         info.handler();
111*00c7fec1SAndroid Build Coastguard Worker         for (auto fd : to_remove_) {
112*00c7fec1SAndroid Build Coastguard Worker             epoll_handlers_.erase(fd);
113*00c7fec1SAndroid Build Coastguard Worker         }
114*00c7fec1SAndroid Build Coastguard Worker         to_remove_.clear();
115*00c7fec1SAndroid Build Coastguard Worker     }
116*00c7fec1SAndroid Build Coastguard Worker     return num_events;
117*00c7fec1SAndroid Build Coastguard Worker }
118*00c7fec1SAndroid Build Coastguard Worker 
119*00c7fec1SAndroid Build Coastguard Worker }  // namespace init
120*00c7fec1SAndroid Build Coastguard Worker }  // namespace android
121