コード例 #1
0
ファイル: tevent_epoll.c プロジェクト: atlant2011/samba
/*
  reopen the epoll handle when our pid changes
  see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an 
  demonstration of why this is needed
 */
static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
{
	struct tevent_fd *fde;

	if (epoll_ev->pid == getpid()) {
		return;
	}

	close(epoll_ev->epoll_fd);
	epoll_ev->epoll_fd = epoll_create(64);
	if (epoll_ev->epoll_fd == -1) {
		tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
			     "Failed to recreate epoll handle after fork\n");
		return;
	}

	if (!ev_set_close_on_exec(epoll_ev->epoll_fd)) {
		tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING,
			     "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
	}

	epoll_ev->pid = getpid();
	for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
		epoll_add_event(epoll_ev, fde);
	}
}
コード例 #2
0
ファイル: tevent_port.c プロジェクト: DanilKorotenko/samba
/*
  Reopen the port handle when our pid changes.
 */
static int port_check_reopen(struct port_event_context *port_ev)
{
	struct tevent_fd *fde;

	if (port_ev->pid == getpid()) {
		return 0;
	}

	close(port_ev->port_fd);
	port_ev->port_fd = port_create();
	if (port_ev->port_fd == -1) {
		tevent_debug(port_ev->ev, TEVENT_DEBUG_FATAL,
				"port_create() failed");
		return -1;
	}

	if (!ev_set_close_on_exec(port_ev->port_fd)) {
		tevent_debug(port_ev->ev, TEVENT_DEBUG_WARNING,
			     "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
	}

	port_ev->pid = getpid();
	for (fde=port_ev->ev->fd_events;fde;fde=fde->next) {
		fde->additional_flags &= PORT_ADDITIONAL_FD_FLAG_HAS_ASSOCIATION;
		if (port_update_event(port_ev, fde) != 0) {
			return -1;
		}
	}
	return 0;
}
コード例 #3
0
ファイル: tevent_standard.c プロジェクト: AllardJ/Tomato
/*
  called when a epoll call fails, and we should fallback
  to using select
*/
static void epoll_fallback_to_select(struct std_event_context *std_ev, const char *reason)
{
	tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
		     "%s (%s) - falling back to select()\n",
		     reason, strerror(errno));
	close(std_ev->epoll_fd);
	std_ev->epoll_fd = -1;
	talloc_set_destructor(std_ev, NULL);
}
コード例 #4
0
ファイル: tevent_port.c プロジェクト: DanilKorotenko/samba
/*
 Init the port fd
*/
static int port_init_ctx(struct port_event_context *port_ev)
{
	port_ev->port_fd = port_create();
	if (port_ev->port_fd == -1) {
		tevent_debug(port_ev->ev, TEVENT_DEBUG_FATAL,
			     "Failed to create port handle.\n");
		return -1;
	}

	if (!ev_set_close_on_exec(port_ev->port_fd)) {
		tevent_debug(port_ev->ev, TEVENT_DEBUG_WARNING,
			     "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
	}

	port_ev->pid = getpid();
	talloc_set_destructor(port_ev, port_ctx_destructor);

	return 0;
}
コード例 #5
0
ファイル: tevent_epoll.c プロジェクト: AIdrifter/samba
/*
 init the epoll fd
*/
static int epoll_init_ctx(struct epoll_event_context *epoll_ev)
{
	epoll_ev->epoll_fd = epoll_create(64);
	if (epoll_ev->epoll_fd == -1) {
		tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
			     "Failed to create epoll handle.\n");
		return -1;
	}

	if (!ev_set_close_on_exec(epoll_ev->epoll_fd)) {
		tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING,
			     "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
	}

	epoll_ev->pid = getpid();
	talloc_set_destructor(epoll_ev, epoll_ctx_destructor);

	return 0;
}
コード例 #6
0
ファイル: tevent_epoll.c プロジェクト: AIdrifter/samba
/*
  called when a epoll call fails
*/
static void epoll_panic(struct epoll_event_context *epoll_ev,
			const char *reason, bool replay)
{
	struct tevent_context *ev = epoll_ev->ev;
	bool (*panic_fallback)(struct tevent_context *ev, bool replay);

	panic_fallback = epoll_ev->panic_fallback;

	if (epoll_ev->panic_state != NULL) {
		*epoll_ev->panic_state = true;
	}

	if (epoll_ev->panic_force_replay) {
		replay = true;
	}

	TALLOC_FREE(ev->additional_data);

	if (panic_fallback == NULL) {
		tevent_debug(ev, TEVENT_DEBUG_FATAL,
			"%s (%s) replay[%u] - calling abort()\n",
			reason, strerror(errno), (unsigned)replay);
		abort();
	}

	tevent_debug(ev, TEVENT_DEBUG_ERROR,
		     "%s (%s) replay[%u] - calling panic_fallback\n",
		     reason, strerror(errno), (unsigned)replay);

	if (!panic_fallback(ev, replay)) {
		/* Fallback failed. */
		tevent_debug(ev, TEVENT_DEBUG_FATAL,
			"%s (%s) replay[%u] - calling abort()\n",
			reason, strerror(errno), (unsigned)replay);
		abort();
	}
}
コード例 #7
0
ファイル: tevent_standard.c プロジェクト: AllardJ/Tomato
/*
  reopen the epoll handle when our pid changes
  see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an 
  demonstration of why this is needed
 */
