From 543296a62235d5303662720d3f341e1dc10d478e Mon Sep 17 00:00:00 2001 From: Kali Kaneko Date: Wed, 9 Jul 2014 00:39:36 -0500 Subject: invoke mainwindow.quit only from parent pid because the fork happens after the registration of the signal handler, all children processes were inheriting the handler (and being passed a reference to the mainwindow object, ugh...) --- src/leap/bitmask/app.py | 67 +++++++++++++++++++++++++++++++------------------ 1 file changed, 43 insertions(+), 24 deletions(-) (limited to 'src/leap/bitmask/app.py') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index 6a7d6ff1..d0906b7c 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -49,7 +49,6 @@ from PySide import QtCore, QtGui from leap.bitmask import __version__ as VERSION from leap.bitmask.config import flags -from leap.bitmask.gui import locale_rc # noqa - silence pylint from leap.bitmask.gui.mainwindow import MainWindow from leap.bitmask.logs.utils import create_logger from leap.bitmask.platform_init.locks import we_are_the_one_and_only @@ -67,16 +66,39 @@ import codecs codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None) +import psutil + + +def kill_the_children(): + """ + Make sure no lingering subprocesses are left in case of a bad termination. + """ + me = os.getpid() + parent = psutil.Process(me) + print "Killing all the children processes..." + for child in parent.get_children(recursive=True): + try: + child.terminate() + except Exception as exc: + print exc + +# XXX This is currently broken, but we need to fix it to avoid +# orphaned processes in case of a crash. +#atexit.register(kill_the_children) + def sigint_handler(*args, **kwargs): """ Signal handler for SIGINT """ logger = kwargs.get('logger', None) - if logger: - logger.debug("SIGINT catched. shutting down...") - mainwindow = args[0] - mainwindow.quit() + parentpid = kwargs.get('parentpid', None) + pid = os.getpid() + if parentpid == pid: + if logger: + logger.debug("SIGINT catched. shutting down...") + mainwindow = args[0] + mainwindow.quit() def sigterm_handler(*args, **kwargs): @@ -85,10 +107,13 @@ def sigterm_handler(*args, **kwargs): This handler is actually passed to twisted reactor """ logger = kwargs.get('logger', None) - if logger: - logger.debug("SIGTERM catched. shutting down...") - mainwindow = args[0] - mainwindow.quit() + parentpid = kwargs.get('parentpid', None) + pid = os.getpid() + if parentpid == pid: + if logger: + logger.debug("SIGTERM catched. shutting down...") + mainwindow = args[0] + mainwindow.quit() def do_display_version(opts): @@ -203,32 +228,26 @@ def main(): app.setApplicationName("leap") app.setOrganizationDomain("leap.se") - # XXX --------------------------------------------------------- - # In quarantine, looks like we don't need it anymore. - # This dummy timer ensures that control is given to the outside - # loop, so we can hook our sigint handler. - #timer = QtCore.QTimer() - #timer.start(500) - #timer.timeout.connect(lambda: None) - # XXX --------------------------------------------------------- - window = MainWindow(bypass_checks=bypass_checks, start_hidden=start_hidden) - sigint_window = partial(sigint_handler, window, logger=logger) + mainpid = os.getpid() + sigint_window = partial(sigint_handler, window, + logger=logger, parentpid=mainpid) signal.signal(signal.SIGINT, sigint_window) # callable used in addSystemEventTrigger to handle SIGTERM - sigterm_window = partial(sigterm_handler, window, logger=logger) - - l = LoopingCall(QtCore.QCoreApplication.processEvents, 0, 10) - l.start(0.01) - + sigterm_window = partial(sigterm_handler, window, + logger=logger, parentpid=mainpid) # SIGTERM can't be handled the same way SIGINT is, since it's # caught by twisted. See _handleSignals method in # twisted/internet/base.py#L1150. So, addSystemEventTrigger # reactor's method is used. reactor.addSystemEventTrigger('before', 'shutdown', sigterm_window) + + l = LoopingCall(QtCore.QCoreApplication.processEvents, 0, 10) + l.start(0.01) + reactor.run() if __name__ == "__main__": -- cgit v1.2.3 From 3795dedd26fc239e143ca2a29b7e16d433f964ba Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Tue, 10 Jun 2014 17:05:06 -0300 Subject: Separate app.py and frontend_app.py logics. This prepares the scenario to run the frontend and the backend in different processes. --- src/leap/bitmask/app.py | 106 +++++++----------------------------------------- 1 file changed, 15 insertions(+), 91 deletions(-) (limited to 'src/leap/bitmask/app.py') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index d0906b7c..f1d87d18 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -39,17 +39,13 @@ # M:::::::::::~NMMM7???7MMMM:::::::::::::::::::::::NMMMI??I7MMMM:::::::::::::M # M::::::::::::::7MMMMMMM+:::::::::::::::::::::::::::?MMMMMMMZ:::::::::::::::M # (thanks to: http://www.glassgiant.com/ascii/) -import signal -import sys +import multiprocessing import os - -from functools import partial - -from PySide import QtCore, QtGui +import sys from leap.bitmask import __version__ as VERSION from leap.bitmask.config import flags -from leap.bitmask.gui.mainwindow import MainWindow +from leap.bitmask.frontend_app import run_frontend from leap.bitmask.logs.utils import create_logger from leap.bitmask.platform_init.locks import we_are_the_one_and_only from leap.bitmask.services.mail import plumber @@ -59,9 +55,6 @@ from leap.bitmask.util.requirement_checker import check_requirements from leap.common.events import server as event_server from leap.mail import __version__ as MAIL_VERSION -from twisted.internet import reactor -from twisted.internet.task import LoopingCall - import codecs codecs.register(lambda name: codecs.lookup('utf-8') if name == 'cp65001' else None) @@ -84,36 +77,7 @@ def kill_the_children(): # XXX This is currently broken, but we need to fix it to avoid # orphaned processes in case of a crash. -#atexit.register(kill_the_children) - - -def sigint_handler(*args, **kwargs): - """ - Signal handler for SIGINT - """ - logger = kwargs.get('logger', None) - parentpid = kwargs.get('parentpid', None) - pid = os.getpid() - if parentpid == pid: - if logger: - logger.debug("SIGINT catched. shutting down...") - mainwindow = args[0] - mainwindow.quit() - - -def sigterm_handler(*args, **kwargs): - """ - Signal handler for SIGTERM. - This handler is actually passed to twisted reactor - """ - logger = kwargs.get('logger', None) - parentpid = kwargs.get('parentpid', None) - pid = os.getpid() - if parentpid == pid: - if logger: - logger.debug("SIGTERM catched. shutting down...") - mainwindow = args[0] - mainwindow.quit() +# atexit.register(kill_the_children) def do_display_version(opts): @@ -141,7 +105,7 @@ def do_mail_plumbing(opts): # XXX catch when import is used w/o acct -def main(): +def start_app(): """ Starts the main event loop and launches the main window. """ @@ -149,8 +113,12 @@ def main(): opts = leap_argparse.get_options() do_display_version(opts) - bypass_checks = opts.danger - start_hidden = opts.start_hidden + options = { + 'bypass_checks': opts.danger, + 'start_hidden': opts.start_hidden, + 'debug': opts.debug, + 'log_file': opts.log_file, + } flags.STANDALONE = opts.standalone flags.OFFLINE = opts.offline @@ -202,53 +170,9 @@ def main(): logger.info('Starting app') - # We force the style if on KDE so that it doesn't load all the kde - # libs, which causes a compatibility issue in some systems. - # For more info, see issue #3194 - if flags.STANDALONE and os.environ.get("KDE_SESSION_UID") is not None: - sys.argv.append("-style") - sys.argv.append("Cleanlooks") - - app = QtGui.QApplication(sys.argv) - - # To test: - # $ LANG=es ./app.py - locale = QtCore.QLocale.system().name() - qtTranslator = QtCore.QTranslator() - if qtTranslator.load("qt_%s" % locale, ":/translations"): - app.installTranslator(qtTranslator) - appTranslator = QtCore.QTranslator() - if appTranslator.load("%s.qm" % locale[:2], ":/translations"): - app.installTranslator(appTranslator) - - # Needed for initializing qsettings it will write - # .config/leap/leap.conf top level app settings in a platform - # independent way - app.setOrganizationName("leap") - app.setApplicationName("leap") - app.setOrganizationDomain("leap.se") - - window = MainWindow(bypass_checks=bypass_checks, - start_hidden=start_hidden) - - mainpid = os.getpid() - sigint_window = partial(sigint_handler, window, - logger=logger, parentpid=mainpid) - signal.signal(signal.SIGINT, sigint_window) - - # callable used in addSystemEventTrigger to handle SIGTERM - sigterm_window = partial(sigterm_handler, window, - logger=logger, parentpid=mainpid) - # SIGTERM can't be handled the same way SIGINT is, since it's - # caught by twisted. See _handleSignals method in - # twisted/internet/base.py#L1150. So, addSystemEventTrigger - # reactor's method is used. - reactor.addSystemEventTrigger('before', 'shutdown', sigterm_window) - - l = LoopingCall(QtCore.QCoreApplication.processEvents, 0, 10) - l.start(0.01) - - reactor.run() + frontend = multiprocessing.Process(target=run_frontend, args=(options, )) + frontend.start() + if __name__ == "__main__": - main() + start_app() -- cgit v1.2.3 From 6dbd52e2f0d75ad9bf7c2f11e3384d8bab0520c9 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 18 Jun 2014 12:37:23 -0300 Subject: Use new backend/signaler and start logic in processes. --- src/leap/bitmask/app.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'src/leap/bitmask/app.py') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index f1d87d18..9afe41be 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -43,9 +43,12 @@ import multiprocessing import os import sys +from leap.bitmask.backend.utils import generate_certificates + from leap.bitmask import __version__ as VERSION from leap.bitmask.config import flags from leap.bitmask.frontend_app import run_frontend +from leap.bitmask.backend.leapbackend import run_backend from leap.bitmask.logs.utils import create_logger from leap.bitmask.platform_init.locks import we_are_the_one_and_only from leap.bitmask.services.mail import plumber @@ -114,7 +117,6 @@ def start_app(): do_display_version(opts) options = { - 'bypass_checks': opts.danger, 'start_hidden': opts.start_hidden, 'debug': opts.debug, 'log_file': opts.log_file, @@ -170,8 +172,15 @@ def start_app(): logger.info('Starting app') - frontend = multiprocessing.Process(target=run_frontend, args=(options, )) - frontend.start() + generate_certificates() + + app = lambda: run_frontend(options=options) + gui_process = multiprocessing.Process(target=app) + gui_process.start() + + backend = lambda: run_backend(bypass_checks=opts.danger) + backend_process = multiprocessing.Process(target=backend) + backend_process.start() if __name__ == "__main__": -- cgit v1.2.3 From c46a93e290194cdeb1b4e1776d4bf0edde303072 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 25 Jun 2014 12:36:25 -0300 Subject: Add SIGINT handler. --- src/leap/bitmask/app.py | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/leap/bitmask/app.py') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index 9afe41be..eda4073c 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -41,6 +41,7 @@ # (thanks to: http://www.glassgiant.com/ascii/) import multiprocessing import os +import signal import sys from leap.bitmask.backend.utils import generate_certificates @@ -112,6 +113,9 @@ def start_app(): """ Starts the main event loop and launches the main window. """ + # Ensure that the application quits using CTRL-C + signal.signal(signal.SIGINT, signal.SIG_DFL) + # Parse arguments and store them opts = leap_argparse.get_options() do_display_version(opts) -- cgit v1.2.3 From cf75e3575c33249a6f756dceb423c6ec7f6cd50e Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 2 Jul 2014 12:14:22 -0300 Subject: Move the backend starter to its own file. --- src/leap/bitmask/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/leap/bitmask/app.py') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index eda4073c..43dabad3 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -49,7 +49,7 @@ from leap.bitmask.backend.utils import generate_certificates from leap.bitmask import __version__ as VERSION from leap.bitmask.config import flags from leap.bitmask.frontend_app import run_frontend -from leap.bitmask.backend.leapbackend import run_backend +from leap.bitmask.backend_app import run_backend from leap.bitmask.logs.utils import create_logger from leap.bitmask.platform_init.locks import we_are_the_one_and_only from leap.bitmask.services.mail import plumber -- cgit v1.2.3 From 0cab909f9518273d95e371e5fb1061fb9b0a92fd Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 2 Jul 2014 12:52:31 -0300 Subject: Send the flag module values to the processes. Add serialize/deserialize to dict helper. --- src/leap/bitmask/app.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/leap/bitmask/app.py') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index 43dabad3..d1a2a111 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -53,7 +53,7 @@ from leap.bitmask.backend_app import run_backend from leap.bitmask.logs.utils import create_logger from leap.bitmask.platform_init.locks import we_are_the_one_and_only from leap.bitmask.services.mail import plumber -from leap.bitmask.util import leap_argparse +from leap.bitmask.util import leap_argparse, flags_to_dict from leap.bitmask.util.requirement_checker import check_requirements from leap.common.events import server as event_server @@ -178,11 +178,13 @@ def start_app(): generate_certificates() - app = lambda: run_frontend(options=options) + flags_dict = flags_to_dict() + + app = lambda: run_frontend(options, flags_dict) gui_process = multiprocessing.Process(target=app) gui_process.start() - backend = lambda: run_backend(bypass_checks=opts.danger) + backend = lambda: run_backend(opts.danger, flags_dict) backend_process = multiprocessing.Process(target=backend) backend_process.start() -- cgit v1.2.3 From c3f485e194eb32939755178b11d472e1e69a94ad Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Wed, 2 Jul 2014 16:43:58 -0300 Subject: Handle SIGINT/SIGTERM in processes. --- src/leap/bitmask/app.py | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) (limited to 'src/leap/bitmask/app.py') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index d1a2a111..fa244470 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -44,6 +44,8 @@ import os import signal import sys +from functools import partial + from leap.bitmask.backend.utils import generate_certificates from leap.bitmask import __version__ as VERSION @@ -109,12 +111,33 @@ def do_mail_plumbing(opts): # XXX catch when import is used w/o acct +def sigterm_handler(logger, gui_process, backend_process, signum, frame): + """ + Signal handler that quits the running app cleanly. + + :param logger: the configured logger object. + :type logger: logging.Logger + :param gui_process: the GUI process + :type gui_process: multiprocessing.Process + :param backend_process: the backend process + :type backend_process: multiprocessing.Process + :param signum: number of the signal received (e.g. SIGINT -> 2) + :type signum: int + :param frame: current stack frame + :type frame: frame or None + """ + logger.debug("SIGTERM catched, terminating processes.") + gui_process.terminate() + # Don't terminate the backend, the frontend takes care of that. + # backend_process.terminate() + + def start_app(): """ Starts the main event loop and launches the main window. """ - # Ensure that the application quits using CTRL-C - signal.signal(signal.SIGINT, signal.SIG_DFL) + # Ignore the signals since we handle them in the subprocesses + # signal.signal(signal.SIGINT, signal.SIG_IGN) # Parse arguments and store them opts = leap_argparse.get_options() @@ -181,13 +204,18 @@ def start_app(): flags_dict = flags_to_dict() app = lambda: run_frontend(options, flags_dict) - gui_process = multiprocessing.Process(target=app) + gui_process = multiprocessing.Process(target=app, name='Frontend') gui_process.start() backend = lambda: run_backend(opts.danger, flags_dict) - backend_process = multiprocessing.Process(target=backend) + backend_process = multiprocessing.Process(target=backend, name='Backend') backend_process.start() + handle_sigterm = partial(sigterm_handler, logger, + gui_process, backend_process) + signal.signal(signal.SIGTERM, handle_sigterm) + signal.signal(signal.SIGINT, handle_sigterm) + if __name__ == "__main__": start_app() -- cgit v1.2.3 From 525433088d6fbe3392af90942272dfd5dd2511d6 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Fri, 11 Jul 2014 12:28:20 -0300 Subject: Use main process to run frontend. Running the GUI in a child process gives problems on OSX. Also, change signal handling since we have less processes. --- src/leap/bitmask/app.py | 34 +++------------------------------- 1 file changed, 3 insertions(+), 31 deletions(-) (limited to 'src/leap/bitmask/app.py') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index fa244470..e80b9dd1 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -41,10 +41,8 @@ # (thanks to: http://www.glassgiant.com/ascii/) import multiprocessing import os -import signal import sys -from functools import partial from leap.bitmask.backend.utils import generate_certificates @@ -111,27 +109,6 @@ def do_mail_plumbing(opts): # XXX catch when import is used w/o acct -def sigterm_handler(logger, gui_process, backend_process, signum, frame): - """ - Signal handler that quits the running app cleanly. - - :param logger: the configured logger object. - :type logger: logging.Logger - :param gui_process: the GUI process - :type gui_process: multiprocessing.Process - :param backend_process: the backend process - :type backend_process: multiprocessing.Process - :param signum: number of the signal received (e.g. SIGINT -> 2) - :type signum: int - :param frame: current stack frame - :type frame: frame or None - """ - logger.debug("SIGTERM catched, terminating processes.") - gui_process.terminate() - # Don't terminate the backend, the frontend takes care of that. - # backend_process.terminate() - - def start_app(): """ Starts the main event loop and launches the main window. @@ -203,18 +180,13 @@ def start_app(): flags_dict = flags_to_dict() - app = lambda: run_frontend(options, flags_dict) - gui_process = multiprocessing.Process(target=app, name='Frontend') - gui_process.start() - backend = lambda: run_backend(opts.danger, flags_dict) backend_process = multiprocessing.Process(target=backend, name='Backend') + backend_process.daemon = True backend_process.start() - handle_sigterm = partial(sigterm_handler, logger, - gui_process, backend_process) - signal.signal(signal.SIGTERM, handle_sigterm) - signal.signal(signal.SIGINT, handle_sigterm) + run_frontend(options, flags_dict) + if __name__ == "__main__": -- cgit v1.2.3 From d6cee5b46587367b558863292f71f5baafadc762 Mon Sep 17 00:00:00 2001 From: Ivan Alejandro Date: Mon, 14 Jul 2014 12:23:13 -0300 Subject: pep8 fixes --- src/leap/bitmask/app.py | 1 - 1 file changed, 1 deletion(-) (limited to 'src/leap/bitmask/app.py') diff --git a/src/leap/bitmask/app.py b/src/leap/bitmask/app.py index e80b9dd1..88f6bc15 100644 --- a/src/leap/bitmask/app.py +++ b/src/leap/bitmask/app.py @@ -188,6 +188,5 @@ def start_app(): run_frontend(options, flags_dict) - if __name__ == "__main__": start_app() -- cgit v1.2.3