epoll.cpp 4.52 KB
Newer Older
Martin Sustrik's avatar
Martin Sustrik committed
1
/*
2
    Copyright (c) 2007-2010 iMatix Corporation
Martin Sustrik's avatar
Martin Sustrik committed
3 4 5 6

    This file is part of 0MQ.

    0MQ is free software; you can redistribute it and/or modify it under
7
    the terms of the GNU Lesser General Public License as published by
Martin Sustrik's avatar
Martin Sustrik committed
8 9 10 11 12 13
    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
14
    GNU Lesser General Public License for more details.
Martin Sustrik's avatar
Martin Sustrik committed
15

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

#include "platform.hpp"

Martin Sustrik's avatar
Martin Sustrik committed
22
#ifdef ZMQ_HAVE_LINUX
Martin Sustrik's avatar
Martin Sustrik committed
23 24 25 26 27 28

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

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

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

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

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

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

    //  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.
71
    adjust_load (1);
Martin Sustrik's avatar
Martin Sustrik committed
72

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

Martin Sustrik's avatar
Martin Sustrik committed
76
void zmq::epoll_t::rm_fd (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
77
{
78
    poll_entry_t *pe = (poll_entry_t*) handle_;
Martin Sustrik's avatar
Martin Sustrik committed
79 80 81 82 83 84
    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.
85
    adjust_load (-1);
Martin Sustrik's avatar
Martin Sustrik committed
86 87
}

Martin Sustrik's avatar
Martin Sustrik committed
88
void zmq::epoll_t::set_pollin (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
89
{
90
    poll_entry_t *pe = (poll_entry_t*) handle_;
Martin Sustrik's avatar
Martin Sustrik committed
91 92 93 94 95
    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
96
void zmq::epoll_t::reset_pollin (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
97
{
98
    poll_entry_t *pe = (poll_entry_t*) handle_;
Martin Sustrik's avatar
Martin Sustrik committed
99 100 101 102 103
    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
104
void zmq::epoll_t::set_pollout (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
105
{
106
    poll_entry_t *pe = (poll_entry_t*) handle_;
Martin Sustrik's avatar
Martin Sustrik committed
107 108 109 110 111
    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
112
void zmq::epoll_t::reset_pollout (handle_t handle_)
Martin Sustrik's avatar
Martin Sustrik committed
113
{
114
    poll_entry_t *pe = (poll_entry_t*) handle_;
Martin Sustrik's avatar
Martin Sustrik committed
115 116 117 118 119
    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
120
void zmq::epoll_t::start ()
Martin Sustrik's avatar
Martin Sustrik committed
121 122 123 124
{
    worker.start (worker_routine, this);
}

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

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

    while (!stopping) {

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

139 140 141 142
        //  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
143
            continue;
144
        errno_assert (n != -1);
Martin Sustrik's avatar
Martin Sustrik committed
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170

        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 ();
              it ++)
            delete *it;
        retired.clear ();
    }
}

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

#endif