Skip to content

Commit c16a39d

Browse files
authored
Try to increase robustness of the JobOpen hack (#116)
1 parent c39a440 commit c16a39d

File tree

2 files changed

+44
-36
lines changed

2 files changed

+44
-36
lines changed

anypytools/abcutils.py

+22-24
Original file line numberDiff line numberDiff line change
@@ -193,23 +193,21 @@ def execute_anybodycon(
193193
subprocess_flags |= CREATE_NEW_PROCESS_GROUP
194194
extra_kwargs = {"creationflags": subprocess_flags}
195195

196-
anybodycmd = [
196+
cmd = [
197197
str(anybodycon_path.resolve()),
198198
"-m",
199199
str(macrofile_path),
200200
"/deb",
201201
str(debug_mode),
202202
"/ni" if not interactive_mode else "",
203203
]
204-
205-
proc = Popen(
206-
anybodycmd,
207-
stdout=logfile,
208-
stderr=logfile,
209-
env=env,
210-
cwd=folder,
204+
kwargs = {
205+
"stdout": logfile,
206+
"stderr": logfile,
207+
"env": env,
208+
"cwd": folder,
211209
**extra_kwargs,
212-
)
210+
}
213211

214212
else:
215213
if os.environ.get("WINE_REDIRECT_OUTPUT", 0):
@@ -222,14 +220,13 @@ def execute_anybodycon(
222220
str(debug_mode),
223221
"/ni",
224222
]
225-
proc = Popen(
226-
cmd,
227-
env=env,
228-
cwd=folder,
229-
close_fds=False,
230-
stdout=logfile,
231-
stderr=logfile,
232-
)
223+
kwargs = {
224+
"env": env,
225+
"cwd": folder,
226+
"close_fds": False,
227+
"stdout": logfile,
228+
"stderr": logfile,
229+
}
233230
else:
234231
# ON Linux/Wine we use a bat file to redirect the output into a file on wine/windows
235232
# side. This prevents a bug with AnyBody starts it's builtin python.
@@ -248,11 +245,10 @@ def execute_anybodycon(
248245
macrofile_cleanup.append(batfile)
249246

250247
cmd = ["wine", "cmd", "/c", str(batfile) + r"& exit /b %ERRORLEVEL%"]
251-
proc = Popen(
252-
cmd,
253-
env=env,
254-
cwd=folder,
255-
)
248+
249+
kwargs = {"env": env, "cwd": folder}
250+
251+
proc = Popen(cmd, **kwargs)
256252

257253
retcode = None
258254
_subprocess_container.add(proc.pid)
@@ -269,8 +265,10 @@ def execute_anybodycon(
269265
retcode = _KILLED_BY_ANYPYTOOLS
270266
raise e
271267
finally:
272-
if not retcode:
268+
if retcode is None:
273269
proc.kill()
270+
if ON_WINDOWS:
271+
proc._close_job_object(proc._win32_job)
274272
else:
275273
_subprocess_container.remove(proc.pid)
276274

@@ -949,7 +947,7 @@ def _schedule_processes(
949947
task = task_queue.get()
950948
yield task
951949

952-
time.sleep(0.05)
950+
time.sleep(0.1)
953951

954952
def cleanup_logfiles(self, tasklist):
955953
for task in tasklist:

anypytools/jobpopen.py

+22-12
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@
88

99
import subprocess
1010
from subprocess import Popen
11+
from threading import RLock
1112

1213
import win32api
1314
import win32job
1415
import win32process
16+
import pywintypes
1517

1618

1719
class JobPopen(Popen):
@@ -41,7 +43,14 @@ def __getattr__(self, key):
4143

4244
def CreateProcess(self, *args, **kwargs):
4345
hp, ht, pid, tid = self._oldapi.CreateProcess(*args, **kwargs)
44-
win32job.AssignProcessToJobObject(self._job, hp)
46+
try:
47+
win32job.AssignProcessToJobObject(self._job, hp)
48+
except BaseException as e: # to catch pywintypes.error
49+
if e.args == (6, "AssignProcessToJobObject", "The handle is invalid."):
50+
# Try to ignore an error can occur randomly sometimes.
51+
pass
52+
else:
53+
raise e
4554
win32process.ResumeThread(ht)
4655
return hp, ht, pid, tid
4756

@@ -56,17 +65,18 @@ def __init__(self, *args, **kwargs):
5665
CREATE_SUSPENDED = 0x00000004
5766
kwargs.setdefault("creationflags", 0)
5867
kwargs["creationflags"] |= CREATE_SUSPENDED
59-
_winapi = subprocess._winapi # Python 3
60-
_winapi_key = "_winapi"
61-
try:
62-
setattr(
63-
subprocess,
64-
_winapi_key,
65-
JobPopen._winapijobhandler(_winapi, self._win32_job),
66-
)
67-
super(JobPopen, self).__init__(*args, **kwargs)
68-
finally:
69-
setattr(subprocess, _winapi_key, _winapi)
68+
with RLock():
69+
_winapi = subprocess._winapi # Python 3
70+
_winapi_key = "_winapi"
71+
try:
72+
setattr(
73+
subprocess,
74+
_winapi_key,
75+
JobPopen._winapijobhandler(_winapi, self._win32_job),
76+
)
77+
super(JobPopen, self).__init__(*args, **kwargs)
78+
finally:
79+
setattr(subprocess, _winapi_key, _winapi)
7080

7181
def _create_job_object(self):
7282
"""Create a new anonymous job object"""

0 commit comments

Comments
 (0)