epoll.cpp 6.15 KB
Newer Older
Martin Sustrik's avatar
Martin Sustrik committed
1
/*
2
    Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
Martin Sustrik's avatar
Martin Sustrik committed
3

4
    This file is part of libzmq, the ZeroMQ core engine in C++.
Martin Sustrik's avatar
Martin Sustrik committed
5

6 7 8
    libzmq is free software; you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License (LGPL) as published
    by the Free Software Foundation; either version 3 of the License, or
Martin Sustrik's avatar
Martin Sustrik committed
9 10
    (at your option) any later version.

11 12 13 14 15 16 17 18 19 20 21 22 23 24
    As a special exception, the Contributors give you permission to link
    this library with independent modules to produce an executable,
    regardless of the license terms of these independent modules, and to
    copy and distribute the resulting executable under terms of your choice,
    provided that you also meet, for each linked independent module, the
    terms and conditions of the license of that module. An independent
    module is a module which is not derived from or based on this library.
    If you modify this library, you must extend this exception to your
    version of the library.

    libzmq is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    License for more details.
Martin Sustrik's avatar
Martin Sustrik committed
25

26
    You should have received a copy of the GNU Lesser General Public License
Martin Sustrik's avatar
Martin Sustrik committed
27 28 29
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

30
#include "precompiled.hpp"
31
#if defined ZMQ_IOTHREAD_POLLER_USE_EPOLL
32 33 34 35 36
#include "epoll.hpp"

#if !defined ZMQ_HAVE_WINDOWS
#include <unistd.h>
#endif
Martin Sustrik's avatar
Martin Sustrik committed
37 38 39

#include <stdlib.h>
#include <string.h>
40
#include <signal.h>
Martin Sustrik's avatar
Martin Sustrik committed
41
#include <algorithm>
42
#include <new>
Martin Sustrik's avatar
Martin Sustrik committed
43

44
#include "macros.hpp"
Martin Sustrik's avatar
Martin Sustrik committed
45 46 47 48
#include "err.hpp"
#include "config.hpp"
#include "i_poll_events.hpp"

49 50 51 52 53
#ifdef ZMQ_HAVE_WINDOWS
const zmq::epoll_t::epoll_fd_t zmq::epoll_t::epoll_retired_fd =
  INVALID_HANDLE_VALUE;
#endif

54
zmq::epoll_t::epoll_t (const zmq::thread_ctx_t &ctx_) :
55
    worker_poller_base_t (ctx_)
Martin Sustrik's avatar
Martin Sustrik committed
56
{
57
#ifdef ZMQ_IOTHREAD_POLLER_USE_EPOLL_CLOEXEC
58 59 60
    //  Setting this option result in sane behaviour when exec() functions
    //  are used. Old sockets are closed and don't block TCP ports, avoid
    //  leaks, etc.
61
    _epoll_fd = epoll_create1 (EPOLL_CLOEXEC);
62
#else
63
    _epoll_fd = epoll_create (1);
64
#endif
65
    errno_assert (_epoll_fd != epoll_retired_fd);
Martin Sustrik's avatar
Martin Sustrik committed
66 67
}

Martin Sustrik's avatar
Martin Sustrik committed
68
zmq::epoll_t::~epoll_t ()
Martin Sustrik's avatar
Martin Sustrik committed
69
{
70
    //  Wait till the worker thread exits.
71
    stop_worker ();
72

73
#ifdef ZMQ_HAVE_WINDOWS
74
    epoll_close (_epoll_fd);
75
#else
76
    close (_epoll_fd);
77
#endif
78 79
    for (retired_t::iterator it = _retired.begin (), end = _retired.end ();
         it != end; ++it) {
80
        LIBZMQ_DELETE (*it);
81
    }
Martin Sustrik's avatar
Martin Sustrik committed
82 83
}

84
zmq::epoll_t::handle_t zmq::epoll_t::add_fd (fd_t fd_, i_poll_events *events_)
Martin Sustrik's avatar
Martin Sustrik committed
85
{
86
    check_thread ();
87
    poll_entry_t *pe = new (std::nothrow) poll_entry_t;
88
    alloc_assert (pe);
Martin Sustrik's avatar
Martin Sustrik committed
89 90 91 92 93 94 95 96 97 98

    //  The memset is not actually needed. It's here to prevent debugging
    //  tools to complain about using uninitialised memory.
    memset (pe, 0, sizeof (poll_entry_t));

    pe->fd = fd_;
    pe->ev.events = 0;
    pe->ev.data.ptr = pe;
    pe->events = events_;

99
    int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_ADD, fd_, &pe->ev);
Martin Sustrik's avatar
Martin Sustrik committed
100 101 102
    errno_assert (rc != -1);

    //  Increase the load metric of the thread.
103
    adjust_load (1);
Martin Sustrik's avatar
Martin Sustrik committed
104

105
    return pe;
Martin Sustrik's avatar
Martin Sustrik committed
106 107
}

Martin Sustrik's avatar
Martin Sustrik committed
108
void zmq::epoll_t::rm_fd (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
109
{
110
    check_thread ();
111
    poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);
112
    int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_DEL, pe->fd, &pe->ev);
Martin Sustrik's avatar
Martin Sustrik committed
113 114
    errno_assert (rc != -1);
    pe->fd = retired_fd;
115
    _retired.push_back (pe);
Martin Sustrik's avatar
Martin Sustrik committed
116 117

    //  Decrease the load metric of the thread.
118
    adjust_load (-1);
Martin Sustrik's avatar
Martin Sustrik committed
119 120
}

Martin Sustrik's avatar
Martin Sustrik committed
121
void zmq::epoll_t::set_pollin (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
122
{
123
    check_thread ();
124
    poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);
Martin Sustrik's avatar
Martin Sustrik committed
125
    pe->ev.events |= EPOLLIN;
126
    int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
Martin Sustrik's avatar
Martin Sustrik committed
127 128 129
    errno_assert (rc != -1);
}

Martin Sustrik's avatar
Martin Sustrik committed
130
void zmq::epoll_t::reset_pollin (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
131
{
132
    check_thread ();
133 134
    poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);
    pe->ev.events &= ~(static_cast<short> (EPOLLIN));
135
    int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
Martin Sustrik's avatar
Martin Sustrik committed
136 137 138
    errno_assert (rc != -1);
}

Martin Sustrik's avatar
Martin Sustrik committed
139
void zmq::epoll_t::set_pollout (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
140
{
141
    check_thread ();
142
    poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);
Martin Sustrik's avatar
Martin Sustrik committed
143
    pe->ev.events |= EPOLLOUT;
144
    int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
Martin Sustrik's avatar
Martin Sustrik committed
145 146 147
    errno_assert (rc != -1);
}

Martin Sustrik's avatar
Martin Sustrik committed
148
void zmq::epoll_t::reset_pollout (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
149
{
150
    check_thread ();
151 152
    poll_entry_t *pe = static_cast<poll_entry_t *> (handle_);
    pe->ev.events &= ~(static_cast<short> (EPOLLOUT));
153
    int rc = epoll_ctl (_epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
Martin Sustrik's avatar
Martin Sustrik committed
154 155 156
    errno_assert (rc != -1);
}

Martin Sustrik's avatar
Martin Sustrik committed
157
void zmq::epoll_t::stop ()
Martin Sustrik's avatar
Martin Sustrik committed
158
{
159
    check_thread ();
Martin Sustrik's avatar
Martin Sustrik committed
160 161
}

Richard Newton's avatar
Richard Newton committed
162
int zmq::epoll_t::max_fds ()
163 164 165 166
{
    return -1;
}

Martin Sustrik's avatar
Martin Sustrik committed
167
void zmq::epoll_t::loop ()
Martin Sustrik's avatar
Martin Sustrik committed
168
{
169
    epoll_event ev_buf[max_io_events];
Martin Sustrik's avatar
Martin Sustrik committed
170

171
    while (true) {
172
        //  Execute any due timers.
173
        int timeout = static_cast<int> (execute_timers ());
Martin Sustrik's avatar
Martin Sustrik committed
174

175 176 177 178 179 180 181 182
        if (get_load () == 0) {
            if (timeout == 0)
                break;

            // TODO sleep for timeout
            continue;
        }

183
        //  Wait for events.
184
        int n = epoll_wait (_epoll_fd, &ev_buf[0], max_io_events,
185
                            timeout ? timeout : -1);
Martin Hurton's avatar
Martin Hurton committed
186 187
        if (n == -1) {
            errno_assert (errno == EINTR);
Martin Sustrik's avatar
Martin Sustrik committed
188
            continue;
Martin Hurton's avatar
Martin Hurton committed
189
        }
Martin Sustrik's avatar
Martin Sustrik committed
190

191
        for (int i = 0; i < n; i++) {
192 193
            poll_entry_t *pe =
              (static_cast<poll_entry_t *> (ev_buf[i].data.ptr));
Martin Sustrik's avatar
Martin Sustrik committed
194 195 196

            if (pe->fd == retired_fd)
                continue;
197
            if (ev_buf[i].events & (EPOLLERR | EPOLLHUP))
Martin Sustrik's avatar
Martin Sustrik committed
198 199
                pe->events->in_event ();
            if (pe->fd == retired_fd)
200 201
                continue;
            if (ev_buf[i].events & EPOLLOUT)
Martin Sustrik's avatar
Martin Sustrik committed
202 203 204
                pe->events->out_event ();
            if (pe->fd == retired_fd)
                continue;
205
            if (ev_buf[i].events & EPOLLIN)
Martin Sustrik's avatar
Martin Sustrik committed
206 207 208 209
                pe->events->in_event ();
        }

        //  Destroy retired event sources.
210 211
        for (retired_t::iterator it = _retired.begin (), end = _retired.end ();
             it != end; ++it) {
212
            LIBZMQ_DELETE (*it);
213
        }
214
        _retired.clear ();
Martin Sustrik's avatar
Martin Sustrik committed
215 216 217 218
    }
}

#endif