diff options
author | Adam Gross <grossag@vmware.com> | 2019-12-06 21:43:52 (GMT) |
---|---|---|
committer | Adam Gross <grossag@vmware.com> | 2019-12-06 21:45:30 (GMT) |
commit | ed66f1338f029a63b7a93f7027f3149ab5376bdd (patch) | |
tree | d7f17e6b77d15ed705282bb430e00f982bae6a2b /src/engine/SCons/Platform/win32.py | |
parent | b24e34897212026548d9b5ff0bc20610347f9367 (diff) | |
download | SCons-ed66f1338f029a63b7a93f7027f3149ab5376bdd.zip SCons-ed66f1338f029a63b7a93f7027f3149ab5376bdd.tar.gz SCons-ed66f1338f029a63b7a93f7027f3149ab5376bdd.tar.bz2 |
Fix multithreaded Windows builds when a thread has a file open for write
Python 2 enables handle inheritance by default for child processes. It wasn't
until Python 3.4 that it was disabled. This causes problems because if a Python
action is writing to a file and a child process is spawned at that exact
moment, builds fail because of sharing issues.
Diffstat (limited to 'src/engine/SCons/Platform/win32.py')
-rw-r--r-- | src/engine/SCons/Platform/win32.py | 59 |
1 files changed, 34 insertions, 25 deletions
diff --git a/src/engine/SCons/Platform/win32.py b/src/engine/SCons/Platform/win32.py index 0a3b199..c0cf03b 100644 --- a/src/engine/SCons/Platform/win32.py +++ b/src/engine/SCons/Platform/win32.py @@ -51,10 +51,6 @@ try: import msvcrt import win32api import win32con - - msvcrt.get_osfhandle - win32api.SetHandleInformation - win32con.HANDLE_FLAG_INHERIT except ImportError: parallel_msg = \ "you do not seem to have the pywin32 extensions installed;\n" + \ @@ -66,28 +62,41 @@ except AttributeError: else: parallel_msg = None - _builtin_open = open - - def _scons_open(*args, **kw): - fp = _builtin_open(*args, **kw) - win32api.SetHandleInformation(msvcrt.get_osfhandle(fp.fileno()), - win32con.HANDLE_FLAG_INHERIT, - 0) - return fp - - open = _scons_open - if sys.version_info.major == 2: - _builtin_file = file - class _scons_file(_builtin_file): - def __init__(self, *args, **kw): - _builtin_file.__init__(self, *args, **kw) - win32api.SetHandleInformation(msvcrt.get_osfhandle(self.fileno()), - win32con.HANDLE_FLAG_INHERIT, 0) - file = _scons_file - else: - # No longer needed for python 3.4 and above. Files are opened non sharable - pass + import __builtin__ + + _builtin_file = __builtin__.file + _builtin_open = __builtin__.open + + def _scons_fixup_mode(mode): + """Adjust 'mode' to mark handle as non-inheritable. + + SCons is multithreaded, so allowing handles to be inherited by + children opens us up to races, where (e.g.) processes spawned by + the Taskmaster may inherit and retain references to files opened + by other threads. This may lead to sharing violations and, + ultimately, build failures. + + By including 'N' as part of fopen's 'mode' parameter, all file + handles returned from these functions are atomically marked as + non-inheritable. + """ + if not mode: + # Python's default is 'r'. + # https://docs.python.org/2/library/functions.html#open + mode = 'rN' + elif 'N' not in mode: + mode += 'N' + return mode + + def _scons_file(name, mode=None, *args, **kwargs): + return _builtin_file(name, _scons_fixup_mode(mode), *args, **kwargs) + + def _scons_open(name, mode=None, *args, **kwargs): + return _builtin_open(name, _scons_fixup_mode(mode), *args, **kwargs) + + __builtin__.file = _scons_file + __builtin__.open = _scons_open |