Example #1
0
static int
event_unregister_epoll_common (struct event_pool *event_pool, int fd,
			       int idx, int do_close)
{
        int  ret = -1;
	struct event_slot_epoll *slot = NULL;

        GF_VALIDATE_OR_GOTO ("event", event_pool, out);

	slot = event_slot_get (event_pool, idx);

	assert (slot->fd == fd);

	LOCK (&slot->lock);
	{
                ret = epoll_ctl (event_pool->fd, EPOLL_CTL_DEL, fd, NULL);

                if (ret == -1) {
                        gf_log ("epoll", GF_LOG_ERROR,
                                "fail to del fd(=%d) from epoll fd(=%d) (%s)",
                                fd, event_pool->fd, strerror (errno));
                        goto unlock;
                }

		slot->do_close = do_close;
		slot->gen++; /* detect unregister in dispatch_handler() */
        }
unlock:
	UNLOCK (&slot->lock);

	event_slot_unref (event_pool, slot, idx); /* one for event_register() */
	event_slot_unref (event_pool, slot, idx); /* one for event_slot_get() */
out:
        return ret;
}
Example #2
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;
}
Example #3
0
static int
event_dispatch_epoll_handler (struct event_pool *event_pool,
                              struct epoll_event *event)
{
        struct event_data  *ev_data = NULL;
	struct event_slot_epoll *slot = NULL;
        event_handler_t     handler = NULL;
        void               *data = NULL;
        int                 idx = -1;
	int                 gen = -1;
        int                 ret = -1;
	int                 fd = -1;

	ev_data = (void *)&event->data;
        handler = NULL;
        data = NULL;

	idx = ev_data->idx;
	gen = ev_data->gen;

	slot = event_slot_get (event_pool, idx);

	LOCK (&slot->lock);
	{
		fd = slot->fd;
		if (fd == -1) {
			gf_log ("epoll", GF_LOG_ERROR,
				"stale fd found on idx=%d, gen=%d, events=%d, "
				"slot->gen=%d",
				idx, gen, event->events, slot->gen);
			/* fd got unregistered in another thread */
			goto pre_unlock;
		}

		if (gen != slot->gen) {
			gf_log ("epoll", GF_LOG_ERROR,
				"generation mismatch on idx=%d, gen=%d, "
				"slot->gen=%d, slot->fd=%d",
				idx, gen, slot->gen, slot->fd);
			/* slot was re-used and therefore is another fd! */
			goto pre_unlock;
		}

		handler = slot->handler;
		data = slot->data;

		slot->in_handler++;
	}
pre_unlock:
	UNLOCK (&slot->lock);

        if (!handler)
		goto out;

	ret = handler (fd, idx, data,
		       (event->events & (EPOLLIN|EPOLLPRI)),
		       (event->events & (EPOLLOUT)),
		       (event->events & (EPOLLERR|EPOLLHUP)));

	LOCK (&slot->lock);
	{
		slot->in_handler--;

		if (gen != slot->gen) {
			/* event_unregister() happened while we were
			   in handler()
			*/
			gf_log ("epoll", GF_LOG_DEBUG,
				"generation bumped on idx=%d from "
				"gen=%d to slot->gen=%d, fd=%d, "
				"slot->fd=%d",
				idx, gen, slot->gen, fd, slot->fd);
			goto post_unlock;
		}

		/* This call also picks up the changes made by another
		   thread calling event_select_on_epoll() while this
		   thread was busy in handler()
		*/
                if (slot->in_handler == 0) {
                        event->events = slot->events;
                        ret = epoll_ctl (event_pool->fd, EPOLL_CTL_MOD,
                                         fd, event);
                }
	}
post_unlock:
	UNLOCK (&slot->lock);
out:
	event_slot_unref (event_pool, slot, idx);

        return ret;
}
Example #4
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;
}