Line data Source code
1 : /* 2 : * Copyright (C) 2016 Intel Corporation. All rights reserved. 3 : * 4 : * This file is free software: you can redistribute it and/or modify it 5 : * under the terms of the GNU General Public License as published by the 6 : * Free Software Foundation, either version 3 of the License, or 7 : * (at your option) any later version. 8 : * 9 : * This file is distributed in the hope that it will be useful, but 10 : * WITHOUT ANY WARRANTY; without even the implied warranty of 11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 : * See the GNU General Public License for more details. 13 : * 14 : * You should have received a copy of the GNU General Public License along 15 : * with this program. If not, see <http://www.gnu.org/licenses/>. 16 : */ 17 : #include <errno.h> 18 : #include <fcntl.h> 19 : #include <inttypes.h> 20 : #include <stdio.h> 21 : #include <sys/epoll.h> 22 : #include <sys/eventfd.h> 23 : #include <sys/types.h> 24 : #include <sys/uio.h> 25 : #include <unistd.h> 26 : 27 : #include "Poller.h" 28 : 29 : extern const AP_HAL::HAL &hal; 30 : 31 : namespace Linux { 32 : 33 2 : void WakeupPollable::on_can_read() 34 : { 35 : ssize_t r; 36 : uint64_t val; 37 : 38 : do { 39 2 : r = read(_fd, &val, sizeof(val)); 40 2 : } while (!(r == -1 && errno == EAGAIN)); 41 1 : } 42 : 43 1 : Poller::Poller() 44 : { 45 1 : _epfd = epoll_create1(EPOLL_CLOEXEC); 46 1 : if (_epfd == -1) { 47 0 : fprintf(stderr, "Failed to create epoll: %m\n"); 48 0 : return; 49 : } 50 : 51 1 : _wakeup._fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); 52 1 : if (_wakeup._fd == -1) { 53 0 : fprintf(stderr, "Failed to create wakeup fd: %m\n"); 54 0 : goto fail_eventfd; 55 : } 56 : 57 1 : if (!register_pollable(&_wakeup, EPOLLIN)) { 58 0 : fprintf(stderr, "Failed to add wakeup fd\n"); 59 0 : goto fail_register; 60 : } 61 : 62 1 : return; 63 : 64 0 : fail_register: 65 0 : close(_wakeup._fd); 66 0 : _wakeup._fd = -1; 67 0 : fail_eventfd: 68 0 : close(_epfd); 69 0 : _epfd = -1; 70 : } 71 : 72 1 : bool Poller::register_pollable(Pollable *p, uint32_t events) 73 : { 74 : /* 75 : * EPOLLWAKEUP prevents the system from hibernating or suspending when 76 : * inside epoll_wait() for this particular event. It is silently 77 : * ignored if the process does not have the CAP_BLOCK_SUSPEND 78 : * capability. 79 : */ 80 1 : events |= EPOLLWAKEUP; 81 : 82 1 : if (_epfd < 0) { 83 0 : return false; 84 : } 85 : 86 1 : struct epoll_event epev = { }; 87 1 : epev.events = events; 88 1 : epev.data.ptr = static_cast<void *>(p); 89 : 90 1 : return epoll_ctl(_epfd, EPOLL_CTL_ADD, p->get_fd(), &epev) == 0; 91 : } 92 : 93 1 : void Poller::unregister_pollable(const Pollable *p) 94 : { 95 1 : if (_epfd >= 0 && p->get_fd() >= 0) { 96 1 : epoll_ctl(_epfd, EPOLL_CTL_DEL, p->get_fd(), nullptr); 97 : } 98 1 : } 99 : 100 1 : int Poller::poll() const 101 : { 102 1 : const int max_events = 16; 103 : epoll_event events[max_events]; 104 : int r; 105 : 106 : do { 107 1 : r = epoll_wait(_epfd, events, max_events, -1); 108 1 : } while (r < 0 && errno == EINTR); 109 : 110 1 : if (r < 0) { 111 0 : return -errno; 112 : } 113 : 114 2 : for (int i = 0; i < r; i++) { 115 1 : Pollable *p = static_cast<Pollable *>(events[i].data.ptr); 116 : 117 1 : if (events[i].events & EPOLLIN) { 118 1 : p->on_can_read(); 119 : } 120 1 : if (events[i].events & EPOLLOUT) { 121 0 : p->on_can_write(); 122 : } 123 1 : if (events[i].events & EPOLLERR) { 124 0 : p->on_error(); 125 : } 126 1 : if (events[i].events & EPOLLHUP) { 127 0 : p->on_hang_up(); 128 : } 129 : } 130 : 131 1 : return r; 132 : } 133 : 134 1 : void Poller::wakeup() const 135 : { 136 : ssize_t r; 137 1 : uint64_t val = 1; 138 : 139 : do { 140 1 : r = write(_wakeup.get_fd(), &val, sizeof(val)); 141 1 : } while (r == -1 && errno == EINTR); 142 : 143 1 : if (r == -1) { 144 0 : fprintf(stderr, "Failed to wakeup poller: %m\n"); 145 : } 146 1 : } 147 : 148 1 : Pollable::~Pollable() 149 : { 150 : /* 151 : * Make sure to remove the file descriptor from epoll since events could 152 : * continue to be reported if the file descriptor was dup()'ed. However 153 : * we rely on user unregistering it rather than taking a reference to the 154 : * Poller. Here we just close our file descriptor. 155 : */ 156 1 : if (_fd >= 0) { 157 1 : close(_fd); 158 : } 159 1 : } 160 : 161 : }