?? io.c
字號:
* \param transfer the transfer to submit * \returns 0 on success * \returns LIBUSB_ERROR_NO_DEVICE if the device has been disconnected * \returns another LIBUSB_ERROR code on other failure */API_EXPORTED int libusb_submit_transfer(struct libusb_transfer *transfer){ struct usbi_transfer *itransfer = __LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer); int r; itransfer->transferred = 0; r = calculate_timeout(itransfer); if (r < 0) return LIBUSB_ERROR_OTHER; add_to_flying_list(itransfer); r = usbi_backend->submit_transfer(itransfer); if (r) { pthread_mutex_lock(&TRANSFER_CTX(transfer)->flying_transfers_lock); list_del(&itransfer->list); pthread_mutex_unlock(&TRANSFER_CTX(transfer)->flying_transfers_lock); } return r;}/** \ingroup asyncio * Asynchronously cancel a previously submitted transfer. * It is undefined behaviour to call this function on a transfer that is * already being cancelled or has already completed. * This function returns immediately, but this does not indicate cancellation * is complete. Your callback function will be invoked at some later time * with a transfer status of * \ref libusb_transfer_status::LIBUSB_TRANSFER_CANCELLED * "LIBUSB_TRANSFER_CANCELLED." * * \param transfer the transfer to cancel * \returns 0 on success * \returns a LIBUSB_ERROR code on failure */API_EXPORTED int libusb_cancel_transfer(struct libusb_transfer *transfer){ struct usbi_transfer *itransfer = __LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer); int r; usbi_dbg(""); r = usbi_backend->cancel_transfer(itransfer); if (r < 0) usbi_err(TRANSFER_CTX(transfer), "cancel transfer failed error %d", r); return r;}/* Handle completion of a transfer (completion might be an error condition). * This will invoke the user-supplied callback function, which may end up * freeing the transfer. Therefore you cannot use the transfer structure * after calling this function, and you should free all backend-specific * data before calling it. */void usbi_handle_transfer_completion(struct usbi_transfer *itransfer, enum libusb_transfer_status status){ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); struct libusb_context *ctx = TRANSFER_CTX(transfer); uint8_t flags; pthread_mutex_lock(&ctx->flying_transfers_lock); list_del(&itransfer->list); pthread_mutex_unlock(&ctx->flying_transfers_lock); if (status == LIBUSB_TRANSFER_COMPLETED && transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { int rqlen = transfer->length; if (transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL) rqlen -= LIBUSB_CONTROL_SETUP_SIZE; if (rqlen != itransfer->transferred) { usbi_dbg("interpreting short transfer as error"); status = LIBUSB_TRANSFER_ERROR; } } flags = transfer->flags; transfer->status = status; transfer->actual_length = itransfer->transferred; if (transfer->callback) transfer->callback(transfer); /* transfer might have been freed by the above call, do not use from * this point. */ if (flags & LIBUSB_TRANSFER_FREE_TRANSFER) libusb_free_transfer(transfer); pthread_mutex_lock(&ctx->event_waiters_lock); pthread_cond_broadcast(&ctx->event_waiters_cond); pthread_mutex_unlock(&ctx->event_waiters_lock);}/* Similar to usbi_handle_transfer_completion() but exclusively for transfers * that were asynchronously cancelled. The same concerns w.r.t. freeing of * transfers exist here. */void usbi_handle_transfer_cancellation(struct usbi_transfer *transfer){ /* if the URB was cancelled due to timeout, report timeout to the user */ if (transfer->flags & USBI_TRANSFER_TIMED_OUT) { usbi_dbg("detected timeout cancellation"); usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_TIMED_OUT); return; } /* otherwise its a normal async cancel */ usbi_handle_transfer_completion(transfer, LIBUSB_TRANSFER_CANCELLED);}/** \ingroup poll * Attempt to acquire the event handling lock. 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 * \returns 0 if the lock was obtained successfully * \returns 1 if the lock was not obtained (i.e. another thread holds the lock) * \see \ref mtasync */API_EXPORTED int libusb_try_lock_events(libusb_context *ctx){ int r; USBI_GET_CONTEXT(ctx); 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); 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 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){ USBI_GET_CONTEXT(ctx); 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 */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -