procutil: try and avoid angering CoreFoundation on macOS
authorAugie Fackler <augie@google.com>
Thu, 05 Dec 2019 16:19:16 -0500
changeset 43912 a89381e04c58
parent 43911 f2de8dc9c52f
child 43913 4b7d5d10c45d
procutil: try and avoid angering CoreFoundation on macOS We've seen failures like this: objc[57662]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called. objc[57662]: +[__NSCFConstantString initialize] may have been in progress in another thread when fork() was called. We cannot safely call it or ignore it in the fork() child process. Crashing instead. Set a breakpoint on objc_initializeAfterForkError to debug. I think this is due to forking off some background processes during `hg update` or similar. I don't have any conclusive proof this is the fork() call that's to blame, but it's the most likely one since the regular `hg update` codepath uses the other fork() invocation (via workers) and we don't get this report from non-Google macOS users. Ugh. Differential Revision: https://phab.mercurial-scm.org/D7615
mercurial/utils/procutil.py
--- a/mercurial/utils/procutil.py	Wed Dec 11 17:35:29 2019 +0100
+++ b/mercurial/utils/procutil.py	Thu Dec 05 16:19:16 2019 -0500
@@ -423,7 +423,10 @@
     return rc
 
 
-def gui():
+_is_gui = None
+
+
+def _gui():
     '''Are we running in a GUI?'''
     if pycompat.isdarwin:
         if b'SSH_CONNECTION' in encoding.environ:
@@ -439,6 +442,13 @@
         return pycompat.iswindows or encoding.environ.get(b"DISPLAY")
 
 
+def gui():
+    global _is_gui
+    if _is_gui is None:
+        _is_gui = _gui()
+    return _is_gui
+
+
 def hgcmd():
     """Return the command used to execute current hg
 
@@ -583,6 +593,11 @@
         `Subprocess.wait` function for the spawned process.  This is mostly
         useful for developers that need to make sure the spawned process
         finished before a certain point. (eg: writing test)'''
+        if pycompat.isdarwin:
+            # avoid crash in CoreFoundation in case another thread
+            # calls gui() while we're calling fork().
+            gui()
+
         # double-fork to completely detach from the parent process
         # based on http://code.activestate.com/recipes/278731
         if record_wait is None: