同步方式
libusb_bulk_transfer(devh, ep_bulk, buf, CAM_BUF_SZ, &len, timeout);
进入libusb研究,发现libusb是采用异步方式来实现的。在do_sync_bulk_transfer中:
 
staticint do_sync_bulk_transfer(struct libusb_device_handle *dev_handle,
unsignedchar endpoint,unsignedchar*buffer,int length,
int*transferred,unsignedint timeout,unsignedchar type)
{
libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer, length,
bulk_transfer_cb,&completed, timeout);
transfer->type = type;
 
r = libusb_submit_transfer(transfer);
if(r <0){
libusb_free_transfer(transfer);
return r;
}
 
while(!completed){
r = libusb_handle_events(HANDLE_CTX(dev_handle));
}
}
这里libusb_fill_bulk_transfer来填充bulk transfer,然后libusb_submit_transfer提交bulk transfer,最后用libusb_handle_events来等待完成。当收到回应后,bulk_transfer_cb回调设置completed,从而阻塞被接触,函数返回。
 
分段处理bulk transfer
libusb_submit_transfer最终调到了submit_bulk_transfer。该函数会检查buffer大小,如果大于MAX_BULK_BUFFER_LENGTH(16K),则分成若干16K大小的urb,每个urb指向用户buffer的适当位置,然后用ioctl(IOCTL_USBFS_SUBMITURB)提交每个urb。
 
收到数据时会判断是否收齐所有urb。在handle_bulk_completion中,若urb_idx为最后一个urb,则认为收齐了所有的urb。最终会调用usbi_handle_transfer_completion来调用urb callback。
 
timeout处理
若libusb_bulk_transfer传入的timeout为0,则没有timeout,libusb会一直等待数据。在libusb_handle_events中设置了一个2s的poll timeout,libusb会在while中一直poll,每次poll的timeout为2s。
 
若设置了timeout,libusb_submit_transfer会按照timeout升序将transfer插入到libusb_context的flying_transfers列表中,然后提交transfer(当然会分段了,如上所述)
 
libusb_handle_events会根据自己设置的2s timeout和flying_transfers中的timeout得出实际timeout,然后用poll查询usb fd。
 
问题根源
libusb阻塞的原因就是超时。有时usb指纹头返回数据较慢,在指定的timeout时间内没有完成所有urb请求,进入超时处理。handle_timeout()会cancel掉为完成的urb(IOCTL_USBFS_DISCARDURB)。在do_sync_bulk_transfer中,由于未完成所有urb,bulk_transfer_cb没有被调用,从而会阻塞。libusb_handle_events会继续以2s超时来查询fd,但由于urb已经取消,设备会返回-2(ENOENT)。
 
按道理讲,即使超时,libusb也应该在超时后返回。libusb为什么没有返回呢?handle_bulk_completion函数中,若读到ENOENT,awaiting_discard会递减至0。与awaiting_discard一起的还有awaiting_reap,若二者均为0,也会调用bulk_transfer_cb通知用户。
 
awaiting_discard在超时时cancel urb时被设置。若ioctl(IOCTL_USBFS_DISCARDURB)返回EINVAL,则awaiting_reap会递增。
 
经过打印验证,发现在cancel urb时,对于已经完成的urb,会返回EINVAL。而未完成的urb,则返回0。我想这大概是一个bug,正确做法应该是不要取消已经完成的urb。

