On Fri, Aug 8, 2008 at 1:42 AM, Nathaniel Smith <[EMAIL PROTECTED]> wrote:
> Revised patch attached, also committed as
> 0490573b05ba466a373ee6380c24c266423dffd6 on branch
> org.vorpus.parti.spawn-children. Now I just need to test it...
Okay, and here's the version that works :-)
I am struck by another question now, though, i.e.: should
--survive-children be the default or not? I can imagine people be
surprised either way...
-- Nathaniel
#
# old_revision [0490573b05ba466a373ee6380c24c266423dffd6]
#
# patch "xpra/scripts/main.py"
# from [ab87ff74958e2549a9e817957a7fe6ed8463a558]
# to [0a2ece3c5989579ab35b56487882b887b8e4eae2]
#
# patch "xpra/scripts/server.py"
# from [e8923cc866750d4196572ea0648f089c02ae69c9]
# to [57a51c5c15dbd53a48e75c207e27dd61f0601e20]
#
============================================================
--- xpra/scripts/main.py ab87ff74958e2549a9e817957a7fe6ed8463a558
+++ xpra/scripts/main.py 0a2ece3c5989579ab35b56487882b887b8e4eae2
@@ -27,12 +27,21 @@ def main(script_file, cmdline):
parser.add_option("--no-daemon", action="store_false",
dest="daemon", default=True,
help="Don't daemonize when running as a server")
+ parser.add_option("--no-automatic-stop", action="store_false",
+ dest="automatic_stop", default=True,
+ help="Don't terminate server when client on start command exits")
parser.add_option("--remote-xpra", action="store",
dest="remote_xpra", default=None, metavar="CMD",
help="How to run 'xpra' on the remote host")
parser.add_option("-d", "--debug", action="store",
dest="debug", default=None, metavar="FILTER1,FILTER2,...",
help="List of categories to enable debugging for (or \"all\")")
+ parser.add_option("--start-child", action="append",
+ dest="children",
+ help="program to spawn in new server (may be repeated)")
+ parser.add_option("--survive-children", action="store_true",
+ dest="survive_children", default=False,
+ help="Don't terminate server when --start-child command(s) exit")
(options, args) = parser.parse_args(cmdline[1:])
if not args:
============================================================
--- xpra/scripts/server.py e8923cc866750d4196572ea0648f089c02ae69c9
+++ xpra/scripts/server.py 57a51c5c15dbd53a48e75c207e27dd61f0601e20
@@ -31,6 +31,39 @@ def deadly_signal(signum, frame):
#kill(os.getpid(), signum)
os._exit(128 + signum)
+# Note that this class has async subtleties -- e.g., it is possible for a
+# child to exit and us to receive the SIGCHLD before our fork() returns (and
+# thus before we even know the pid of the child). So be careful:
+class ChildReaper(object):
+ def __init__(self, app, survive_children):
+ self._app = app
+ self._children_pids = None
+ self._dead_pids = set()
+ self._survive_children = survive_children
+
+ def set_children_pids(self, children_pids):
+ assert self._children_pids is None
+ self._children_pids = children_pids
+ self.check()
+
+ def check(self):
+ if (self._children_pids
+ and not self._survive_children
+ and self._children_pids.issubset(self._dead_pids)):
+ print "all children have exited and --survive-children was not specified, exiting"
+ self._app.quit(False)
+
+ def __call__(self, signum, frame):
+ while 1:
+ try:
+ pid, status = os.waitpid(-1, os.WNOHANG)
+ except OSError:
+ break
+ if pid == 0:
+ break
+ self._dead_pids.add(pid)
+ self.check()
+
def save_pid(pid):
prop_set(gtk.gdk.get_default_root_window(),
"_XPRA_SERVER_PID", "u32", pid)
@@ -101,7 +134,7 @@ def run_server(parser, opts, mode, xpra_
def run_server(parser, opts, mode, xpra_file, extra_args):
if len(extra_args) != 1:
parser.error("need exactly 1 extra argument")
- display_name = extra_args[0]
+ display_name = extra_args.pop(0)
atexit.register(run_cleanups)
signal.signal(signal.SIGINT, deadly_signal)
@@ -219,6 +252,17 @@ def run_server(parser, opts, mode, xpra_
except:
pass
_cleanups.append(cleanup_socket)
+
+ child_reaper = ChildReaper(app, opts.survive_children)
+ # Always register the child reaper, because even if survive_children is
+ # true, we still need to reap them somehow to avoid zombies:
+ signal.signal(signal.SIGCHLD, child_reaper)
+ if opts.children:
+ children_pids = set()
+ for child_cmd in opts.children:
+ children_pids.add(subprocess.Popen(child_cmd, shell=True).pid)
+ child_reaper.set_children_pids(children_pids)
+
if app.run():
# Upgrading, so leave X server running
_cleanups.remove(kill_xvfb)
_______________________________________________
Parti-discuss mailing list
[email protected]
http://lists.partiwm.org/cgi-bin/mailman/listinfo/parti-discuss