同步方式
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. Docker存储容易忽略的使用细节

    一.Docker容器使用前其实有个非常重要的步骤就是规划好部署的磁盘区域,因为docker容器默认存储的路径是在/var/lib/docker的根目录内,随着使用时间越长部署的内容越多,基本的根目录的 ...

  2. Hyperledger Fabric 安全基础:身份系统 PKIs

    什么是身份系统 区块链网络中的角色包括对等节点(peer),订购着,客户端应用程序,管理员等等.这些参与者的身份都封装在X.509数字证书中.这些身份信息真的非常重要,因为他们决定了在网络中参与者具体 ...

  3. 带你手写基于 Spring 的可插拔式 RPC 框架(二)整体结构

    前言 上一篇文章中我们已经知道了什么是 RPC 框架和为什么要做一个 RPC 框架了,这一章我们来从宏观上分析,怎么来实现一个 RPC 框架,这个框架都有那些模块以及这些模块的作用. 总体设计 在我们 ...

  4. Linux上,最常用的一批命令解析(10年精选)

    Linux这么多命令,通常会让初学者望而生畏.下面是我结合日常工作,以及在公司的内部培训中,针对对Linux不是很熟悉的同学,精选的一批必须要搞懂的命令集合.任何一个命令其实都是可以深入的,比如tai ...

  5. FTP服务器搭建基础工具:Serv-U 14.0.2使用教程

    安装教程   1.在本站下载好压缩包,将文件解压,双击运行“ServUSetup官方原版程序.exe”程序,弹出语言选择框,选择“中文(简体)”,点击“确定”开始安装   2.点击“下一步”进行安装  ...

  6. js中遍历对象的属性和值的方法

    鉴于循环目标是个对象,length是为undefined,用map等对数组的循环方法不行,对象就用此下方法 for(var key in _this.lists.medicines){ medicin ...

  7. Ajax方式上传文件报错"Uncaught TypeError: Illegal invocation"

    今天使用ajax上传文件时,出现了错误.数据传输的方式是通过定义formData完成的,提交的文件对象也设置为dom对象,但是还是不能发送请求.F12看到后台报了个错误:Uncaught TypeEr ...

  8. spring入门一:框架整体简介

    1:spring的基本框架主要包含六大模块:DAO.ORM.AOP.JEE.WEB.CORE DAO:(Data Access Object) 数据访问对象,是一个面向对象的数据库接口. ORM:(O ...

  9. Ural 1250 Sea Burial 题解

    目录 Ural 1250 Sea Burial 题解 题意 输入 题解 程序 Ural 1250 Sea Burial 题解 题意 给定一个\(n\times m\)的地图,\(.\)为水,\(\#\ ...

  10. Django-djangorestframework-响应模块

    响应模块 一般都用 Response 对象来做返回(最后一定是打包成符合 HTTP 协议的数据格式来传输,Response 类做了一系列处理,所以这里我们只需要关注下它的那些参数即可) 响应类构造器 ...