Use kill
to terminate the process:
import subprocess
import os
def foo():
with subprocess.Popen(["strace", "/usr/bin/wireshark"], stdout=subprocess.PIPE,stderr=subprocess.PIPE, preexec_fn=os.setsid) as process:
try:
return process.communicate(timeout=2)[0]
except subprocess.TimeoutExpired:
process.kill()
return process.communicate()[0]
output = foo()
If this does not work for you (it does for me), then:
Instead of calling communicate
, start a thread that will loop reading chunks from process.stdout
and write them to a passed queue.Queue
instance. The main thread will now call process.wait(timeout=2)
to await the termination. If subprocess.TimeoutExpired
is raised, then the process will be killed. When we know that the process is no longer running and the thread has written all the chunks it will ever write, we loop doing calls to get_nowait
on the queue to get all the chunks until the queue is empty and finally we concatenate the chunks together:
import subprocess
from threading import Thread
from queue import Queue
import os
def foo():
def reader(stream, queue):
while True:
data = stream.read(4096)
if data == b'':
break
queue.put(data)
with subprocess.Popen(["strace", "/usr/bin/wireshark"], stdout=subprocess.PIPE,stderr=subprocess.PIPE, preexec_fn=os.setsid) as process:
queue = Queue()
t = Thread(target=reader, args=(process.stdout, queue))
t.start()
try:
process.wait(timeout=2)
except subprocess.TimeoutExpired:
process.kill()
# Never do a join on a process writing to a multiprocessing.Queue
# before you retrieve all items from the queue. But here we are OK:
t.join()
output = []
try:
while True:
output.append(queue.get_nowait())
except Empty:
pass
return b''.join(output)
output = foo()