Merge lp:~cmiller/desktopcouch/segv-ya-rly into lp:desktopcouch

Proposed by Chad Miller
Status: Merged
Approved by: Tim Cole
Approved revision: 143
Merged at revision: not available
Proposed branch: lp:~cmiller/desktopcouch/segv-ya-rly
Merge into: lp:desktopcouch
Diff against target: 59 lines (+15/-4)
2 files modified
desktopcouch/replication_services/example.py (+3/-1)
desktopcouch/replication_services/ubuntuone.py (+12/-3)
To merge this branch: bzr merge lp:~cmiller/desktopcouch/segv-ya-rly
Reviewer Review Type Date Requested Status
Tim Cole (community) Approve
Guillermo Gonzalez Approve
Review via email: mp+22417@code.launchpad.net

Commit message

Since replication takes a long time (and we are not clever enough yet to replicate asynchronously), all replication is pushed into a subthread so that we don't block DBus server calls on getPort and such.

However, for some GUI libraries, GUI functions are not allowed to be outside the main execution thread. Violating that causes undefined behavior.

We need access to the keyring data in replication, and 'gnomekeyring' may try to display an alert to the user, using GUI functions. Doing so from inside the replication thread, outside the main thread, can cause SEGV crashes in deep and mysterious parts of Python and libraries it uses.

Now, add a wrapper for those functions that can call GUI functions. First test what environment we're in and if in a subthread, ask the twisted reactor to run the target function in the main execution thread and return the values down to the subthread.

To post a comment you must log in.
Revision history for this message
Guillermo Gonzalez (verterok) wrote :

looks good

review: Approve
Revision history for this message
Tim Cole (tcole) wrote :

Awesome. I'm glad we found and addressed the real problem.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'desktopcouch/replication_services/example.py'
--- desktopcouch/replication_services/example.py 2009-09-28 15:13:33 +0000
+++ desktopcouch/replication_services/example.py 2010-03-30 00:11:19 +0000
@@ -13,7 +13,9 @@
1313
14# Required14# Required
15def oauth_data():15def oauth_data():
16 """OAuth information needed to replicate to a server."""16 """OAuth information needed to replicate to a server. This may be
17 called from a subthread, so be sure not to violate any execution
18 idioms, like updating the GUI from a non-main thread."""
17 return dict(consumer_key="", consumer_secret="", oauth_token="",19 return dict(consumer_key="", consumer_secret="", oauth_token="",
18 oauth_token_secret="")20 oauth_token_secret="")
19 # or to symbolize failure21 # or to symbolize failure
2022
=== modified file 'desktopcouch/replication_services/ubuntuone.py'
--- desktopcouch/replication_services/ubuntuone.py 2010-03-10 22:27:28 +0000
+++ desktopcouch/replication_services/ubuntuone.py 2010-03-30 00:11:19 +0000
@@ -17,6 +17,15 @@
17oauth_consumer_key = "ubuntuone"17oauth_consumer_key = "ubuntuone"
18oauth_consumer_secret = "hammertime"18oauth_consumer_secret = "hammertime"
1919
20def in_main_thread(function, *args, **kwargs):
21 from twisted.python.threadable import isInIOThread
22 if isInIOThread(): # We may not be in main thread right now.
23 from twisted.internet.threads import blockingCallFromThread
24 from twisted.internet import reactor
25 return blockingCallFromThread(reactor, function, *args, **kwargs)
26 else: # If in main, just do it.
27 return function(*args, **kwargs)
28
20def is_active():29def is_active():
21 """Can we deliver information?"""30 """Can we deliver information?"""
22 return get_oauth_data() is not None31 return get_oauth_data() is not None
@@ -29,7 +38,7 @@
29 return oauth_data38 return oauth_data
3039
31 try:40 try:
32 matches = gnomekeyring.find_items_sync(41 matches = in_main_thread(gnomekeyring.find_items_sync,
33 gnomekeyring.ITEM_GENERIC_SECRET,42 gnomekeyring.ITEM_GENERIC_SECRET,
34 {'ubuntuone-realm': "https://ubuntuone.com",43 {'ubuntuone-realm': "https://ubuntuone.com",
35 'oauth-consumer-key': oauth_consumer_key})44 'oauth-consumer-key': oauth_consumer_key})
@@ -58,13 +67,13 @@
58def get_oauth_token(consumer):67def get_oauth_token(consumer):
59 """Get the token from the keyring"""68 """Get the token from the keyring"""
60 try:69 try:
61 items = gnomekeyring.find_items_sync(70 items = in_main_thread(gnomekeyring.find_items_sync,
62 gnomekeyring.ITEM_GENERIC_SECRET,71 gnomekeyring.ITEM_GENERIC_SECRET,
63 {'ubuntuone-realm': "https://one.ubuntu.com",72 {'ubuntuone-realm': "https://one.ubuntu.com",
64 'oauth-consumer-key': consumer.key})73 'oauth-consumer-key': consumer.key})
65 except gnomekeyring.NoMatchError:74 except gnomekeyring.NoMatchError:
66 logging.info("No o.u.c key. Maybe there's uo.c key?")75 logging.info("No o.u.c key. Maybe there's uo.c key?")
67 items = gnomekeyring.find_items_sync(76 items = in_main_thread(gnomekeyring.find_items_sync,
68 gnomekeyring.ITEM_GENERIC_SECRET,77 gnomekeyring.ITEM_GENERIC_SECRET,
69 {'ubuntuone-realm': "https://ubuntuone.com",78 {'ubuntuone-realm': "https://ubuntuone.com",
70 'oauth-consumer-key': consumer.key})79 'oauth-consumer-key': consumer.key})

Subscribers

People subscribed via source and target branches