views:

233

answers:

1

Hi all,

Basically, I have a python program which listens for DeviceAdded DBus events (e.g. when someone plugs in a USB drive), and when an event occurs, I want to create a thread which collects metadata on that newly connected device. However, I want to do this asynchronously - that is, allow one thread to keep collecting metadata on the device while returning control to the parent which can keep listening for these events. At the moment, my thread blocks until the collection is finished. Here is a sample of my code:

class DeviceAddedListener:
def __init__(self):
    self.bus = dbus.SystemBus()
    self.hal_manager_obj = self.bus.get_object("org.freedesktop.Hal", "/org$
    self.hal_manager = dbus.Interface(self.hal_manager_obj, "org.freedeskto$
    self.hal_manager.connect_to_signal("DeviceAdded", self._filter)

def _filter(self, udi):
    device_obj = self.bus.get_object ("org.freedesktop.Hal", udi)
    device = dbus.Interface(device_obj, "org.freedesktop.Hal.Device")

    if device.QueryCapability("volume"):
        return self.capture(device)

def capture(self,volume):
    self.device_file = volume.GetProperty("block.device")
    self.label = volume.GetProperty("volume.label")
    self.fstype = volume.GetProperty("volume.fstype")
    self.mounted = volume.GetProperty("volume.is_mounted")
    self.mount_point = volume.GetProperty("volume.mount_point")
    try:
        self.size = volume.GetProperty("volume.size")
    except:
        self.size = 0

    print "New storage device detected:"
    print " device_file: %s" % self.device_file
    print " label: %s" % self.label
    print " fstype: %s" % self.fstype
    if self.mounted:
        print "  mount_point: %s" % self.mount_point
    response = raw_input("\nWould you like to acquire %s [y/N]? " % self.device_file)
    if (response == "y"):
        self.get_meta()
        thread.start_new_thread(DoSomething(self.device_file))
    else:
        print "Returning to idle"


if __name__ == '__main__':
from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)
loop = gobject.MainLoop()
DeviceAddedListener()
loop.run()

Any thoughts would be greatly appreciated :) I have excluded the import list to save space

+2  A: 

Try spawning a thread just for the capture stuff, by changing the following lines in your _filter() function to this:

if device.QueryCapability("volume"):
    threading.start_new_thread(self.capture, (device))

This is assuming that the bulk of the work is happening in the capture() function. If not, then just spawn the thread a little earlier, possibly on the whole _filter() function. This should then spawn a new thread for every filtered device detected. Bear in mind that I haven't done any dbus stuff and can't really test this, but it's an idea.

Also, you're trying to get user input from the capture function which, using the app as you've defined it, isn't really a nice thing to do in threads. What if a second device is connected while the first prompt is still on screen? Might not play nicely.

The design of this thing might be exactly the way you want it for specific reasons, but I can't help feeling like it could be a lot slicker. It's not really designed with threads in mind from what I can tell.

Wayne Koorts