9

I have some GPU test software i'm trying to automate using python3, The test would normally be run for 3 minutes then cancelled by a user using ctrl+c generating the following output

GPU test output

After exiting with ctrl+c the test can then be run again with no issue

When trying to automate this with subprocess popen and sending SIGINT or SIGTERM i'm not getting the same as if keyboard entry was used. The script exits abruptly and on subsequent runs cant find the gpus (assume its not unloading the driver properly)

from subprocess import Popen, PIPE
from signal import SIGINT
from time import time


def check_subproc_alive(subproc):
    return subproc.poll() is None

def print_subproc(subproc, timer=True):
    start_time = time()
    while check_subproc_alive(subproc):
        line = subproc.stdout.readline().decode('utf-8')
        print(line, end="")
        if timer and (time() - start_time) > 10:
            break


subproc = Popen(['./gpu_test.sh', '-t', '1'], stdin=PIPE, stdout=PIPE, stderr=PIPE, shell=False)

print_subproc(subproc)

subproc.send_signal(SIGINT)

print_subproc(subproc, False)

How can I send ctrl+c to a subprocess as if a user typed it?

**UPDATE

import subprocess


def start(executable_file):
    return subprocess.Popen(
        executable_file,
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )


def read(process):
    return process.stdout.readline().decode("utf-8").strip()


def write(process):
    process.stdin.write('\x03'.encode())
    process.stdin.flush()

def terminate(process):
    process.stdin.close()
    process.terminate()
    process.wait(timeout=0.2)


process = start("./test.sh")
write(process)
for x in range(100):
    print(read(process))
terminate(process)

Tried the above code and can get characters to register with dummy sh script however sending the \x03 command just sends an empty char and doesn't end script

andowt
  • 274
  • 1
  • 4
  • 15

2 Answers2

6

I think you can probably use something like this:

import signal
try:
    p=subprocess...
except KeyboardInterrupt:
    p.send_signal(signal.SIGINT)
Jonathan S
  • 546
  • 3
  • 10
  • Wouldnt this send SIGINT if a keyboard interrupt occured during the subprocess execution? im trying to automate that keyboard interrupt happening in the first place – andowt Aug 22 '19 at 11:32
  • if you want to send sigint without pressing ctrl+c, you can just use p.send_signal(signal.SIGINT) directly without the try, except block – Jonathan S Aug 22 '19 at 11:39
  • That is what I want to do but sending SIGINT is not the same as when I run the gpu test script and manually press ctrl+c. Manually pressing ctrl+c causes the script to report error manual user intervention and it stops gracefully. Sending SIGINT stops the script dead with no teardown – andowt Aug 22 '19 at 11:41
  • I think it's because you have shell=False, can you try without that? – Jonathan S Aug 22 '19 at 11:42
  • If i set shell as true the gpu test would have to complete before the next lines of code are executed – andowt Aug 22 '19 at 11:49
  • Oh I see in that case what about using subproc.communicate() and sending the ctrl-c value to stdin https://stackoverflow.com/questions/7018139/pyserial-how-to-send-ctrl-c-command-on-the-serial-line – Jonathan S Aug 22 '19 at 12:01
  • try sending b'\x03\n' – Jonathan S Aug 23 '19 at 08:47
3

The following solution is the only one I could find that works for windows and is the closest resemblance to sending a Ctrl+C event.

import signal
os.kill(self.p.pid, signal.CTRL_C_EVENT)
MedoAlmasry
  • 452
  • 5
  • 19