libusb_bulk_transfer 异步同步的更多相关文章

  1. 对JavaScript中异步同步机制以及线程深入了解

    今天在网上看到各种对Js异步同步单线程多线程的讨论 经过前辈们的洗礼 加上鄙人小小的理解 就来纸上谈兵一下吧~ Js本身就是单线程的 至于为什么Js是单线程的 那就要追溯到Js的历史了 总而言之 由于 ...

  2. 异步|同步&阻塞|非阻塞

    异步|同步:区别在于发出一个功能调用时,是否马上得到返回结果 阻塞|非阻塞:区别在于调用结果返回之前,当前线程是否挂起 node.js:单线程.异步非阻塞模型 单线程与异步不矛盾,与并发是矛盾的 ht ...

  3. AJAX异步同步

    为了更好的用户体验,AJAX的异步同步技术给了我们一个很好的用户体验下面是我做的一个例子. 1.客户端处理 UserId.HTML <!DOCTYPE html PUBLIC "-// ...

  4. 支持异步同步的分布式CommandBus MSMQ实现

    支持异步同步的分布式CommandBus MSMQ实现 先上一张本文所描述的适用场景图 分布式场景,共3台server: 前端Server Order App Server Warehouse App ...

  5. JavaScript学习-5——异步同步、回调函数

    ----------异步同步函数 ----------回调函数 一.异步同步函数 同步:发送一个请求,等待返回,然后再发送下一个请求 异步:发送一个请求,不等待返回,随时可以再发送下一个请求 同步可以 ...

  6. Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就绪,挂起,运行) ,***协程概念,yield模拟并发(有缺陷),Greenlet模块(手动切换),Gevent(协程并发)

    Python进阶----异步同步,阻塞非阻塞,线程池(进程池)的异步+回调机制实行并发, 线程队列(Queue, LifoQueue,PriorityQueue), 事件Event,线程的三个状态(就 ...

  7. TTS异步+同步

    微软TTS使用说明 一.SAPI SDK的介绍 SAPI,全称是The Microsoft Speech API.就是微软的语音API.由Windows Speech SDK提供. Windows S ...

  8. (转)函数中使用 ajax 异步 同步 返回值错误 主函数显示返回值总是undefined -- ajax使用总结

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAloAAAE0CAIAAAB7LwoKAAAgAElEQVR4nO2dy6sc152A6+/R2mXwSn ...

  9. GCD之异步同步体会

    前面的博文也有写到同步异步,可能是看他人的博文,自己没有实验,感觉理解不深,所以就敲了些代码比较一下串行.并行分别对应的同步.异步. 1.首先创建串行.并行线程队列 1 2 dispatch_queu ...

随机推荐

  1. Arduino基础入门—3.连接 IIC 1602 LCD显示文字

    1. IIC转接板介绍 Arduino Uno R3开发板的外部IO口是非常有限的.在驱动LCD1602时,尽管我们的数据线使用了4线,相对于8线方式减少一半,但是在需要外接多种传感器的应用中,4线驱 ...

  2. HIVE配置mysql metastore

    HIVE配置mysql metastore    hive中除了保存真正的数据以外还要额外保存用来描述库.表.数据的数据,称为hive的元数据.这些元数据又存放在何处呢?    如果不修改配置hive ...

  3. PYTHON 100days学习笔记008-4:错误和异常

    目录 Day008_04:python错误和异常 1.语法错误 2.异常 3.异常处理 4.抛出异常 5.用户自定义异常 6.定义清理行为 7.预定义的清理行为 参考文章: python3错误和异常 ...

  4. C#中异步编程异常的处理方式

    异步编程异常处理 在同步编程中,一旦出现错误就会抛出异常,我们可以使用try-catch来捕捉异常,未被捕获的异常则会不断向上传递,形成一个简单而统一的错误处理机制.但是对于异步编程来说,异常处理一直 ...

  5. mybatis三种批量插入方式对比

    <insert id="addInquiryQA" parameterType="java.util.List"> insert into inqu ...

  6. *#【Python】【基础知识】【模块】【tkinter】【学用tkinter画图/制作窗口】

    Python 提供了多个图形开发界面的库,几个常用 Python GUI 库如下: Tkinter: Tkinter 模块(Tk 接口)是 Python 的标准 Tk GUI 工具包的接口 . Tk ...

  7. CF1032B Personalized Cup

    一个多月前写的题,既然没人写题解,那蒟蒻就写一篇吧 基本思路 既然是输出任意一个解,那么号的位置在那里是没有关系的.我的思路是默认*号在最后面,然后对输入的字符串输出的行数进行分类. 代码 #incl ...

  8. MySQL8.0哪些新特性你最期待

    1.数据字典全部采用InnoDB引擎存储,支持DDL原子性.crash safe,metadata管理更完善 2.快速在线加新列(腾讯互娱DBA团队贡献) 3.并行redo log,并提升redo l ...

  9. StoneTab标签页CAD插件 3.2.6

    //////////////////////////////////////////////////////////////////////////////////////////////////// ...

  10. vmware centos .net core sdk开发测试

    环境:vmware + centos+ .net core2.0 一.安装.net core sdk sudo rpm -Uvh https://packages.microsoft.com/conf ...