~thomir-deactivatedaccount/unity/glib-loop-threading

« back to all changes in this revision

Viewing changes to autopilot/glibrunner.py

  • Committer: Thomi Richards
  • Date: 2012-08-02 19:55:24 UTC
  • Revision ID: thomi.richards@canonical.com-20120802195524-vj6cgig16pedtsrh
In the middle of hacking.

Show diffs side-by-side

added added

removed removed

Lines of Context:
8
8
 
9
9
from __future__ import absolute_import
10
10
 
 
11
import dbus.glib
 
12
 
11
13
import sys
12
 
import dbus
13
 
from dbus.mainloop.glib import DBusGMainLoop
14
 
import gobject
 
14
# import dbus
 
15
# from dbus.mainloop.glib import DBusGMainLoop
15
16
import glib
16
 
import gtk
17
 
import gtk.gdk
 
17
# import gtk
 
18
# import gtk.gdk
18
19
import testtools
 
20
import time
19
21
import threading
 
22
try:
 
23
    import faulthandler
 
24
    faulthandler.enable()
 
25
except:
 
26
    pass
20
27
 
 
28
# Pokemon functions: gotta call 'em all!
 
29
# If you don't, random glib/gobject/gtk functions will hang...
21
30
glib.threads_init()
22
 
dbus.mainloop.glib.threads_init()
23
 
gtk.gdk.threads_init()
24
 
 
25
 
 
26
 
# Turning run_in_glib_loop into a decorator is left as an exercise for the
27
 
# reader.
 
31
dbus.glib.threads_init()
 
32
# dbus.mainloop.glib.threads_init()
 
33
# gtk.gdk.threads_init()
 
34
 
 
35
class WorkerThread(threading.Thread):
 
36
    def __init__(self, loop, worker):
 
37
        super(WorkerThread, self).__init__()
 
38
        self.loop = loop
 
39
        self.worker = worker
 
40
        self.errors = []
 
41
        self.result = None
 
42
 
 
43
    def run(self):
 
44
        try:
 
45
            while self.loop.is_running() is False:
 
46
                # _print("Thread '%i': mainloop not yet running, backing off" % (self.ident, ))
 
47
                time.sleep(0.5)
 
48
                continue
 
49
            # from autopilot.emulators.bamf import Bamf
 
50
            # print Bamf().get_running_applications()
 
51
            self.result = self.worker()
 
52
        except:
 
53
            self.errors.append(sys.exc_info())
 
54
            # XXX: Not sure if this is needed / desired
 
55
            raise
 
56
        finally:
 
57
            # print "Quitting main loop now."
 
58
            glib.idle_add(self.loop.quit)
 
59
            # gtk.mainquit()
 
60
            print "Done"
 
61
 
 
62
 
28
63
def run_in_glib_loop(function, *args, **kwargs):
29
 
    # log.info("Running: %r with args: %r and kwargs: %r", function, args, kwargs)
30
 
    loop = gobject.MainLoop()
31
 
    # XXX: I think this has re-entrancy problems.  There is parallel code in
32
 
    # testtools somewhere (spinner.py or deferredruntest.py)
33
 
    result = []
34
 
    errors = []
35
 
 
36
 
    # This function is run in a worker thread. The GLib main loop is guaranteed to
37
 
    # be started before this function is run.
38
 
    class ThreadTest(threading.Thread):
39
 
        def __init__(self, loop):
40
 
            super(ThreadTest, self).__init__()
41
 
            self.loop = loop
42
 
 
43
 
        def run(self):
44
 
            DBusGMainLoop(set_as_default=True)
45
 
            try:
46
 
                # import pdb; pdb.set_trace()
47
 
                result.append(function(*args, **kwargs))
48
 
            except:
49
 
                errors.append(sys.exc_info())
50
 
                # XXX: Not sure if this is needed / desired
51
 
                raise
52
 
            finally:
53
 
                self.loop.quit()
54
 
 
55
 
    thread = ThreadTest(loop)
56
 
    # Calling thread.start directly here creates a possible race condition. We
57
 
    # need to be assured that the glib main loop has started by the time the test
58
 
    # is running, so we start the thread from the main loop itself. This waits
59
 
    # 10 mS - it could possibly be set to 0.
60
 
    glib.timeout_add(10, thread.start)
61
 
    # loop.run()
62
 
    gtk.threads_enter()
63
 
    gtk.main()
64
 
    gtk.threads_leave()
65
 
 
66
 
 
 
64
    # set_main_loop()
 
65
    loop = glib.MainLoop()
 
66
    # dbus.set_default_main_loop(dbus_loop)
 
67
 
 
68
    thread = WorkerThread(loop, lambda: function(*args, **kwargs))
 
69
    thread.start()
 
70
    loop.run()
 
71
    print "Loop finished."
67
72
    thread.join()
 
73
    # print "Thread joined"
68
74
    if thread.is_alive():
69
75
        raise RuntimeError("Test %r did not exit after 120 seconds." % function)
70
76
 
71
 
    # assert loop.is_running() == False, "Loop should not be running after thread has quit!"
72
 
 
73
 
    if errors:
74
 
        raise errors[0]
75
 
    return True
 
77
    if thread.errors:
 
78
        raise thread.errors[0]
 
79
    return thread.result
76
80
 
77
81
 
78
82
class GlibRunner(testtools.RunTest):