[kupfer: 21/41] utils: Implement spawn_plugin_helper in kupfer.utils
- From: Ulrik Sverdrup <usverdrup src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [kupfer: 21/41] utils: Implement spawn_plugin_helper in kupfer.utils
- Date: Tue, 26 Apr 2011 17:14:34 +0000 (UTC)
commit 8226018af1091e8d79d21c2fc9e9d798189ecb4b
Author: Ulrik Sverdrup <ulrik sverdrup gmail com>
Date: Tue Apr 26 18:44:03 2011 +0200
utils: Implement spawn_plugin_helper in kupfer.utils
spawn_plugin_helper and spawn_child in kupfer.utils can spawn processes
that should never live longer than Kupfer itself. Use (On linux)
pr_set_deathsig to terminate the child process when kupfer exits.
kupfer/plugin/vim/plugin.py | 39 +---------------------
kupfer/utils.py | 74 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 76 insertions(+), 37 deletions(-)
---
diff --git a/kupfer/plugin/vim/plugin.py b/kupfer/plugin/vim/plugin.py
index cdf6008..6cbd638 100644
--- a/kupfer/plugin/vim/plugin.py
+++ b/kupfer/plugin/vim/plugin.py
@@ -15,6 +15,7 @@ from kupfer import utils
from kupfer import kupferstring
from kupfer import pretty
from kupfer import plugin_support
+from kupfer import utils
plugin_support.check_dbus_connection()
@@ -123,7 +124,7 @@ def get_plugin_service_obj(plugin_id, activate=True):
except dbus.DBusException as exc:
if activate:
service_id = "kupfer.plugin.%s.service" % plugin_id
- return start_plugin_helper(service_id, True)
+ return utils.start_plugin_helper(service_id, True)
return None
proxy_iface = dbus.Interface(proxy_obj, interface_name)
return proxy_iface
@@ -137,42 +138,6 @@ def stop_plugin_service(plugin_id):
plug_iface.Exit(reply_handler=_dummy_handler,
error_handler=_dummy_handler)
-def on_child_exit(pid, condition, user_data):
- # @condition is the &status field of waitpid(2) (C library)
- import os
- argv, respawn = user_data
- if respawn:
- is_signal = os.WIFSIGNALED(condition)
- if is_signal and respawn:
- glib.timeout_add_seconds(10, spawn_child, argv, respawn)
-
-def spawn_child(argv, respawn=True):
- """
- Spawn argv in the mainloop and keeping it as a child process
- (so that it exits with the parent).
-
- @respawn: If True, respawn if child dies abnormally
-
- raises utils.SpawnError
- """
- flags = (glib.SPAWN_SEARCH_PATH | glib.SPAWN_DO_NOT_REAP_CHILD)
- try:
- pid, stdin_fd, stdout_fd, stderr_fd = \
- glib.spawn_async(argv, flags=flags)
- except glib.GError as exc:
- raise utils.SpawnError(unicode(exc))
- if pid:
- glib.child_watch_add(pid, on_child_exit, (argv, respawn))
-
-def start_plugin_helper(name, respawn):
- """
- @respawn: If True, respawn if child dies abnormally
- """
- argv = [sys.executable]
- argv.extend(sys.argv)
- argv.append('--exec-helper=%s' % name)
- pretty.print_debug(__name__, "Spawning", argv)
- spawn_child(argv, respawn)
def _dummy_handler(*args):
pass
diff --git a/kupfer/utils.py b/kupfer/utils.py
index 02a786e..ed6632d 100644
--- a/kupfer/utils.py
+++ b/kupfer/utils.py
@@ -3,6 +3,7 @@ import os
from os import path as os_path
import locale
import signal
+import sys
import gobject
import glib
@@ -277,6 +278,79 @@ def show_url(url):
except GError, exc:
pretty.print_error(__name__, "gtk.show_uri:", exc)
+def _on_child_exit(pid, condition, user_data):
+ # @condition is the &status field of waitpid(2) (C library)
+ argv, respawn = user_data
+ if respawn:
+ is_signal = os.WIFSIGNALED(condition)
+ if is_signal and respawn:
+ def callback(*args):
+ spawn_child(*args)
+ return False
+ glib.timeout_add_seconds(10, callback, argv, respawn)
+
+def _try_register_pr_pdeathsig():
+ """
+ Register PR_SET_PDEATHSIG (linux-only) for the calling process
+ which is a signal delivered when its parent dies.
+
+ This should ensure child processes die with the parent.
+ """
+ PR_SET_PDEATHSIG=1
+ SIGHUP=1
+ if sys.platform != 'linux2':
+ return
+ try:
+ import ctypes
+ except ImportError:
+ return
+ try:
+ libc = ctypes.CDLL("libc.so.6")
+ libc.prctl(PR_SET_PDEATHSIG, SIGHUP)
+ except (AttributeError, OSError):
+ pass
+
+def spawn_child(argv, respawn=True, display=None):
+ """
+ Spawn argv in the mainloop and keeping it as a child process
+ (it will be made sure to exit with the parent).
+
+ @respawn: If True, respawn if child dies abnormally
+
+ raises utils.SpawnError
+ returns pid
+ """
+ flags = (glib.SPAWN_SEARCH_PATH | glib.SPAWN_DO_NOT_REAP_CHILD)
+ kwargs = {}
+ if display:
+ # environment is passed as a sequence of strings
+ envd = os.environ.copy()
+ envd['DISPLAY'] = display
+ kwargs['envp'] = ['='.join((k,v)) for k,v in envd.items()]
+
+ try:
+ pid, stdin_fd, stdout_fd, stderr_fd = \
+ glib.spawn_async(argv, flags=flags,
+ child_setup=_try_register_pr_pdeathsig,
+ **kwargs)
+ except glib.GError as exc:
+ raise utils.SpawnError(unicode(exc))
+ if pid:
+ glib.child_watch_add(pid, _on_child_exit, (argv, respawn))
+ return pid
+
+def start_plugin_helper(name, respawn, display=None):
+ """
+ @respawn: If True, respawn if child dies abnormally
+
+ raises SpawnError
+ """
+ argv = [sys.executable]
+ argv.extend(sys.argv)
+ argv.append('--exec-helper=%s' % name)
+ pretty.print_debug(__name__, "Spawning", argv)
+ return spawn_child(argv, respawn, display=display)
+
def show_help_url(url):
"""
Try at length to display a startup notification for the help browser.
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]