Interruption Management in Windows CE

本文深入探讨了Windows CE操作系统的中断处理机制,包括硬件中断如何被捕获并传递给内核,内核如何管理和调度这些中断,以及最终如何触发用户空间的中断处理程序(IST)。此外还解释了IST中CreateEvent的作用及其与系统内核产生的event通知的关系。

Windows CE是一个层次结构的分明的嵌入式操作系统:BSP (Board Support Package)位于硬件层之上,该层内部包括三大部分,一是OAL (OEM Adaption Layer),二是硬件驱动程序,也就是所谓的driver,剩下第三个子模块就是Bootloader了,它的作用有点类似于普通PC的BIOS程序。BSP由产品制造商开发,提供硬件和操作系统内核间联系的桥梁。BSP层向上就是Windows CE的内核了,由微软开发,是整个操作系统的指挥中心。既然是内核,其功能也无外乎进程线程调度,内存管理等等。内核之上就是用户空间了,主要包括设备管理器device manager,各种服务程序等。这里需要注意的是device manager和device driver是两个完全不同的概念,device driver是真正的驱动,而这些驱动是否加载,什么时候加载则由device manager控制了。最顶层就是由用户利用Windows CE API开发的application了,无需多说。

 

在进行操作系统内核编译的时候,需要将OAL和内核一起打包成NK.bin镜像,最后生成NK.exe可执行文件。这里要讲的是Windows CE的中断处理机制,详细流程见下图。NK.exe就是CE的内核,上层的DEVMGR.dll就是设备管理器。

 

假设硬件在某一时刻产生了一个中断,这个中断首先由内核捕获。内核需要对中断的优先级进行管理,单从硬件来说各设备之间是用总线相连的,所以当出现两个设备同时产生中断的时候,内核需要做出选择,先相应哪个设备的中断信号。这是上图中所示的第一步。

 

第二步内核将硬件中断交给OAL代码,这段代码就是ISR中断服务程序。它可以分辨这个中断来自于哪个硬件设备,同时它也知道该硬件设备的ID。这一步的关键是它会将这个硬件ID翻译成软件ID,也就是该中断的逻辑号码,同时将翻译后的得到的逻辑号码交回给系统内核,也就是上图所示第3步。

 

第四步内核发出一个evenement通知,该通知里面包含了它刚才收到的逻辑ID。最后用户空间的IST,也就是真正的中断处理程序对中断进行处理。

 

上述步骤很清晰,但是实现IST的时候让我产生些许疑惑。IST的代码框架大致是这样的:

明明是系统内核产生一个evenement,为什么却在IST里CreateEvent? 后来查了一下MSDN,发现是我对Event Object这个概念的理解存在偏差。

 

事实上,假设有两个进程(process)A和B,A想要通过Event通知B某件事情已经发生,CreateEvent的调用在A和B里都是可行的。如果在A中调用,那么可以让B在该Event上等待,直到A调用SetEvent使得B可以继续执行;如果在B中调用,还是B紧接着在该Event上等待,条件一旦满足A就对Event进行set操作,于是B可以继续执行。也就是说,Event的创建与它是通知者还是被通知者无关,反正只要创建了一个Event,这个对象对两个进程都可见,因此可以用于进程间通信。注意这里是进程间通信,而不是线程,线程间通信有Critical Region和Lock这种更为轻量级的做法。

 

前文说过第四步系统内核发送evenement通知IST当前产生了一个硬件中断,这句话很含糊。我有那么多硬件,相应的,每一个硬件都一个IST,这么多IST,内核是怎么知道给哪个IST发送通知的? 回到上面的代码就清楚了,dwSysIntr是一个system call,它以硬件ID为参数返回对应的逻辑号码,这个工作OAL也要做。然后调用InterruptInitialize初始化中断,这个初始化过程它干了什么?答案就是它将硬件的逻辑ID在内核中进行注册,这个注册会产生一条logic ID到第一行代码生成的Event的句柄的映射。那么好了,系统收到OAL给它的逻辑ID之后开始查表,看看这个ID在这张表中存在吗? 不存在,中断自然会被丢弃。假设找到相应的记录项,则可以知晓应该对哪个Event进行set操作。set这个Event之后,在这个Event上等待的IST就可以从等待状态中恢复了。

 

上面说过中断可能被丢弃,那么什么时候会出现这种情况呢?个人理解,假设存在一个硬件A,但是它的IST并未被激活,常见的情形就是设备管理器device manager没有对设备A进行加载。毕竟,所有的IST线程都是由device manager创建的。

 

更多请参考:

http://geekswithblogs.net/BruceEitman/archive/2009/01/15/windows-ce-interrupt-service-thread.aspx

### 解决 Windows 系统无法检测到键盘中断的问题 对于在 Windows 系统下开发的应用程序,尤其是涉及实时数据处理或机器人控制的场景,确实可能会遇到无法正常捕获键盘中断的情况。这通常是因为标准输入流的行为与 Linux 或其他操作系统有所不同。 #### 使用 msvcrt 模块捕捉键盘事件 为了能够在 Windows 下有效监听键盘事件,在 Python 中可以利用 `msvcrt` 库来实现非阻塞式的按键读取功能[^1]: ```python import msvcrt while True: if msvcrt.kbhit(): # 判断是否有键被按下 key = msvcrt.getch() # 获取按下的键 print(f"Key pressed: {key}") break ``` 这段代码展示了如何通过循环不断检查是否有新的按键动作发生,并立即响应这些操作而不必等待回车确认。 #### 设置正确的命令行环境 有时,Windows 的命令提示符窗口默认设置可能会影响对某些特殊字符的支持,特别是当涉及到跨平台移植 ROS 节点或其他依赖于 POSIX 接口的应用时。确保使用兼容性更好的终端模拟器如 ConEmu 或者 PowerShell 来运行脚本,它们提供了更接近 Unix 风格的标准输入输出行为[^3]。 #### 修改应用程序逻辑适应不同平台特性 考虑到多平台上的一致性和稳定性,建议编写能够自动识别当前执行环境并调整相应参数的应用程序。例如,在启动阶段加入简单的 OS 类型判断语句,以便针对特定的操作系统应用优化措施[^5]: ```python import platform if 'Windows' == platform.system(): import msvcrt def get_key(): while not msvcrt.kbhit(): pass return ord(msvcrt.getch()) else: import sys, tty, termios def get_key(): fd = sys.stdin.fileno() old_settings = termios.tcgetattr(fd) try: tty.setraw(sys.stdin.fileno()) ch = sys.stdin.read(1) finally: termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) return ord(ch) # 后续可以根据get_key函数获取按键值进行相应的业务逻辑处理... ``` 上述代码片段提供了一个适用于多个操作系统的解决方案框架,其中包含了针对 Windows 和类 Unix 平台的不同实现方式。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值