112 lines
3.3 KiB
Python
112 lines
3.3 KiB
Python
import logging
|
|
import multiprocessing
|
|
import multiprocessing.dummy
|
|
from multiprocessing.reduction import reduce_connection
|
|
import pickle
|
|
|
|
import gobject
|
|
gobject.threads_init()
|
|
|
|
from mopidy import SettingsError
|
|
|
|
logger = logging.getLogger('mopidy.utils.process')
|
|
|
|
def pickle_connection(connection):
|
|
return pickle.dumps(reduce_connection(connection))
|
|
|
|
def unpickle_connection(pickled_connection):
|
|
# From http://stackoverflow.com/questions/1446004
|
|
(func, args) = pickle.loads(pickled_connection)
|
|
return func(*args)
|
|
|
|
class BaseProcess(multiprocessing.Process):
|
|
def __init__(self, core_queue):
|
|
super(BaseProcess, self).__init__()
|
|
self.core_queue = core_queue
|
|
|
|
def run(self):
|
|
logger.debug(u'%s: Starting process', self.name)
|
|
try:
|
|
self.run_inside_try()
|
|
except KeyboardInterrupt:
|
|
logger.info(u'Interrupted by user')
|
|
self.exit(0, u'Interrupted by user')
|
|
except SettingsError as e:
|
|
logger.error(e.message)
|
|
self.exit(1, u'Settings error')
|
|
except ImportError as e:
|
|
logger.error(e)
|
|
self.exit(2, u'Import error')
|
|
except Exception as e:
|
|
logger.exception(e)
|
|
self.exit(3, u'Unknown error')
|
|
|
|
def run_inside_try(self):
|
|
raise NotImplementedError
|
|
|
|
def destroy(self):
|
|
self.terminate()
|
|
|
|
def exit(self, status=0, reason=None):
|
|
self.core_queue.put({'to': 'core', 'command': 'exit',
|
|
'status': status, 'reason': reason})
|
|
self.destroy()
|
|
|
|
|
|
class BaseThread(multiprocessing.dummy.Process):
|
|
def __init__(self, core_queue):
|
|
super(BaseThread, self).__init__()
|
|
self.core_queue = core_queue
|
|
# No thread should block process from exiting
|
|
self.daemon = True
|
|
|
|
def run(self):
|
|
logger.debug(u'%s: Starting thread', self.name)
|
|
try:
|
|
self.run_inside_try()
|
|
except KeyboardInterrupt:
|
|
logger.info(u'Interrupted by user')
|
|
self.exit(0, u'Interrupted by user')
|
|
except SettingsError as e:
|
|
logger.error(e.message)
|
|
self.exit(1, u'Settings error')
|
|
except ImportError as e:
|
|
logger.error(e)
|
|
self.exit(2, u'Import error')
|
|
except Exception as e:
|
|
logger.exception(e)
|
|
self.exit(3, u'Unknown error')
|
|
|
|
def run_inside_try(self):
|
|
raise NotImplementedError
|
|
|
|
def destroy(self):
|
|
pass
|
|
|
|
def exit(self, status=0, reason=None):
|
|
self.core_queue.put({'to': 'core', 'command': 'exit',
|
|
'status': status, 'reason': reason})
|
|
self.destroy()
|
|
|
|
|
|
class GObjectEventThread(BaseThread):
|
|
"""
|
|
A GObject event loop which is shared by all Mopidy components that uses
|
|
libraries that need a GObject event loop, like GStreamer and D-Bus.
|
|
|
|
Should be started by Mopidy's core and used by
|
|
:mod:`mopidy.output.gstreamer`, :mod:`mopidy.frontend.mpris`, etc.
|
|
"""
|
|
|
|
def __init__(self, core_queue):
|
|
super(GObjectEventThread, self).__init__(core_queue)
|
|
self.name = u'GObjectEventThread'
|
|
self.loop = None
|
|
|
|
def run_inside_try(self):
|
|
self.loop = gobject.MainLoop().run()
|
|
|
|
def destroy(self):
|
|
self.loop.quit()
|
|
super(GObjectEventThread, self).destroy()
|