From 3a7e7cdde04a032fec3d6986955f2d12dd8d3aca Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Wed, 10 Feb 2016 21:30:59 +0100 Subject: [PATCH 1/2] process: Rename exit_handler() to sigterm_handler() --- mopidy/__main__.py | 2 +- mopidy/internal/process.py | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/mopidy/__main__.py b/mopidy/__main__.py index ee87b82d..86a0c19c 100644 --- a/mopidy/__main__.py +++ b/mopidy/__main__.py @@ -27,7 +27,7 @@ def main(): log.bootstrap_delayed_logging() logger.info('Starting Mopidy %s', versioning.get_version()) - signal.signal(signal.SIGTERM, process.exit_handler) + signal.signal(signal.SIGTERM, process.sigterm_handler) # Windows does not have signal.SIGUSR1 if hasattr(signal, 'SIGUSR1'): signal.signal(signal.SIGUSR1, pykka.debug.log_thread_tracebacks) diff --git a/mopidy/internal/process.py b/mopidy/internal/process.py index 8c8af18f..4bf681dd 100644 --- a/mopidy/internal/process.py +++ b/mopidy/internal/process.py @@ -1,7 +1,6 @@ from __future__ import absolute_import, unicode_literals import logging -import signal import threading import pykka @@ -12,20 +11,23 @@ from mopidy.compat import thread logger = logging.getLogger(__name__) -SIGNALS = dict( - (k, v) for v, k in signal.__dict__.items() - if v.startswith('SIG') and not v.startswith('SIG_')) - - def exit_process(): logger.debug('Interrupting main...') thread.interrupt_main() logger.debug('Interrupted main') -def exit_handler(signum, frame): - """A :mod:`signal` handler which will exit the program on signal.""" - logger.info('Got %s signal', SIGNALS[signum]) +def sigterm_handler(signum, frame): + """A :mod:`signal` handler which will exit the program on signal. + + This function is not called when the process' main thread is running a GLib + mainloop. In that case, the GLib mainloop must listen for SIGTERM signals + and quit itself. + + For Mopidy subcommands that does not run the GLib mainloop, this handler + ensures a proper shutdown of the process on SIGTERM. + """ + logger.info('Got SIGTERM signal. Exiting...') exit_process() From e88b2a7beb24f33e4821f75368ef1727d1d384bc Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Wed, 10 Feb 2016 21:37:25 +0100 Subject: [PATCH 2/2] commands: Make GLib quit mainloop on SIGTERM Fixes #1435 --- mopidy/commands.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/mopidy/commands.py b/mopidy/commands.py index 74905f8f..50590172 100644 --- a/mopidy/commands.py +++ b/mopidy/commands.py @@ -5,6 +5,7 @@ import collections import contextlib import logging import os +import signal import sys import pykka @@ -13,7 +14,7 @@ from mopidy import config as config_lib, exceptions from mopidy.audio import Audio from mopidy.core import Core from mopidy.internal import deps, process, timer, versioning -from mopidy.internal.gi import GLib, GObject +from mopidy.internal.gi import GLib logger = logging.getLogger(__name__) @@ -283,7 +284,13 @@ class RootCommand(Command): help='`section/key=value` values to override config options') def run(self, args, config): - loop = GObject.MainLoop() + def on_sigterm(loop): + logger.info('GLib mainloop got SIGTERM. Exiting...') + loop.quit() + + loop = GLib.MainLoop() + GLib.unix_signal_add( + GLib.PRIORITY_DEFAULT, signal.SIGTERM, on_sigterm, loop) mixer_class = self.get_mixer_class(config, args.registry['mixer']) backend_classes = args.registry['backend'] @@ -300,6 +307,7 @@ class RootCommand(Command): backends = self.start_backends(config, backend_classes, audio) core = self.start_core(config, mixer, backends, audio) self.start_frontends(config, frontend_classes, core) + logger.info('Starting GLib mainloop') loop.run() except (exceptions.BackendError, exceptions.FrontendError,