static void epoll_check_reopen(struct std_event_context *std_ev)
{
	struct tevent_fd *fde;

	if (std_ev->pid == getpid()) {
		return;
	}

	close(std_ev->epoll_fd);
	std_ev->epoll_fd = epoll_create(64);
	if (std_ev->epoll_fd == -1) {
		tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
			     "Failed to recreate epoll handle after fork\n");
		return;
	}
	std_ev->pid = getpid();
	for (fde=std_ev->ev->fd_events;fde;fde=fde->next) {
		epoll_add_event(std_ev, fde);
	}
}
コード例 #8
0
ファイル: tevent_epoll.c プロジェクト: atlant2011/samba
/*
 delete the epoll event for given fd_event
*/
static void epoll_del_event(struct epoll_event_context *epoll_ev, struct tevent_fd *fde)
{
	struct epoll_event event;

	if (epoll_ev->epoll_fd == -1) return;

	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_REPORT_ERROR;

	/* if there's no epoll_event, we don't need to delete it */
	if (!(fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) return;

	ZERO_STRUCT(event);
	event.events = epoll_map_flags(fde->flags);
	event.data.ptr = fde;
	if (epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_DEL, fde->fd, &event) != 0) {
		tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
			     "epoll_del_event failed! probable early close bug (%s)\n",
			     strerror(errno));
	}
	fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
}
コード例 #9
0
ファイル: tevent_epoll.c プロジェクト: AIdrifter/samba
/*
  reopen the epoll handle when our pid changes
  see http://junkcode.samba.org/ftp/unpacked/junkcode/epoll_fork.c for an 
  demonstration of why this is needed
 */
static void epoll_check_reopen(struct epoll_event_context *epoll_ev)
{
	struct tevent_fd *fde;
	bool *caller_panic_state = epoll_ev->panic_state;
	bool panic_triggered = false;

	if (epoll_ev->pid == getpid()) {
		return;
	}

	close(epoll_ev->epoll_fd);
	epoll_ev->epoll_fd = epoll_create(64);
	if (epoll_ev->epoll_fd == -1) {
		epoll_panic(epoll_ev, "epoll_create() failed", false);
		return;
	}

	if (!ev_set_close_on_exec(epoll_ev->epoll_fd)) {
		tevent_debug(epoll_ev->ev, TEVENT_DEBUG_WARNING,
			     "Failed to set close-on-exec, file descriptor may be leaked to children.\n");
	}

	epoll_ev->pid = getpid();
	epoll_ev->panic_state = &panic_triggered;
	for (fde=epoll_ev->ev->fd_events;fde;fde=fde->next) {
		fde->additional_flags &= ~EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT;
		epoll_update_event(epoll_ev, fde);

		if (panic_triggered) {
			if (caller_panic_state != NULL) {
				*caller_panic_state = true;
			}
			return;
		}
	}
	epoll_ev->panic_state = NULL;
}
コード例 #10
0
ファイル: tevent_poll.c プロジェクト: AIdrifter/samba
/*
  event loop handling using poll()
*/
static int poll_event_loop_poll(struct tevent_context *ev,
				struct timeval *tvalp)
{
	struct poll_event_context *poll_ev = talloc_get_type_abort(
		ev->additional_data, struct poll_event_context);
	int pollrtn;
	int timeout = -1;
	int poll_errno;
	struct tevent_fd *fde = NULL;
	unsigned i;

	if (ev->signal_events && tevent_common_check_signal(ev)) {
		return 0;
	}

	if (tvalp != NULL) {
		timeout = tvalp->tv_sec * 1000;
		timeout += (tvalp->tv_usec + 999) / 1000;
	}

	poll_event_drain_signal_fd(poll_ev);

