⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 io.c

📁 最新的libusb库
💻 C
📖 第 1 页 / 共 5 页
字号:
	list_for_each_entry(transfer, &ctx->flying_transfers, list) {		struct timeval *cur_tv = &transfer->timeout;		/* if we've reached transfers of infinite timeout, we're all done */		if (!timerisset(cur_tv))			goto out;		/* ignore timeouts we've already handled */		if (transfer->flags & USBI_TRANSFER_TIMED_OUT)			continue;		/* if transfer has non-expired timeout, nothing more to do */		if ((cur_tv->tv_sec > systime.tv_sec) ||				(cur_tv->tv_sec == systime.tv_sec &&					cur_tv->tv_usec > systime.tv_usec))			goto out;			/* otherwise, we've got an expired timeout to handle */		handle_timeout(transfer);	}out:	pthread_mutex_unlock(&ctx->flying_transfers_lock);	return r;}/* do the actual event handling. assumes that no other thread is concurrently * doing the same thing. */static int handle_events(struct libusb_context *ctx, struct timeval *tv){	int r;	struct usbi_pollfd *ipollfd;	nfds_t nfds = 0;	struct pollfd *fds;	int i = -1;	int timeout_ms;	pthread_mutex_lock(&ctx->pollfds_lock);	list_for_each_entry(ipollfd, &ctx->pollfds, list)		nfds++;	/* TODO: malloc when number of fd's changes, not on every poll */	fds = malloc(sizeof(*fds) * nfds);	if (!fds)		return LIBUSB_ERROR_NO_MEM;	list_for_each_entry(ipollfd, &ctx->pollfds, list) {		struct libusb_pollfd *pollfd = &ipollfd->pollfd;		int fd = pollfd->fd;		i++;		fds[i].fd = fd;		fds[i].events = pollfd->events;		fds[i].revents = 0;	}	pthread_mutex_unlock(&ctx->pollfds_lock);	timeout_ms = (tv->tv_sec * 1000) + (tv->tv_usec / 1000);	/* round up to next millisecond */	if (tv->tv_usec % 1000)		timeout_ms++;	usbi_dbg("poll() %d fds with timeout in %dms", nfds, timeout_ms);	r = poll(fds, nfds, timeout_ms);	usbi_dbg("poll() returned %d", r);	if (r == 0) {		free(fds);		return handle_timeouts(ctx);	} else if (r == -1 && errno == EINTR) {		free(fds);		return LIBUSB_ERROR_INTERRUPTED;	} else if (r < 0) {		free(fds);		usbi_err(ctx, "poll failed %d err=%d\n", r, errno);		return LIBUSB_ERROR_IO;	}	r = usbi_backend->handle_events(ctx, fds, nfds, r);	if (r)		usbi_err(ctx, "backend handle_events failed with error %d", r);	free(fds);	return r;}/* returns the smallest of: *  1. timeout of next URB *  2. user-supplied timeout * returns 1 if there is an already-expired timeout, otherwise returns 0 * and populates out */static int get_next_timeout(libusb_context *ctx, struct timeval *tv,	struct timeval *out){	struct timeval timeout;	int r = libusb_get_next_timeout(ctx, &timeout);	if (r) {		/* timeout already expired? */		if (!timerisset(&timeout))			return 1;		/* choose the smallest of next URB timeout or user specified timeout */		if (timercmp(&timeout, tv, <))			*out = timeout;		else			*out = *tv;	} else {		*out = *tv;	}	return 0;}/** \ingroup poll * Handle any pending events. * * libusb determines "pending events" by checking if any timeouts have expired * and by checking the set of file descriptors for activity. * * If a zero timeval is passed, this function will handle any already-pending * events and then immediately return in non-blocking style. * * If a non-zero timeval is passed and no events are currently pending, this * function will block waiting for events to handle up until the specified * timeout. If an event arrives or a signal is raised, this function will * return early. * * \param ctx the context to operate on, or NULL for the default context * \param tv the maximum time to block waiting for events, or zero for * non-blocking mode * \returns 0 on success, or a LIBUSB_ERROR code on failure */API_EXPORTED int libusb_handle_events_timeout(libusb_context *ctx,	struct timeval *tv){	int r;	struct timeval poll_timeout;	USBI_GET_CONTEXT(ctx);	r = get_next_timeout(ctx, tv, &poll_timeout);	if (r) {		/* timeout already expired */		return handle_timeouts(ctx);	}retry:	if (libusb_try_lock_events(ctx) == 0) {		/* we obtained the event lock: do our own event handling */		r = handle_events(ctx, &poll_timeout);		libusb_unlock_events(ctx);		return r;	}	/* another thread is doing event handling. wait for pthread events that	 * notify event completion. */	libusb_lock_event_waiters(ctx);	if (!libusb_event_handler_active(ctx)) {		/* we hit a race: whoever was event handling earlier finished in the		 * time it took us to reach this point. try the cycle again. */		libusb_unlock_event_waiters(ctx);		usbi_dbg("event handler was active but went away, retrying");		goto retry;	}	usbi_dbg("another thread is doing event handling");	r = libusb_wait_for_event(ctx, &poll_timeout);	libusb_unlock_event_waiters(ctx);	if (r < 0)		return r;	else if (r == 1)		return handle_timeouts(ctx);	else		return 0;}/** \ingroup poll * Handle any pending events in blocking mode with a sensible timeout. This * timeout is currently hardcoded at 2 seconds but we may change this if we * decide other values are more sensible. For finer control over whether this * function is blocking or non-blocking, or the maximum timeout, use * libusb_handle_events_timeout() instead. * * \param ctx the context to operate on, or NULL for the default context * \returns 0 on success, or a LIBUSB_ERROR code on failure */API_EXPORTED int libusb_handle_events(libusb_context *ctx){	struct timeval tv;	tv.tv_sec = 2;	tv.tv_usec = 0;	return libusb_handle_events_timeout(ctx, &tv);}/** \ingroup poll * Handle any pending events by polling file descriptors, without checking if * any other threads are already doing so. Must be called with the event lock * held, see libusb_lock_events(). * * This function is designed to be called under the situation where you have * taken the event lock and are calling poll()/select() directly on libusb's * file descriptors (as opposed to using libusb_handle_events() or similar). * You detect events on libusb's descriptors, so you then call this function * with a zero timeout value (while still holding the event lock). * * \param ctx the context to operate on, or NULL for the default context * \param tv the maximum time to block waiting for events, or zero for * non-blocking mode * \returns 0 on success, or a LIBUSB_ERROR code on failure * \see \ref mtasync */API_EXPORTED int libusb_handle_events_locked(libusb_context *ctx,	struct timeval *tv){	int r;	struct timeval poll_timeout;	USBI_GET_CONTEXT(ctx);	r = get_next_timeout(ctx, tv, &poll_timeout);	if (r) {		/* timeout already expired */		return handle_timeouts(ctx);	}	return handle_events(ctx, &poll_timeout);}/** \ingroup poll * Determine the next internal timeout that libusb needs to handle. You only * need to use this function if you are calling poll() or select() or similar * on libusb's file descriptors yourself - you do not need to use it if you * are calling libusb_handle_events() or a variant directly. *  * You should call this function in your main loop in order to determine how * long to wait for select() or poll() to return results. libusb needs to be * called into at this timeout, so you should use it as an upper bound on * your select() or poll() call. * * When the timeout has expired, call into libusb_handle_events_timeout() * (perhaps in non-blocking mode) so that libusb can handle the timeout. * * This function may return 1 (success) and an all-zero timeval. If this is * the case, it indicates that libusb has a timeout that has already expired * so you should call libusb_handle_events_timeout() or similar immediately. * A return code of 0 indicates that there are no pending timeouts. * * \param ctx the context to operate on, or NULL for the default context * \param tv output location for a relative time against the current * clock in which libusb must be called into in order to process timeout events * \returns 0 if there are no pending timeouts, 1 if a timeout was returned, * or LIBUSB_ERROR_OTHER on failure */API_EXPORTED int libusb_get_next_timeout(libusb_context *ctx,	struct timeval *tv){	struct usbi_transfer *transfer;	struct timespec cur_ts;	struct timeval cur_tv;	struct timeval *next_timeout;	int r;	int found = 0;	USBI_GET_CONTEXT(ctx);	pthread_mutex_lock(&ctx->flying_transfers_lock);	if (list_empty(&ctx->flying_transfers)) {		pthread_mutex_unlock(&ctx->flying_transfers_lock);		usbi_dbg("no URBs, no timeout!");		return 0;	}	/* find next transfer which hasn't already been processed as timed out */	list_for_each_entry(transfer, &ctx->flying_transfers, list) {		if (!(transfer->flags & USBI_TRANSFER_TIMED_OUT)) {			found = 1;			break;		}	}	pthread_mutex_unlock(&ctx->flying_transfers_lock);	if (!found) {		usbi_dbg("all URBs have already been processed for timeouts");		return 0;	}	next_timeout = &transfer->timeout;	/* no timeout for next transfer */	if (!timerisset(next_timeout)) {		usbi_dbg("no URBs with timeouts, no timeout!");		return 0;	}	r = clock_gettime(CLOCK_MONOTONIC, &cur_ts);	if (r < 0) {		usbi_err(ctx, "failed to read monotonic clock, errno=%d", errno);		return LIBUSB_ERROR_OTHER;	}	TIMESPEC_TO_TIMEVAL(&cur_tv, &cur_ts);	if (timercmp(&cur_tv, next_timeout, >=)) {		usbi_dbg("first timeout already expired");		timerclear(tv);	} else {		timersub(next_timeout, &cur_tv, tv);		usbi_dbg("next timeout in %d.%06ds", tv->tv_sec, tv->tv_usec);	}	return 1;}/** \ingroup poll * Register notification functions for file descriptor additions/removals. * These functions will be invoked for every new or removed file descriptor * that libusb uses as an event source. * * To remove notifiers, pass NULL values for the function pointers. * * \param ctx the context to operate on, or NULL for the default context * \param added_cb pointer to function for addition notifications * \param removed_cb pointer to function for removal notifications * \param user_data User data to be passed back to callbacks (useful for * passing context information) */API_EXPORTED void libusb_set_pollfd_notifiers(libusb_context *ctx,	libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,	void *user_data){	USBI_GET_CONTEXT(ctx);	ctx->fd_added_cb 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -