lzy.je 发表于 2013-2-4 20:10:59

win32-process(0.6.0) Process::kill 方法发送POSIX信号的问题

这两天在写一个工具,今天下午被win32-process(0.6.0)包的Process::kill方法浪费了2小时。
 
trap("INT") doputs "got signal INT"endputs "Sup"getsProcess.kill("INT", Process.pid); 这段代码举个例子,目的很简单,就是想接收和发送一个POSIX信号,验证执行上正确的结果。这个我本是准备用在fork子进程后,父向子通知消息用的,但是发现很简单的道理,可子进程就是不能进trap。后来发现问题是在于win32-process(0.6.0)包的Process::kill方法问。验证一下,上面的代码只要在首行加上:
 
require 'win32/process' 就立刻玩完,win32-process(0.6.0)包修改后的kill方法无法正确投递“SIGINT”中断。可怜的是,一方面为了在Windows平台上使用fork方法使用win32-process(0.6.0)包,而另一方面它的kill又有这个问题。不知道各位看客有什么高见,分享下。
 
另:今天休息,家里没*nix环境无法再实验了,等将来跨平台Review代码时再试吧。呵呵,看来Ruby还是和*nix亲。
 
// 11.30 18.10 添加 ////
 
刚google到一个,和我有同样的疑问,看来问题不是那么好解决。
http://stackoverflow.com/questions/140111/sending-an-arbitrary-signal-in-windows
 
// 11.30 18.11 添加 ////
 
看了一下win32-process(0.6.0)包process.rb的源代码,发现问题是在183行:
 
if GenerateConsoleCtrlEvent(CTRL_C_EVENT, pid)    killed_pids.push(pid)end 
其中GenerateConsoleCtrlEvent函数始终失败,返回0值。通过kill方法上的注释和MSDN(http://msdn.microsoft.com/en-us/library/ms683155(VS.85).aspx)里的说明看到,该函数成功处理CTRL_C_EVENT消息的必要条件是,必须要向进程标识中dwProcessGroupId参数包含CREATE_NEW_PROCESS_GROUP(0x00000200)flag的进程发送消息才能够成功。为了验证,临时在process.rb中添加了个函数fork2:
 
   def fork2      last_arg = ARGV.last            # Look for the 'child#xxx' tag      if last_arg =~ /child#\d+/         @i += 1         num = last_arg.split('#').last.to_i         if num == @i            if block_given?               status = 0               begin                  yield               rescue Exception                  status = -1 # Any non-zero result is failure               ensure                  return status               end            end            return nil         else            return false         end      end         # Tag the command with the word 'child#xxx' to distinguish it      # from the calling process.      cmd = 'ruby -I "' + $LOAD_PATH.join(File::PATH_SEPARATOR) << '" "'      cmd << File.expand_path($PROGRAM_NAME) << '" ' << ARGV.join(' ')      cmd << ' child#' << @child_pids.length.to_s            startinfo =       startinfo = startinfo.pack('LLLLLLLLLLLLSSLLLL')      procinfo= .pack('LLLL')            rv = CreateProcess(0, cmd, 0, 0, 1, CREATE_NEW_PROCESS_GROUP, 0, 0, startinfo, procinfo)            if rv == 0         raise Error, get_last_error      end            pid = procinfo.unpack('L').first      @child_pids.push(pid)            pid    end 
上面的代码就是复制的fork代码,只是其中红色代码行中的CreateProcess函数的第六个dwCreationFlags(DWORD)参数将CREATE_NEW_PROCESS_GROUP置位。之后执行测试代码:
 
require 'win32/process'Signal.trap('INT') doFile.open("c:/c.txt", "w") { |f| f.write("ok") }endpid = Process::fork2 dotrap(2) { File.open("c:/b.txt", "w") { |f| f.write("ok") }; exit! }while 1sleep(2)endendexit! if pid < 1puts "Pause any key to send 'INT' sinal to child #{pid}"getsProcess.kill(2, pid);Process.kill('INT', Process.pid);getsputs "parent proc end." 发现对于fork2出的子进程GenerateConsoleCtrlEvent函数执行成功,即两个kill都执行成功。但是发现测试代码中的trap代码还是不能被执行。很是奇怪~
 
看了上面的google到的贴子,感觉可能是Windows没有很好的对POSIX信号支持造成的。再研究研究,大家有什么看法?期待中~~
 
// 2009.03.07 13:40 添加 ////


作者:lzy.je
出处:http://lzy.iteye.com
本文版权归作者所有,只允许以摘要和完整全文两种形式转载,不允许对文字进行裁剪。未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
 
页: [1]
查看完整版本: win32-process(0.6.0) Process::kill 方法发送POSIX信号的问题