Commit 34d59b0b by Baruch Sterin

fixes to pyabc kill mechanism

parent 02081dba
...@@ -12,23 +12,35 @@ from contextlib import contextmanager, nested ...@@ -12,23 +12,35 @@ from contextlib import contextmanager, nested
import pyabc import pyabc
def wait_with_timeout(p, timeout): def popen_and_wait_with_timeout(timeout,cmd, *args, **kwargs):
""" Wait for a subprocess.Popen object to terminate, or until timeout (in seconds) expires. """ """ Wait for a subprocess.Popen object to terminate, or until timeout (in seconds) expires. """
if timeout <= 0: p = None
timeout = None t = None
t = threading.Thread(target=lambda: p.wait()) try:
t.start() p = subprocess.Popen(cmd, *args, **kwargs)
t.join(timeout) if timeout <= 0:
timeout = None
if t.is_alive():
p.kill() t = threading.Thread(target=lambda: p.communicate())
t.start()
t.join()
t.join(timeout)
return p.returncode
finally:
if p is not None and p.poll() is None:
p.kill()
if t is not None and t.is_alive():
t.join()
if p is not None:
return p.returncode
return -1
@contextmanager @contextmanager
def replace_sys_argv(argv): def replace_sys_argv(argv):
...@@ -74,13 +86,11 @@ def run_reachx_cmd(effort, timeout): ...@@ -74,13 +86,11 @@ def run_reachx_cmd(effort, timeout):
'qua_ffix -effort %d -L %s'%(effort, cygpath(tmplog_name)), 'qua_ffix -effort %d -L %s'%(effort, cygpath(tmplog_name)),
'quit' 'quit'
] ]
cmd = ["jabc", "-c", " ; ".join(cmdline)] cmd = ["jabc", "-c", " ; ".join(cmdline)]
p = subprocess.Popen(cmd, shell=False, stdout=sys.stdout, stderr=sys.stderr) rc = popen_and_wait_with_timeout(timeout, cmd, shell=False, stdout=sys.stdout, stderr=sys.stderr)
rc = wait_with_timeout(p,timeout)
if rc != 0: if rc != 0:
# jabc failed or stopped. Write a status file to update the status to unknown # jabc failed or stopped. Write a status file to update the status to unknown
with open(tmplog_name, "w") as f: with open(tmplog_name, "w") as f:
......
...@@ -44,14 +44,7 @@ ABC_NAMESPACE_HEADER_START ...@@ -44,14 +44,7 @@ ABC_NAMESPACE_HEADER_START
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
/*=== utilSignal.c ==========================================================*/ /*=== utilSignal.c ==========================================================*/
extern void Util_SignalCleanup();
extern void Util_SignalStartHandler();
extern void Util_SignalResetHandler();
extern void Util_SignalStopHandler();
extern void Util_SignalBlockSignals();
extern void Util_SignalUnblockSignals();
extern void Util_SignalAddChildPid(int pid);
extern void Util_SignalRemoveChildPid(int pid);
extern int Util_SignalTmpFile(const char* prefix, const char* suffix, char** out_name); extern int Util_SignalTmpFile(const char* prefix, const char* suffix, char** out_name);
extern void Util_SignalTmpFileRemove(const char* fname, int fLeave); extern void Util_SignalTmpFileRemove(const char* fname, int fLeave);
extern int Util_SignalSystem(const char* cmd); extern int Util_SignalSystem(const char* cmd);
......
...@@ -61,4 +61,21 @@ pyabc.tgz : $(PROG) $(ABC_PYTHON_SRC:_wrap.c=.py) $(ABC_PYTHON_FILES_PREFIX)/abc ...@@ -61,4 +61,21 @@ pyabc.tgz : $(PROG) $(ABC_PYTHON_SRC:_wrap.c=.py) $(ABC_PYTHON_FILES_PREFIX)/abc
--out=$@ \ --out=$@ \
$(ABC_PYTHON_OPTIONS) $(ABC_PYTHON_OPTIONS)
PYABC_INSTALL_TARGET ?= $(shell date +%Y-%m-%d_%H-%M.%N_${USER})
PYABC_INSTALL_TARGET := $(PYABC_INSTALL_TARGET)
PYABC_INSTALL_DIR ?= /hd/common/pyabc/builds/pyabc_builds/
.PHONY: zzz
pyabc_install_target: pyabc_extension_bdist
mkdir -p "$(PYABC_INSTALL_DIR)/$(PYABC_INSTALL_TARGET)"
tar \
--directory="$(PYABC_INSTALL_DIR)/$(PYABC_INSTALL_TARGET)" \
--show-transformed-names \
--transform='s#^.*/##g' \
-xvzf "$(ABC_PYTHON_FILES_PREFIX)/dist/pyabc-1.0.linux-x86_64.tar.gz"
find "$(PYABC_INSTALL_DIR)/$(PYABC_INSTALL_TARGET)/"* -type d | xargs rmdir
echo "Installed at $(PYABC_INSTALL_DIR)/$(PYABC_INSTALL_TARGET)"
endif endif
...@@ -15,7 +15,6 @@ Caveats: ...@@ -15,7 +15,6 @@ Caveats:
1. Global variables in the parent process are not affected by the child processes. 1. Global variables in the parent process are not affected by the child processes.
2. The functions can only return simple types, see the pickle module for details 2. The functions can only return simple types, see the pickle module for details
3. Signals are currently not handled correctly
Usage: Usage:
...@@ -91,47 +90,6 @@ from contextlib import contextmanager ...@@ -91,47 +90,6 @@ from contextlib import contextmanager
import pyabc import pyabc
def _waitpid(pid, flags):
while True:
try:
res = os.waitpid(pid, flags)
return res
except OSError as e:
if e.errno != errno.EINTR:
raise
def _wait():
while True:
try:
pid,rc = os.wait()
return pid, rc
except OSError as e:
if e.errno != errno.EINTR:
raise
except Exceptions as e:
raise
class _sigint_critical_section(object):
def __init__(self):
self.blocked = False
def __enter__(self):
self.acquire()
return self
def __exit__(self, type, value, traceback):
self.release()
def acquire(self):
if not self.blocked:
self.blocked = True
pyabc.block_sigint()
def release(self):
if self.blocked:
self.blocked = False
pyabc.restore_sigint_block()
class _splitter(object): class _splitter(object):
def __init__(self, funcs): def __init__(self, funcs):
...@@ -144,18 +102,19 @@ class _splitter(object): ...@@ -144,18 +102,19 @@ class _splitter(object):
return len(self.fds) == 0 return len(self.fds) == 0
def cleanup(self): def cleanup(self):
# close pipes and kill child processes # close pipes and kill child processes
for pid,(i,fd) in self.fds.iteritems(): for pid,(i,fd) in self.fds.iteritems():
os.close(fd) os.close(fd)
os.kill( pid, signal.SIGINT ) try:
os.kill( pid, signal.SIGINT )
except Exception as e:
print >>sys.stderr, 'exception while trying to kill pid=%d: '%pid, e
raise
with _sigint_critical_section() as cs:
# wait for termination and update result # wait for termination and update result
for pid, _ in self.fds.iteritems(): for pid, _ in self.fds.iteritems():
_waitpid( pid, 0 ) os.waitpid( pid, 0 )
pyabc.remove_child_pid(pid) self.results[pid] = None
self.results[pid] = None
self.fds = {} self.fds = {}
...@@ -179,22 +138,20 @@ class _splitter(object): ...@@ -179,22 +138,20 @@ class _splitter(object):
try: try:
with _sigint_critical_section() as cs: # create child process
# create child process pid = os.fork()
pid = os.fork()
if pid == 0:
if pid == 0: # child process:
# child process: os.close(pr)
pyabc.reset_sigint_handler() pyabc.close_on_fork(pw)
cs.release()
os.close(pr) rc = self.child( pw, f)
rc = self.child( pw, f) os._exit(rc)
os._exit(rc) else:
else: # parent process:
# parent process: os.close(pw)
pyabc.add_child_pid(pid) return (pid, pr)
os.close(pw)
return (pid, pr)
finally: finally:
if os.getpid() != parentpid: if os.getpid() != parentpid:
...@@ -209,12 +166,9 @@ class _splitter(object): ...@@ -209,12 +166,9 @@ class _splitter(object):
def get_next_result(self): def get_next_result(self):
# wait for the next child process to terminate # wait for the next child process to terminate
pid, rc = _wait() pid, rc = os.wait()
assert pid in self.fds assert pid in self.fds
with _sigint_critical_section() as cs:
pyabc.remove_child_pid(pid)
# retrieve the pipe file descriptor1 # retrieve the pipe file descriptor1
i, fd = self.fds[pid] i, fd = self.fds[pid]
del self.fds[pid] del self.fds[pid]
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment