On Wed, 2014-06-25 at 15:07 -0400, David Shea wrote:
(this version doesn't try to mutate the dict it's iterating)
As was noted in the comment, assuming that any SIGCHLD means that X
exited makes the startup process fragile, so stop doing that. Install a
global SIGCHLD handler to track exits from Xorg and metacity. metacity
failures will now throw an exception instead of being silently,
confusingly ignored. Add a fork wrapper to remove the race between
process startup and process monitoring.
Removed a comment about the importance of the window manager being the
first X connection. This is no longer true, which is fortunate as the
period between metacity starting and metacity connecting to the X server
presents an intractible race.
---
anaconda | 212 +++++++++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 165 insertions(+), 47 deletions(-)
diff --git a/anaconda b/anaconda
index cbbedd6..9bb270b 100755
--- a/anaconda
+++ b/anaconda
@@ -44,9 +44,77 @@ if ("debug=1" in proc_cmdline) or ("debug" in
proc_cmdline):
cov.start()
-import atexit, sys, os, time, subprocess
-# keep up with process ID of the window manager if we start it
-wm_pid = None
+import atexit, sys, os, time, subprocess, signal, errno
+
+# Install a global SIGCHLD handler to keep track of things that should be
+# running for as long as anaconda does. The dictionary is of the form
+# {pid: name, ...}. The handler will raise OSError, so if not caught
+# a SIGCHLD from a watched process will halt anaconda.
+forever_pids = {}
+
+def sigchld_handler(num, frame):
+ # Check whether anything in the list of processes being watched has
+ # exited. We don't want to call waitpid(-1), since that would break
+ # anything else using wait/waitpid (like the subprocess module).
+ exited_pids = []
+ exn_message = []
+
+ for child_pid in forever_pids:
+ try:
+ pid_result, status = os.waitpid(child_pid, os.WNOHANG)
+ except OSError as e:
+ if e.errno == errno.ECHILD:
+ continue
+
+ if pid_result:
+ proc_name = forever_pids[child_pid]
+ exited_pids.append(child_pid)
+
+ if os.WIFEXITED(status):
+ status_str = "with status %s" % os.WEXITSTATUS(status)
+ elif os.WIFSIGNALED(status):
+ status_str = "on signal %s" % os.WTERMSIG(status)
+ else:
+ status_str = "with unknown status code %s" % status
+
+ exn_message.append("%s exited %s" % (proc_name, status_str))
+
+ for child_pid in exited_pids:
+ del forever_pids[child_pid]
+
+ if exn_message:
+ raise OSError(0, ", ".join(exn_message))
Can we define a special
exception class for this exception and use it
here?
--
Vratislav Podzimek
Anaconda Rider | RHCE | Red Hat, Inc. | Brno - Czech Republic