Yuya Nishihara avatar Yuya Nishihara committed be0e184

python: example of sending SIGINT to subprocess on Windows

Comments (0)

Files changed (1)

python/win32sigint.py

+# How to kill(pid, SIGINT) on Windows?
+#
+# http://stackoverflow.com/questions/813086/
+# http://stackoverflow.com/questions/7085604/
+
+import ctypes, os, signal, sys, subprocess, time
+
+GenerateConsoleCtrlEvent = ctypes.windll.kernel32.GenerateConsoleCtrlEvent
+CTRL_C_EVENT = 0
+
+CREATE_NO_WINDOW = 0x08000000
+
+pythonexe = sys.executable.replace('pythonw.exe', 'python.exe')
+
+def master(args):
+    # CREATE_NO_WINDOW makes master not share the console, thus middleman's
+    # CTRL_C_EVENT won't affect master.
+    workerargs = [pythonexe, __file__, 'worker']
+    proc = subprocess.Popen([pythonexe, __file__, 'middleman'] + workerargs,
+                            stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+                            stderr=subprocess.PIPE,
+                            creationflags=CREATE_NO_WINDOW)
+    time.sleep(2)
+    proc.stdin.write('hello!\n')
+    proc.stdin.flush()
+    time.sleep(1)
+
+    print >>sys.stderr, 'master: sent SIGINT'
+    proc.stdin.write('SIGINT\n')
+    proc.stdin.flush()
+
+    sout, serr = proc.communicate()
+    for name, src in [('stdout', sout), ('stderr', serr)]:
+        for l in src.splitlines():
+            print >>sys.stderr, 'master: %s: %s' % (name, l)
+
+def middleman(args):
+    proc = subprocess.Popen(args, stdin=subprocess.PIPE)
+    print >>sys.stderr, 'middleman: popen %r' % args
+    try:
+        for l in sys.stdin:
+            if l.strip() == 'SIGINT':
+                # CTRL_C_EVENT won't work if dwProcessGroupId is non-zero
+                GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)
+                # or os.kill(0, signal.CTRL_C_EVENT) on Python>=2.7
+                break
+            else:
+                proc.stdin.write(l)
+                proc.stdin.flush()
+        time.sleep(1)  # KeyboardInterrupt will arrive here
+    except KeyboardInterrupt:
+        print >>sys.stderr, 'middleman: got SIGINT'
+    finally:
+        pass
+
+    proc.communicate()
+
+def worker(args):
+    try:
+        for l in sys.stdin:
+            print 'worker: received %r' % l
+    except KeyboardInterrupt:
+        print >>sys.stderr, 'worker: got SIGINT'
+
+if __name__ == '__main__':
+    args = sys.argv[1:]
+    if args:
+        action = args.pop(0)
+    else:
+        action = 'master'
+
+    print >>sys.stderr, '%s: started' % action
+    actionmap = {'master': master, 'middleman': middleman, 'worker': worker}
+    try:
+        exitcode = actionmap[action](args)
+    finally:
+        print >>sys.stderr, '%s: finished' % action
+    exit(exitcode)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.