|
27 | 27 | import threading
|
28 | 28 | import time
|
29 | 29 | import resource
|
| 30 | +import signal |
30 | 31 |
|
31 | 32 |
|
32 | 33 | class TimeoutException(Exception):
|
@@ -92,18 +93,45 @@ def __init__(self, logger, timeout, condition, p):
|
92 | 93 | self.start()
|
93 | 94 | self.exception = None
|
94 | 95 |
|
| 96 | + def terminate(self, p): |
| 97 | + """ |
| 98 | + Make sure the process goes away. |
| 99 | + """ |
| 100 | + p.terminate() |
| 101 | + |
| 102 | + # The following code tries more methods to terminate |
| 103 | + # the process and is specific to Unix. |
| 104 | + if os.name == 'posix': |
| 105 | + timeout = self.timeout |
| 106 | + term_signals = [signal.SIGINT, signal.SIGKILL] |
| 107 | + for sig in term_signals: |
| 108 | + timeout = timeout / 2 # exponential back-off |
| 109 | + self.logger.info("Sleeping for {} seconds". |
| 110 | + format(timeout)) |
| 111 | + time.sleep(timeout) |
| 112 | + |
| 113 | + if p.poll() is None: |
| 114 | + self.logger.info("Command with PID {} still alive," |
| 115 | + " killing with signal {}". |
| 116 | + format(p.pid, sig)) |
| 117 | + p.send_signal(sig) |
| 118 | + else: |
| 119 | + self.logger.info("Command with PID {} is gone". |
| 120 | + format(p.pid)) |
| 121 | + break |
| 122 | + |
95 | 123 | def run(self):
|
96 | 124 | with self.condition:
|
97 | 125 | if not self.condition.wait(self.timeout):
|
98 | 126 | p = self.popen
|
99 | 127 | self.logger.info("Terminating command {} with PID {} "
|
100 | 128 | "after timeout of {} seconds".
|
101 | 129 | format(p.args, p.pid, self.timeout))
|
102 |
| - p.terminate() |
103 | 130 | self.exception = TimeoutException("Command {} with pid"
|
104 | 131 | " {} timed out".
|
105 | 132 | format(p.args,
|
106 | 133 | p.pid))
|
| 134 | + self.terminate(p) |
107 | 135 | else:
|
108 | 136 | return None
|
109 | 137 |
|
@@ -207,7 +235,8 @@ def close(self):
|
207 | 235 |
|
208 | 236 | if self.timeout:
|
209 | 237 | time_condition = threading.Condition()
|
210 |
| - self.logger.debug("Setting timeout to {}".format(self.timeout)) |
| 238 | + self.logger.debug("Setting timeout to {} seconds". |
| 239 | + format(self.timeout)) |
211 | 240 | timeout_thread = TimeoutThread(self.logger, self.timeout,
|
212 | 241 | time_condition, p)
|
213 | 242 |
|
|
0 commit comments