epoll.cpp 4.63 KB
Newer Older
Martin Sustrik's avatar
Martin Sustrik committed
1
/*
Martin Sustrik's avatar
Martin Sustrik committed
2
    Copyright (c) 2009-2011 250bpm s.r.o.
3
    Copyright (c) 2007-2009 iMatix Corporation
4
    Copyright (c) 2007-2011 Other contributors as noted in the AUTHORS file
Martin Sustrik's avatar
Martin Sustrik committed
5 6 7 8

    This file is part of 0MQ.

    0MQ is free software; you can redistribute it and/or modify it under
9
    the terms of the GNU Lesser General Public License as published by
Martin Sustrik's avatar
Martin Sustrik committed
10 11 12 13 14 15
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    0MQ 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
16
    GNU Lesser General Public License for more details.
Martin Sustrik's avatar
Martin Sustrik committed
17

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

22 23
#include "epoll.hpp"
#if defined ZMQ_USE_EPOLL
Martin Sustrik's avatar
Martin Sustrik committed
24 25 26 27 28 29

#include <sys/epoll.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <algorithm>
30
#include <new>
Martin Sustrik's avatar
Martin Sustrik committed
31 32 33 34 35 36

#include "epoll.hpp"
#include "err.hpp"
#include "config.hpp"
#include "i_poll_events.hpp"

Martin Sustrik's avatar
Martin Sustrik committed
37
zmq::epoll_t::epoll_t () :
Martin Sustrik's avatar
Martin Sustrik committed
38 39 40 41 42 43
    stopping (false)
{
    epoll_fd = epoll_create (1);
    errno_assert (epoll_fd != -1);
}

Martin Sustrik's avatar
Martin Sustrik committed
44
zmq::epoll_t::~epoll_t ()
Martin Sustrik's avatar
Martin Sustrik committed
45
{
46 47 48
    //  Wait till the worker thread exits.
    worker.stop ();

49
    close (epoll_fd);
50
    for (retired_t::iterator it = retired.begin (); it != retired.end (); ++it)
Martin Sustrik's avatar
Martin Sustrik committed
51 52 53
        delete *it;
}

54
zmq::epoll_t::handle_t zmq::epoll_t::add_fd (fd_t fd_, i_poll_events *events_)
Martin Sustrik's avatar
Martin Sustrik committed
55
{
56
    poll_entry_t *pe = new (std::nothrow) poll_entry_t;
57
    alloc_assert (pe);
Martin Sustrik's avatar
Martin Sustrik committed
58 59 60 61 62 63 64 65 66 67 68 69 70 71

    //  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_;

    int rc = epoll_ctl (epoll_fd, EPOLL_CTL_ADD, fd_, &pe->ev);
    errno_assert (rc != -1);

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

74
    return pe;
Martin Sustrik's avatar
Martin Sustrik committed
75 76
}

Martin Sustrik's avatar
Martin Sustrik committed
77
void zmq::epoll_t::rm_fd (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
78
{
79
    poll_entry_t *pe = (poll_entry_t*) handle_;
Martin Sustrik's avatar
Martin Sustrik committed
80 81 82 83 84 85
    int rc = epoll_ctl (epoll_fd, EPOLL_CTL_DEL, pe->fd, &pe->ev);
    errno_assert (rc != -1);
    pe->fd = retired_fd;
    retired.push_back (pe);

    //  Decrease the load metric of the thread.
86
    adjust_load (-1);
Martin Sustrik's avatar
Martin Sustrik committed
87 88
}

Martin Sustrik's avatar
Martin Sustrik committed
89
void zmq::epoll_t::set_pollin (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
90
{
91
    poll_entry_t *pe = (poll_entry_t*) handle_;
Martin Sustrik's avatar
Martin Sustrik committed
92 93 94 95 96
    pe->ev.events |= EPOLLIN;
    int rc = epoll_ctl (epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
    errno_assert (rc != -1);
}

Martin Sustrik's avatar
Martin Sustrik committed
97
void zmq::epoll_t::reset_pollin (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
98
{
99
    poll_entry_t *pe = (poll_entry_t*) handle_;
Martin Sustrik's avatar
Martin Sustrik committed
100 101 102 103 104
    pe->ev.events &= ~((short) EPOLLIN);
    int rc = epoll_ctl (epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
    errno_assert (rc != -1);
}

Martin Sustrik's avatar
Martin Sustrik committed
105
void zmq::epoll_t::set_pollout (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
106
{
107
    poll_entry_t *pe = (poll_entry_t*) handle_;
Martin Sustrik's avatar
Martin Sustrik committed
108 109 110 111 112
    pe->ev.events |= EPOLLOUT;
    int rc = epoll_ctl (epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
    errno_assert (rc != -1);
}

Martin Sustrik's avatar
Martin Sustrik committed
113
void zmq::epoll_t::reset_pollout (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
114
{
115
    poll_entry_t *pe = (poll_entry_t*) handle_;
Martin Sustrik's avatar
Martin Sustrik committed
116 117 118 119 120
    pe->ev.events &= ~((short) EPOLLOUT);
    int rc = epoll_ctl (epoll_fd, EPOLL_CTL_MOD, pe->fd, &pe->ev);
    errno_assert (rc != -1);
}

Martin Sustrik's avatar
Martin Sustrik committed
121
void zmq::epoll_t::start ()
Martin Sustrik's avatar
Martin Sustrik committed
122 123 124 125
{
    worker.start (worker_routine, this);
}

Martin Sustrik's avatar
Martin Sustrik committed
126
void zmq::epoll_t::stop ()
Martin Sustrik's avatar
Martin Sustrik committed
127 128 129 130
{
    stopping = true;
}

Martin Sustrik's avatar
Martin Sustrik committed
131
void zmq::epoll_t::loop ()
Martin Sustrik's avatar
Martin Sustrik committed
132 133 134 135 136
{
    epoll_event ev_buf [max_io_events];

    while (!stopping) {

137
        //  Execute any due timers.
138
        int timeout = (int) execute_timers ();
Martin Sustrik's avatar
Martin Sustrik committed
139

140 141 142 143
        //  Wait for events.
        int n = epoll_wait (epoll_fd, &ev_buf [0], max_io_events,
            timeout ? timeout : -1);
        if (n == -1 && errno == EINTR)
Martin Sustrik's avatar
Martin Sustrik committed
144
            continue;
145
        errno_assert (n != -1);
Martin Sustrik's avatar
Martin Sustrik committed
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165

        for (int i = 0; i < n; i ++) {
            poll_entry_t *pe = ((poll_entry_t*) ev_buf [i].data.ptr);

            if (pe->fd == retired_fd)
                continue;
            if (ev_buf [i].events & (EPOLLERR | EPOLLHUP))
                pe->events->in_event ();
            if (pe->fd == retired_fd)
               continue;
            if (ev_buf [i].events & EPOLLOUT)
                pe->events->out_event ();
            if (pe->fd == retired_fd)
                continue;
            if (ev_buf [i].events & EPOLLIN)
                pe->events->in_event ();
        }

        //  Destroy retired event sources.
        for (retired_t::iterator it = retired.begin (); it != retired.end ();
166
              ++it)
Martin Sustrik's avatar
Martin Sustrik committed
167 168 169 170 171
            delete *it;
        retired.clear ();
    }
}

Martin Sustrik's avatar
Martin Sustrik committed
172
void zmq::epoll_t::worker_routine (void *arg_)
Martin Sustrik's avatar
Martin Sustrik committed
173 174 175 176 177
{
    ((epoll_t*) arg_)->loop ();
}

#endif