Larry Osterman系列--为什么Ctrl-C无法打断net use命令
2022-1-10 07:44:55 Author: mp.weixin.qq.com(查看原文) 阅读量:10 收藏

Why doesn't CTRL-C stop NET USE - [2004-03-19]

十四年来,John Vert一在向我抱怨这个问题,为什么Ctrl-C无法打断cmd中的"net use"命令。这到底是为什么,为什么我不能用Ctrl-C打断它?事实是,一系列复杂因素凑到一起造成这种用户体验欠佳的局面。

首先是Ctrl-C在控制台程序中的处理方式。若程序调用过SetConsoleCtrlHandler,控制台子系统(csrss)记录回调函数地址,将Ctrl-C被按下时,csrss向目标进程插入一个新线程调用前述回调函数。如果控制台窗口有多个进程(考虑cmd中执行net.exe之类的情形),csrss按照注册顺序依次调用前台进程的回调函数,直至某个回调函数返回TRUE,表明Ctrl-C得到处理。若程序未调用SetConsoleCtrlHandler,缺省的回调函数是ExitProcess。

现在,cmd.exe有注册Ctrl-C的回调函数,但net.exe没有,所以按下Ctrl-C时,系统会安排net.exe调用ExitProcess。到目前为止,一切正常。

但是有个问题,net.exe阻塞在WNetAddConnection2,其内部阻塞在一个同步ioctl,而ExitProcess的语义要求其等待这个同步ioctl结束。难道没有一种机制来取消这种未完成的I/O吗?确实有一个,CancelIo就是干这事的。但你仔细看CancelIo的文档,它只能取消由本线程发起的I/O操作。注意,csrss创建了一个全新的线程来执行Ctrl-C的回调函数,该线程并未发起任何I/O操作,所有的I/O都由net.exe的主线程发起。

cmd.exe可以响应Ctrl-C,但此时cmd.exe不是前台进程,net.exe是前台进程,后者优先处理Ctrl-C。于是,你只能等啊等啊等啊。

每次John在大厅碰上我,都会问我什么时候修复Ctrl-C的问题。

scz: 前些日子我写《从僵死的调试器中抢救被调试进程》时,用kd调试Ctrl-C的响应过程,看到csrss向目标进程插入新线程以调用回调函数,当时的前台进程是cdb.exe,回调函数是KERNELBASE!CtrlRoutine。

scz: LO这篇是2004年写的,现在是2022年,Ctrl-C仍然打不断net.exe,估计微软不会考虑在net.exe中使用异步I/O,三十多年了,爱咋的咋的?LO应该已不在微软,John Vert呢?


文章来源: http://mp.weixin.qq.com/s?__biz=MzUzMjQyMDE3Ng==&mid=2247485195&idx=1&sn=992ebcd34d8997ef8f39722675b0d721&chksm=fab2c434cdc54d22cf65e73f186e9d071a79faddb1183012e91d1fc5ce248afbb2786a8e70bc#rd
如有侵权请联系:admin#unsafe.sh