Skip to content

Commit

Permalink
redshift-gtk: Make sure that child process is closed after signals
Browse files Browse the repository at this point in the history
Instead of calling sys.exit() the signal handlers now try to terminate
the child process. After the child exits, the process will be reaped by
the GLib callback which will call Gtk.main_quit() which will then quit
redshift-gtk. This ensures that the redshift process does not outlive
the redshift-gtk process.
  • Loading branch information
jonls committed Jan 2, 2016
1 parent 71f52b7 commit 7e9ef55
Showing 1 changed file with 30 additions and 27 deletions.
57 changes: 30 additions & 27 deletions src/redshift-gtk/statusicon.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,13 @@ def set_inhibit(self, inhibit):
if inhibit != self._inhibited:
self._child_toggle_inhibit()

def _child_signal(self, sg):
"""Send signal to child process."""
os.kill(self._process[0], sg)

def _child_toggle_inhibit(self):
'''Sends a request to the child process to toggle state'''
os.kill(self._process[0], signal.SIGUSR1)
self._child_signal(signal.SIGUSR1)

def _child_cb(self, pid, status, data=None):
'''Called when the child process exists'''
Expand All @@ -163,13 +167,12 @@ def _child_cb(self, pid, status, data=None):
report_errors = False
try:
GLib.spawn_check_exit_status(status)
Gtk.main_quit()
except GLib.GError:
report_errors = True

if report_errors:
self.emit('error-occured', self._errors)

GLib.spawn_close_pid(self._process[0])
Gtk.main_quit()

def _child_key_change_cb(self, key, value):
'''Called when the child process reports a change of internal state'''

Expand Down Expand Up @@ -227,14 +230,13 @@ def _child_data_cb(self, f, cond, data):

return True

def termwait(self):
'''Send SIGINT and wait for the child process to quit'''
try:
os.kill(self._process[0], signal.SIGINT)
os.waitpid(self._process[0], 0)
except ProcessLookupError:
# Process has apparently already disappeared
pass
def terminate_child(self):
"""Send SIGINT to child process."""
self._child_signal(signal.SIGINT)

def kill_child(self):
"""Send SIGKILL to child process."""
self._child_signal(signal.SIGKILL)


class RedshiftStatusIcon(object):
Expand Down Expand Up @@ -490,35 +492,36 @@ def destroy_cb(self, widget, data=None):
'''Callback when a request to quit the application is made'''
if not appindicator:
self.status_icon.set_visible(False)
Gtk.main_quit()
self._controller.terminate_child()
return False


def sigterm_handler(data=None):
sys.exit(0)


def run():
utils.setproctitle('redshift-gtk')

# Install TERM signal handler
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGTERM,
sigterm_handler, None)
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT,
sigterm_handler, None)

# Internationalisation
gettext.bindtextdomain('redshift', defs.LOCALEDIR)
gettext.textdomain('redshift')

# Create redshift child process controller
c = RedshiftController(sys.argv[1:])

def terminate_child(data=None):
c.terminate_child()
return False

# Install signal handlers
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGTERM,
terminate_child, None)
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT,
terminate_child, None)

try:
# Create status icon
s = RedshiftStatusIcon(c)

# Run main loop
Gtk.main()
finally:
# Always make sure that the child process is closed
c.termwait()
except:
c.kill_child()
raise

0 comments on commit 7e9ef55

Please sign in to comment.