Пример #1
0
static int
event_select_on_epoll (struct event_pool *event_pool, int fd, int idx,
                       int poll_in, int poll_out)
{
        int ret = -1;
	struct event_slot_epoll *slot = NULL;
        struct epoll_event epoll_event = {0, };
        struct event_data *ev_data = (void *)&epoll_event.data;


        GF_VALIDATE_OR_GOTO ("event", event_pool, out);

	slot = event_slot_get (event_pool, idx);

	assert (slot->fd == fd);

	LOCK (&slot->lock);
	{
		__slot_update_events (slot, poll_in, poll_out);

		epoll_event.events = slot->events;
		ev_data->idx = idx;
		ev_data->gen = slot->gen;

		if (slot->in_handler)
			/* in_handler indicates at least one thread
			   executing event_dispatch_epoll_handler()
			   which will perform epoll_ctl(EPOLL_CTL_MOD)
			   anyways (because of EPOLLET)

			   This not only saves a system call, but also
			   avoids possibility of another epoll thread
			   parallely picking up the next event while the
			   ongoing handler is still in progress (and
			   resulting in unnecessary contention on
			   rpc_transport_t->mutex).
			*/
			goto unlock;

		ret = epoll_ctl (event_pool->fd, EPOLL_CTL_MOD, fd,
				 &epoll_event);
		if (ret == -1) {
			gf_msg ("epoll", GF_LOG_ERROR, errno,
                                LG_MSG_EPOLL_FD_MODIFY_FAILED, "failed to "
                                "modify fd(=%d) events to %d", fd,
                                epoll_event.events);
		}
	}
unlock:
	UNLOCK (&slot->lock);

	event_slot_unref (event_pool, slot, idx);

out:
        return idx;
}
Пример #2
0
int
event_register_epoll (struct event_pool *event_pool, int fd,
                      event_handler_t handler,
                      void *data, int poll_in, int poll_out)
{
        int                 idx = -1;
        int                 ret = -1;
        int             destroy = 0;
        struct epoll_event  epoll_event = {0, };
        struct event_data  *ev_data = (void *)&epoll_event.data;
	struct event_slot_epoll *slot = NULL;


        GF_VALIDATE_OR_GOTO ("event", event_pool, out);

        /* TODO: Even with the below check, there is a possiblity of race,
         * What if the destroy mode is set after the check is done.
         * Not sure of the best way to prevent this race, ref counting
         * is one possibility.
         * There is no harm in registering and unregistering the fd
         * even after destroy mode is set, just that such fds will remain
         * open until unregister is called, also the events on that fd will be
         * notified, until one of the poller thread is alive.
         */
        pthread_mutex_lock (&event_pool->mutex);
        {
                destroy = event_pool->destroy;
        }
        pthread_mutex_unlock (&event_pool->mutex);

        if (destroy == 1)
               goto out;

	idx = event_slot_alloc (event_pool, fd);
	if (idx == -1) {
		gf_log ("epoll", GF_LOG_ERROR,
			"could not find slot for fd=%d", fd);
		return -1;
	}

	slot = event_slot_get (event_pool, idx);

	assert (slot->fd == fd);

	LOCK (&slot->lock);
	{
		/* make epoll 'singleshot', which
		   means we need to re-add the fd with
		   epoll_ctl(EPOLL_CTL_MOD) after delivery of every
		   single event. This assures us that while a poller
		   thread has picked up and is processing an event,
		   another poller will not try to pick this at the same
		   time as well.
		*/

		slot->events = EPOLLPRI | EPOLLONESHOT;
		slot->handler = handler;
		slot->data = data;

		__slot_update_events (slot, poll_in, poll_out);

		epoll_event.events = slot->events;
		ev_data->idx = idx;
		ev_data->gen = slot->gen;

		ret = epoll_ctl (event_pool->fd, EPOLL_CTL_ADD, fd,
				 &epoll_event);
		/* check ret after UNLOCK() to avoid deadlock in
		   event_slot_unref()
		*/
	}
	UNLOCK (&slot->lock);

	if (ret == -1) {
		gf_log ("epoll", GF_LOG_ERROR,
			"failed to add fd(=%d) to epoll fd(=%d) (%s)",
			fd, event_pool->fd, strerror (errno));

		event_slot_unref (event_pool, slot, idx);
		idx = -1;
	}

	/* keep slot->ref (do not event_slot_unref) if successful */
out:
        return idx;
}