From 10c2dfebd5850f7950e6f0cbd746f38e7fc93c4d Mon Sep 17 00:00:00 2001 From: guinux Date: Wed, 27 Nov 2013 16:11:47 +0100 Subject: [PATCH] don't freeze gui during long makepkg tasks and avoid zombis with pamac-tray --- pamac-tray.py | 11 ++++++----- pamac/transaction.py | 43 +++++++++++++++++++++++++------------------ 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/pamac-tray.py b/pamac-tray.py index 5e757c4..2929ac5 100644 --- a/pamac-tray.py +++ b/pamac-tray.py @@ -19,9 +19,10 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA from gi.repository import Gtk, GObject, Notify -from subprocess import Popen +from subprocess import call import dbus from dbus.mainloop.glib import DBusGMainLoop +from threading import Thread from pamac import common @@ -64,10 +65,10 @@ class Tray: self.update_icon(icon, info) def execute_update(self, widget, event, data = None): - Popen(['/usr/bin/pamac-updater']) + Thread(target = call, args = (['/usr/bin/pamac-updater'],)).start() def execute_manager(self, widget, event, data = None): - Popen(['/usr/bin/pamac-manager']) + Thread(target = call, args = (['/usr/bin/pamac-manager'],)).start() def quit_tray(self, widget, data = None): Gtk.main_quit() @@ -80,7 +81,7 @@ class Tray: def activate_cb(self, widget, data = None): if icon == update_icon: - Popen(['/usr/bin/pamac-updater']) + Thread(target = call, args = (['/usr/bin/pamac-updater'],)).start() def update_icon(self, icon, info): self.statusIcon.set_from_file(icon) @@ -90,7 +91,7 @@ class Tray: self.statusIcon.set_visible(boolean) def refresh(): - Popen(['/usr/bin/pamac-refresh']) + Thread(target = call, args = (['/usr/bin/pamac-refresh'],)).start() def set_icon(update_data): global icon diff --git a/pamac/transaction.py b/pamac/transaction.py index c04871d..eda652a 100644 --- a/pamac/transaction.py +++ b/pamac/transaction.py @@ -29,6 +29,7 @@ import fnmatch #from urllib.parse import urlparse import dbus from dbus.mainloop.glib import DBusGMainLoop +import signal from pamac import config, common, aur @@ -134,18 +135,6 @@ def config_dbus_signals(): bus.add_signal_receiver(log_error, dbus_interface = "org.manjaro.pamac", signal_name = "EmitLogError") bus.add_signal_receiver(log_warning, dbus_interface = "org.manjaro.pamac", signal_name = "EmitLogWarning") -def write_to_buffer(fd, condition): - if condition == GObject.IO_IN: # if there's something interesting to read - line = fd.readline().decode(encoding='UTF-8') - #print(line.rstrip('\n')) - progress_buffer.insert_at_cursor(line) - progress_bar.pulse() - while Gtk.events_pending(): - Gtk.main_iteration() - return True # FUNDAMENTAL, otherwise the callback isn't recalled - else: - return False # Raised an error: exit - def action_handler(action): progress_label.set_text(action) @@ -468,16 +457,34 @@ def prepare(**trans_flags): return(error) def check_finished_build(data): + def handle_timeout(*args): + raise Exception('timeout') + global to_build global build_proc path = data[0] pkg = data[1] if build_proc.poll() is None: - progress_bar.pulse() - while Gtk.events_pending(): - Gtk.main_iteration() - return True + # Build no finished : read stdout to push it to text_buffer + # add a timeout to stop reading stdout if too long + # so the gui won't freeze + signal.signal(signal.SIGALRM, handle_timeout) + signal.setitimer(signal.ITIMER_REAL, 0.05) # 50 ms timeout + try: + line = build_proc.stdout.readline().decode(encoding='UTF-8') + #print(line.rstrip('\n')) + progress_buffer.insert_at_cursor(line) + progress_bar.pulse() + while Gtk.events_pending(): + Gtk.main_iteration() + except Exception: + while Gtk.events_pending(): + Gtk.main_iteration() + finally: + signal.alarm(0) + return True elif build_proc.poll() == 0: + # Build successfully finished built = [] # parse again PKGBUILD to have new pkg objects in case of a pkgver() function # was used so pkgver was changed during build process @@ -525,6 +532,7 @@ def check_finished_build(data): action_long_handler(_('Build process failed.')) return False elif build_proc.poll() == 1: + # Build finish with an error ProgressCancelButton.set_visible(False) ProgressCloseButton.set_visible(True) action_long_handler(_('Build process failed.')) @@ -625,10 +633,9 @@ def build_next(): progress_expander.set_expanded(True) ProgressWindow.show() build_proc = subprocess.Popen(["makepkg", "-cf"], cwd = path, stdout = subprocess.PIPE, stderr=subprocess.STDOUT) - GObject.io_add_watch(build_proc.stdout, GObject.IO_IN, write_to_buffer) while Gtk.events_pending(): Gtk.main_iteration() - GObject.timeout_add(500, check_finished_build, (path, pkg)) + GObject.timeout_add(100, check_finished_build, (path, pkg)) def finalize(): if To_Add() or To_Remove():