diff --git a/qubesmanager/backup_utils.py b/qubesmanager/backup_utils.py index 4cec39c..368b546 100644 --- a/qubesmanager/backup_utils.py +++ b/qubesmanager/backup_utils.py @@ -72,6 +72,8 @@ def umount_device(dev_mount_path): def fill_devs_list(dialog): dialog.dev_combobox.clear() dialog.dev_combobox.addItem("None") + + dialog.blk_manager.blk_lock.acquire() for a in dialog.blk_manager.attached_devs: if dialog.blk_manager.attached_devs[a]['attached_to']['vm'] == dialog.vm.name : att = a + " " + unicode(dialog.blk_manager.attached_devs[a]['size']) + " " + dialog.blk_manager.attached_devs[a]['desc'] @@ -79,6 +81,8 @@ def fill_devs_list(dialog): for a in dialog.blk_manager.free_devs: att = a + " " + unicode(dialog.blk_manager.free_devs[a]['size']) + " " + dialog.blk_manager.free_devs[a]['desc'] dialog.dev_combobox.addItem(att, QVariant(a)) + dialog.blk_manager.blk_lock.release() + dialog.dev_combobox.setCurrentIndex(0) #current selected is null "" dialog.prev_dev_idx = 0 dialog.dir_line_edit.clear() @@ -107,6 +111,7 @@ def dev_combobox_activated(dialog, idx): if dialog.dev_combobox.currentText() != "None": #An existing device chosen dev_name = str(dialog.dev_combobox.itemData(idx).toString()) + dialog.blk_manager.blk_lock.acquire() if dev_name in dialog.blk_manager.free_devs: if dev_name.startswith(dialog.vm.name): # originally attached to dom0 dev_path = "/dev/"+dev_name.split(":")[1] @@ -118,6 +123,7 @@ def dev_combobox_activated(dialog, idx): if dev_name in dialog.blk_manager.attached_devs: #is attached to dom0 assert dialog.blk_manager.attached_devs[dev_name]['attached_to']['vm'] == dialog.vm.name dev_path = "/dev/" + dialog.blk_manager.attached_devs[dev_name]['attached_to']['frontend'] + dialog.blk_manager.blk_lock.release() #check if device mounted dialog.dev_mount_path = check_if_mounted(dev_path) diff --git a/qubesmanager/main.py b/qubesmanager/main.py index 49ff193..d12f083 100755 --- a/qubesmanager/main.py +++ b/qubesmanager/main.py @@ -557,9 +557,14 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): self.setupUi(self) self.toolbar = self.toolBar + self.qubes_watch = qubesutils.QubesWatch() self.qvm_collection = QubesVmCollection() self.blk_manager = QubesBlockDevicesManager(self.qvm_collection) - + self.qubes_watch.setup_block_watch(self.blk_manager.block_devs_event) + self.blk_watch_thread = threading.Thread(target=self.qubes_watch.watch_loop) + self.blk_watch_thread.daemon = True + self.blk_watch_thread.start() + self.connect(self.table, SIGNAL("itemSelectionChanged()"), self.table_selection_changed) self.table.setColumnWidth(0, self.column_width) @@ -794,8 +799,10 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): rows_with_blk = None if update_devs == True: rows_with_blk = [] + self.blk_manager.blk_lock.acquire() for d in self.blk_manager.attached_devs: rows_with_blk.append( self.blk_manager.attached_devs[d]['attached_to']['vm']) + self.blk_manager.blk_lock.release() if self.counter % 3 == 0 or out_of_schedule: (self.last_measure_time, self.last_measure_results) = \ @@ -843,7 +850,7 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): def update_block_devices(self): - res, msg = self.blk_manager.update() + res, msg = self.blk_manager.check_for_updates() if msg != None and len(msg) > 0: str = "\n".join(msg) trayIcon.showMessage ("Qubes Manager", str, msecs=5000) @@ -1304,6 +1311,8 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): else: self.blk_menu.clear() self.blk_menu.setEnabled(True) + + self.blk_manager.blk_lock.acquire() if len(self.blk_manager.attached_devs) > 0 : for d in self.blk_manager.attached_devs: if self.blk_manager.attached_devs[d]['attached_to']['vm'] == vm.name: @@ -1319,6 +1328,8 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): action = self.blk_menu.addAction(QIcon(":/add.png"), str) action.setData(QVariant(d)) + self.blk_manager.blk_lock.release() + if self.blk_menu.isEmpty(): self.blk_menu.setEnabled(False) @@ -1328,10 +1339,13 @@ class VmManagerWindow(Ui_VmManagerWindow, QMainWindow): def attach_dettach_device_triggered(self, action): dev = str(action.data().toString()) vm = self.get_selected_vm() + + self.blk_manager.blk_lock.acquire() if dev in self.blk_manager.attached_devs: self.blk_manager.detach_device(vm, dev) else: self.blk_manager.attach_device(vm, dev) + self.blk_manager.blk_lock.release() class QubesBlockDevicesManager(): @@ -1344,43 +1358,75 @@ class QubesBlockDevicesManager(): self.current_attached = {} self.devs_changed = False + self.last_update_time = time.time() + self.blk_state_changed = True + self.msg = [] + self.check_counter = 0 + self.blk_lock = threading.Lock() + + self.update() + + def block_devs_event(self, xid): + now = time.time() + #don't update more often than 1/10 s + if now - self.last_update_time >= 0.1: + self.last_update_time = now + + self.blk_lock.acquire() + + self.blk_state_changed = True + + self.blk_lock.release() + + def check_for_updates(self): + self.blk_lock.acquire() + + ret = (self.blk_state_changed, self.msg) + + if self.blk_state_changed == True: + self.check_counter += 1 + + self.update() + ret = (self.blk_state_changed, self.msg) + + #let the update last for 3 manager-update cycles + if self.check_counter == 3: + self.check_counter = 0 + self.blk_state_changed = False + self.msg = [] + + self.blk_lock.release() + + return ret + + def update(self): blk = qubesutils.block_list() - msg = [] for b in blk: att = qubesutils.block_check_attached(None, blk[b]['device'], backend_xid = blk[b]['xid']) if b in self.current_blk: if blk[b] == self.current_blk[b]: if self.current_attached[b] != att: #devices the same, sth with attaching changed self.current_attached[b] = att - self.devs_changed = True else: #device changed ?! self.current_blk[b] = blk[b] self.current_attached[b] = att - self.devs_changed = True else: #new device self.current_blk[b] = blk[b] self.current_attached[b] = att - self.devs_changed = True - msg.append("Attached new device: {0}".format(blk[b]['device'])) + self.msg.append("Attached new device: {0}".format(blk[b]['device'])) to_delete = [] for b in self.current_blk: #remove devices that are not there anymore if b not in blk: to_delete.append(b) - self.devs_changed = True - msg.append("Detached device: {0}".format(self.current_blk[b]['device'])) + self.msg.append("Detached device: {0}".format(self.current_blk[b]['device'])) for d in to_delete: del self.current_blk[d] del self.current_attached[d] - if self.devs_changed == True: - self.devs_changed = False - self.__update_blk_entries__() - return True, msg - else: - return False, None + self.__update_blk_entries__() def __update_blk_entries__(self): @@ -1408,16 +1454,12 @@ class QubesBlockDevicesManager(): backend_vm = self.qvm_collection.get_vm_by_name(backend_vm_name) trayIcon.showMessage ("Qubes Manager", "{0} - attaching {1}".format(vm.name, dev), msecs=3000) qubesutils.block_attach(vm, backend_vm, dev_id) - self.devs_changed = True def detach_device(self, vm, dev_name): dev_id = self.attached_devs[dev_name]['attached_to']['devid'] vm_xid = self.attached_devs[dev_name]['attached_to']['xid'] trayIcon.showMessage ("Qubes Manager", "{0} - detaching {1}".format(vm.name, dev_name), msecs=3000) qubesutils.block_detach(None, dev_id, vm_xid) - self.devs_changed = True - - class QubesTrayIcon(QSystemTrayIcon):