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

📄 io.c

📁 linux 下的libusb 1.0.0版本
💻 C
📖 第 1 页 / 共 5 页
字号:
	r = ctx->pollfd_modify;	pthread_mutex_unlock(&ctx->pollfd_modify_lock);	if (r) {		usbi_dbg("someone else is modifying poll fds");		return 1;	}	r = pthread_mutex_trylock(&ctx->events_lock);	if (r)		return 1;	ctx->event_handler_active = 1;		return 0;}/** \ingroup poll * Acquire the event handling lock, blocking until successful acquisition if * it is contended. This lock is used to ensure that only one thread is * monitoring libusb event sources at any one time. * * You only need to use this lock if you are developing an application * which calls poll() or select() on libusb's file descriptors directly. * If you stick to libusb's event handling loop functions (e.g. * libusb_handle_events()) then you do not need to be concerned with this * locking. * * While holding this lock, you are trusted to actually be handling events. * If you are no longer handling events, you must call libusb_unlock_events() * as soon as possible. * * \param ctx the context to operate on, or NULL for the default context * \see \ref mtasync */API_EXPORTED void libusb_lock_events(libusb_context *ctx){	USBI_GET_CONTEXT(ctx);	pthread_mutex_lock(&ctx->events_lock);	ctx->event_handler_active = 1;}/** \ingroup poll * Release the lock previously acquired with libusb_try_lock_events() or * libusb_lock_events(). Releasing this lock will wake up any threads blocked * on libusb_wait_for_event(). * * \param ctx the context to operate on, or NULL for the default context * \see \ref mtasync */API_EXPORTED void libusb_unlock_events(libusb_context *ctx){	USBI_GET_CONTEXT(ctx);	ctx->event_handler_active = 0;	pthread_mutex_unlock(&ctx->events_lock);	/* FIXME: perhaps we should be a bit more efficient by not broadcasting	 * the availability of the events lock when we are modifying pollfds	 * (check ctx->pollfd_modify)? */	pthread_mutex_lock(&ctx->event_waiters_lock);	pthread_cond_broadcast(&ctx->event_waiters_cond);	pthread_mutex_unlock(&ctx->event_waiters_lock);}/** \ingroup poll * Determine if it is still OK for this thread to be doing event handling. * * Sometimes, libusb needs to temporarily pause all event handlers, and this * is the function you should use before polling file descriptors to see if * this is the case. * * If this function instructs your thread to give up the events lock, you * should just continue the usual logic that is documented in \ref mtasync. * On the next iteration, your thread will fail to obtain the events lock, * and will hence become an event waiter. * * This function should be called while the events lock is held: you don't * need to worry about the results of this function if your thread is not * the current event handler. * * \param ctx the context to operate on, or NULL for the default context * \returns 1 if event handling can start or continue * \returns 0 if this thread must give up the events lock * \see \ref fullstory "Multi-threaded I/O: the full story" */API_EXPORTED int libusb_event_handling_ok(libusb_context *ctx){	int r;	USBI_GET_CONTEXT(ctx);	/* is someone else waiting to modify poll fds? if so, don't let this thread	 * continue event handling */	pthread_mutex_lock(&ctx->pollfd_modify_lock);	r = ctx->pollfd_modify;	pthread_mutex_unlock(&ctx->pollfd_modify_lock);	if (r) {		usbi_dbg("someone else is modifying poll fds");		return 0;	}	return 1;}/** \ingroup poll * Determine if an active thread is handling events (i.e. if anyone is holding * the event handling lock). * * \param ctx the context to operate on, or NULL for the default context * \returns 1 if a thread is handling events * \returns 0 if there are no threads currently handling events * \see \ref mtasync */API_EXPORTED int libusb_event_handler_active(libusb_context *ctx){	int r;	USBI_GET_CONTEXT(ctx);	/* is someone else waiting to modify poll fds? if so, don't let this thread	 * start event handling -- indicate that event handling is happening */	pthread_mutex_lock(&ctx->pollfd_modify_lock);	r = ctx->pollfd_modify;	pthread_mutex_unlock(&ctx->pollfd_modify_lock);	if (r) {		usbi_dbg("someone else is modifying poll fds");		return 1;	}	return ctx->event_handler_active;}/** \ingroup poll * Acquire the event waiters lock. This lock is designed to be obtained under * the situation where you want to be aware when events are completed, but * some other thread is event handling so calling libusb_handle_events() is not * allowed. * * You then obtain this lock, re-check that another thread is still handling * events, then call libusb_wait_for_event(). * * You only need to use this lock if you are developing an application * which calls poll() or select() on libusb's file descriptors directly, * <b>and</b> may potentially be handling events from 2 threads simultaenously. * If you stick to libusb's event handling loop functions (e.g. * libusb_handle_events()) then you do not need to be concerned with this * locking. * * \param ctx the context to operate on, or NULL for the default context * \see \ref mtasync */API_EXPORTED void libusb_lock_event_waiters(libusb_context *ctx){	USBI_GET_CONTEXT(ctx);	pthread_mutex_lock(&ctx->event_waiters_lock);}/** \ingroup poll * Release the event waiters lock. * \param ctx the context to operate on, or NULL for the default context * \see \ref mtasync */API_EXPORTED void libusb_unlock_event_waiters(libusb_context *ctx){	USBI_GET_CONTEXT(ctx);	pthread_mutex_unlock(&ctx->event_waiters_lock);}/** \ingroup poll * Wait for another thread to signal completion of an event. Must be called * with the event waiters lock held, see libusb_lock_event_waiters(). * * This function will block until any of the following conditions are met: * -# The timeout expires * -# A transfer completes * -# A thread releases the event handling lock through libusb_unlock_events() * * Condition 1 is obvious. Condition 2 unblocks your thread <em>after</em> * the callback for the transfer has completed. Condition 3 is important * because it means that the thread that was previously handling events is no * longer doing so, so if any events are to complete, another thread needs to * step up and start event handling. * * This function releases the event waiters lock before putting your thread * to sleep, and reacquires the lock as it is being woken up. * * \param ctx the context to operate on, or NULL for the default context * \param tv maximum timeout for this blocking function. A NULL value * indicates unlimited timeout. * \returns 0 after a transfer completes or another thread stops event handling * \returns 1 if the timeout expired * \see \ref mtasync */API_EXPORTED int libusb_wait_for_event(libusb_context *ctx, struct timeval *tv){	struct timespec timeout;	int r;	USBI_GET_CONTEXT(ctx);	if (tv == NULL) {		pthread_cond_wait(&ctx->event_waiters_cond, &ctx->event_waiters_lock);		return 0;	}	r = clock_gettime(CLOCK_REALTIME, &timeout);	if (r < 0) {		usbi_err(ctx, "failed to read realtime clock, error %d", errno);		return LIBUSB_ERROR_OTHER;	}	timeout.tv_sec += tv->tv_sec;	timeout.tv_nsec += tv->tv_usec * 1000;	if (timeout.tv_nsec > 1000000000) {		timeout.tv_nsec -= 1000000000;		timeout.tv_sec++;	}	r = pthread_cond_timedwait(&ctx->event_waiters_cond,		&ctx->event_waiters_lock, &timeout);	return (r == ETIMEDOUT);}static void handle_timeout(struct usbi_transfer *itransfer){	struct libusb_transfer *transfer =		__USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);	int r;	itransfer->flags |= USBI_TRANSFER_TIMED_OUT;	r = libusb_cancel_transfer(transfer);	if (r < 0)		usbi_warn(TRANSFER_CTX(transfer),			"async cancel failed %d errno=%d", r, errno);}static int handle_timeouts(struct libusb_context *ctx){	struct timespec systime_ts;	struct timeval systime;	struct usbi_transfer *transfer;	int r = 0;	USBI_GET_CONTEXT(ctx);	pthread_mutex_lock(&ctx->flying_transfers_lock);	if (list_empty(&ctx->flying_transfers))		goto out;	/* get current time */	r = clock_gettime(CLOCK_MONOTONIC, &systime_ts);	if (r < 0)		goto out;	TIMESPEC_TO_TIMEVAL(&systime, &systime_ts);	/* iterate through flying transfers list, finding all transfers that	 * have expired timeouts */	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(&c

⌨️ 快捷键说明

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