	if (!poll_event_setup_fresh(ev, poll_ev)) {
		return -1;
	}

	tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_BEFORE_WAIT);
	pollrtn = poll(poll_ev->fds, poll_ev->num_fds, timeout);
	poll_errno = errno;
	tevent_trace_point_callback(poll_ev->ev, TEVENT_TRACE_AFTER_WAIT);

	if (pollrtn == -1 && poll_errno == EINTR && ev->signal_events) {
		tevent_common_check_signal(ev);
		return 0;
	}

	if (pollrtn == 0 && tvalp) {
		/* we don't care about a possible delay here */
		tevent_common_loop_timer_delay(ev);
		return 0;
	}

	if (pollrtn <= 0) {
		/*
		 * No fd's ready
		 */
		return 0;
	}

	/* at least one file descriptor is ready - check
	   which ones and call the handler, being careful to allow
	   the handler to remove itself when called */

	for (fde = ev->fd_events; fde; fde = fde->next) {
		unsigned idx = fde->additional_flags;
		struct pollfd *pfd;
		uint16_t flags = 0;

		if (idx == UINT64_MAX) {
			continue;
		}

		pfd = &poll_ev->fds[idx];

		if (pfd->revents & POLLNVAL) {
			/*
			 * the socket is dead! this should never
			 * happen as the socket should have first been
			 * made readable and that should have removed
			 * the event, so this must be a bug.
			 *
			 * We ignore it here to match the epoll
			 * behavior.
			 */
			tevent_debug(ev, TEVENT_DEBUG_ERROR,
				     "POLLNVAL on fde[%p] fd[%d] - disabling\n",
				     fde, pfd->fd);
			poll_ev->fdes[idx] = NULL;
			poll_ev->deleted = true;
			DLIST_REMOVE(ev->fd_events, fde);
			fde->event_ctx = NULL;
			continue;
		}

		if (pfd->revents & (POLLHUP|POLLERR)) {
			/* If we only wait for TEVENT_FD_WRITE, we
			   should not tell the event handler about it,
			   and remove the writable flag, as we only
			   report errors when waiting for read events
			   to match the select behavior. */
			if (!(fde->flags & TEVENT_FD_READ)) {
				TEVENT_FD_NOT_WRITEABLE(fde);
				continue;
			}
			flags |= TEVENT_FD_READ;
		}
		if (pfd->revents & POLLIN) {
			flags |= TEVENT_FD_READ;
		}
		if (pfd->revents & POLLOUT) {
			flags |= TEVENT_FD_WRITE;
		}
		/*
		 * Note that fde->flags could be changed when using
		 * the poll_mt backend together with threads,
		 * that why we need to check pfd->revents and fde->flags
		 */
		flags &= fde->flags;
		if (flags != 0) {
			DLIST_DEMOTE(ev->fd_events, fde, struct tevent_fd);
			fde->handler(ev, fde, flags, fde->private_data);
			return 0;
		}
	}
コード例 #11
0
ファイル: tevent_epoll.c プロジェクト: AIdrifter/samba
static int epoll_add_multiplex_fd(struct epoll_event_context *epoll_ev,
				  struct tevent_fd *add_fde)
{
	struct epoll_event event;
	struct tevent_fd *mpx_fde;
	int ret;

