同步方式
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. Mysql的binlog 和InnoDB的redo-log

    来源:https://www.jianshu.com/p/4bcfffb27ed5 mysql日志系统之redo log和bin log Mr林_月生关注 12018.12.02 01:35:06字数 ...

  2. 【VS开发】内存映射文件进程间共享内存

    内存映射文件进程间共享内存 内存映射文件的另一个功能是在进程间共享数据,它提供了不同进程共享内存的一个有效且简单的方法.后面的许多例子都要用到共享内存.共享内存主要是通过映射机制实现的.Windows ...

  3. 跨域跨域跨域,从此say goodbye

    跨域这个问题每个开发者都会遇到,只是时间先后而已,你不搞清楚它他就像狗皮膏药一样粘着你,在你求职生涯中不停的遇到,然后你每次都要做这个功课,终于有一天这个名词已经让我忍无可忍了,下定决心必须搞定它,要 ...

  4. SpringBoot 项目如何在tomcat容器中运行

    一. SpringBoot内嵌容器的部署方式 SpringBoot内部默认提供内嵌的tomcat容器,所以可以直接打成jar包,丢到服务器上的任何一个目录,然后在当前目录下执行java -jar de ...

  5. (MVC — — Demo)客户管理系统的开发日志

    点击一下 目录 第一步:搭建开发环境 第二步:层次包(按照三层架构思想写) 第四步:开发(utils)工具包 第四步:开发 Dao 层 第五步:开发 services 层 第六步:开发 factory ...

  6. 基本mysql语句

    一 select语句 基本语法 select 列名1,列名2             //可以使用完全限定的列名  tables.列名 form tables 过滤(where ) 分组(group ...

  7. Oracle笔记2

    24.复杂查询的三道题 # 案例一:列出与SCOTT从事相同工作的所有员工及部门名称.人数.平均工资 GROUP BY使用限制: 查询语句中没有GROUP BY,则SELECT子句中只能出现统计函数; ...

  8. 泛型和DataTable的属性

    泛型转DataTable public DataTable ToDataTable<TResult>(this IEnumerable<TResult> value) wher ...

  9. js之数据类型(对象类型——单体内置对象——JSON)

    JSON(Java Script Object Notation)使用JavaScript语法,是用于存储和传输数据的格式,通常用于服务端向网页传递数据.JSON格式仅仅是一个文本,文本可以被任何编程 ...

  10. for in和for of的区别

    for in:一般用于遍历普通对象(即没有部署Iterator接口),遍历的是属性. for of:ES6新增的遍历方式,能遍历大部分的类型,遍历的是值.for...of 允许你遍历 Arrays(数 ...