	/* Find the existing fde that caused the EEXIST error. */
	for (mpx_fde = epoll_ev->ev->fd_events; mpx_fde; mpx_fde = mpx_fde->next) {
		if (mpx_fde->fd != add_fde->fd) {
			continue;
		}

		if (mpx_fde == add_fde) {
			continue;
		}

		break;
	}
	if (mpx_fde == NULL) {
		tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
			     "can't find multiplex fde for fd[%d]",
			     add_fde->fd);
		return -1;
	}

	if (mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX) {
		/* Logic error. Can't have more than 2 multiplexed fde's. */
		tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
			     "multiplex fde for fd[%d] is already multiplexed\n",
			     mpx_fde->fd);
		return -1;
	}

	/*
	 * The multiplex fde must have the same fd, and also
	 * already have an epoll event attached.
	 */
	if (!(mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_HAS_EVENT)) {
		/* Logic error. Can't have more than 2 multiplexed fde's. */
		tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
			     "multiplex fde for fd[%d] has no event\n",
			     mpx_fde->fd);
		return -1;
	}

	/* Modify the mpx_fde to add in the new flags. */
	ZERO_STRUCT(event);
	event.events = epoll_map_flags(mpx_fde->flags);
	event.events |= epoll_map_flags(add_fde->flags);
	event.data.ptr = mpx_fde;
	ret = epoll_ctl(epoll_ev->epoll_fd, EPOLL_CTL_MOD, mpx_fde->fd, &event);
	if (ret != 0 && errno == EBADF) {
		tevent_debug(epoll_ev->ev, TEVENT_DEBUG_ERROR,
			     "EPOLL_CTL_MOD EBADF for "
			     "add_fde[%p] mpx_fde[%p] fd[%d] - disabling\n",
			     add_fde, mpx_fde, add_fde->fd);
		DLIST_REMOVE(epoll_ev->ev->fd_events, mpx_fde);
		mpx_fde->event_ctx = NULL;
		DLIST_REMOVE(epoll_ev->ev->fd_events, add_fde);
		add_fde->event_ctx = NULL;
		return 0;
	} else if (ret != 0) {
		return ret;
	}

	/*
	 * Make each fde->additional_data pointers point at each other
	 * so we can look them up from each other. They are now paired.
	 */
	mpx_fde->additional_data = (struct tevent_fd *)add_fde;
	add_fde->additional_data = (struct tevent_fd *)mpx_fde;

	/* Now flag both fde's as being multiplexed. */
	mpx_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;
	add_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_HAS_MPX;

	/* we need to keep the GOT_ERROR flag */
	if (mpx_fde->additional_flags & EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR) {
		add_fde->additional_flags |= EPOLL_ADDITIONAL_FD_FLAG_GOT_ERROR;
	}

	return 0;
}
コード例 #12
0
ファイル: tevent_standard.c プロジェクト: AllardJ/Tomato
/*
  event loop handling using select()
*/
static int std_event_loop_select(struct std_event_context *std_ev, struct timeval *tvalp)
{
	fd_set r_fds, w_fds;
	struct tevent_fd *fde;
	int selrtn;

	/* we maybe need to recalculate the maxfd */
	if (std_ev->maxfd == EVENT_INVALID_MAXFD) {
		calc_maxfd(std_ev);
	}

	FD_ZERO(&r_fds);
	FD_ZERO(&w_fds);

	/* setup any fd events */
	for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
		if (fde->fd < 0 || fde->fd >= FD_SETSIZE) {
			std_ev->exit_code = EBADF;
			return -1;
		}

		if (fde->flags & TEVENT_FD_READ) {
			FD_SET(fde->fd, &r_fds);
		}
		if (fde->flags & TEVENT_FD_WRITE) {
			FD_SET(fde->fd, &w_fds);
		}
	}

	if (std_ev->ev->signal_events &&
	    tevent_common_check_signal(std_ev->ev)) {
		return 0;
	}

	selrtn = select(std_ev->maxfd+1, &r_fds, &w_fds, NULL, tvalp);

	if (selrtn == -1 && errno == EINTR && 
	    std_ev->ev->signal_events) {
		tevent_common_check_signal(std_ev->ev);
		return 0;
	}

	if (selrtn == -1 && errno == EBADF) {
		/* the socket is dead! this should never
		   happen as the socket should have first been
		   made readable and that should have removed
		   the event, so this must be a bug. This is a
		   fatal error. */
		tevent_debug(std_ev->ev, TEVENT_DEBUG_FATAL,
			     "ERROR: EBADF on std_event_loop_once\n");
		std_ev->exit_code = EBADF;
		return -1;
	}

	if (selrtn == 0 && tvalp) {
		/* we don't care about a possible delay here */
		tevent_common_loop_timer_delay(std_ev->ev);
		return 0;
	}

	if (selrtn > 0) {
		/* at least one file descriptor is ready - check
		   which ones and call the handler, being careful to allow
		   the handler to remove itself when called */
		for (fde = std_ev->ev->fd_events; fde; fde = fde->next) {
			uint16_t flags = 0;

			if (FD_ISSET(fde->fd, &r_fds)) flags |= TEVENT_FD_READ;
			if (FD_ISSET(fde->fd, &w_fds)) flags |= TEVENT_FD_WRITE;
			if (flags) {
				fde->handler(std_ev->ev, fde, flags, fde->private_data);
				break;
			}
		}
	}

	return 0;
}		
コード例 #13
0
ファイル: tevent_epoll.c プロジェクト: atlant2011/samba
/*
  called when a epoll call fails
*/
static void epoll_panic(struct epoll_event_context *epoll_ev, const char *reason)
{
	tevent_debug(epoll_ev->ev, TEVENT_DEBUG_FATAL,
		 "%s (%s) - calling abort()\n", reason, strerror(errno));
	abort();
}