summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <philip.withnall@collabora.co.uk>2015-06-16 17:58:15 +0100
committerPhilip Withnall <philip.withnall@collabora.co.uk>2015-06-16 17:58:15 +0100
commitb5070cec811e68f5b8f8029119a059d3c3eb2ce9 (patch)
tree51950fbb8d1b3a54db6c4dd6053c4f3bf2e4c5ba
parentcce549de95c9faa621b39960ca741cb397cfe7c5 (diff)
downloadfolks-b5070cec811e68f5b8f8029119a059d3c3eb2ce9.tar.gz
eds: Eliminate another race condition when committing contacts
We can’t connect to the objects_modified signal, as we can’t guarantee whether the handler installed in _commit_modified_property() or the _contacts_changed_cb() handler will be called first. Since they both enqueue to the idle queue in order, the callback from _commit_modified_property() will still operate on an outdated Edsf.Persona if it is called first. This race condition can only happen when _commit_modified_property() is called with a null property_name, which happens for custom properties and extended fields. Fix this by listening for changes to the Edsf.Persona.contact property instead of objects_modified. This is always guaranteed to change when a Persona is updated (because it represents the current vCard), and fixes the ordering problem, because the Persona’s properties will have been updated by the time the contact property is notified (see Edsf.Persona._update() for details).
-rw-r--r--backends/eds/lib/edsf-persona-store.vala61
1 files changed, 9 insertions, 52 deletions
diff --git a/backends/eds/lib/edsf-persona-store.vala b/backends/eds/lib/edsf-persona-store.vala
index aa3f05f5..83ffbb5a 100644
--- a/backends/eds/lib/edsf-persona-store.vala
+++ b/backends/eds/lib/edsf-persona-store.vala
@@ -1362,57 +1362,18 @@ public class Edsf.PersonaStore : Folks.PersonaStore
{
var received_notification = false;
var has_yielded = false;
+ var signal_name = property_name ?? "contact";
- if (property_name != null)
+ signal_id = persona.notify[signal_name].connect ((obj, pspec) =>
{
- signal_id = persona.notify[property_name].connect ((obj, pspec) =>
- {
- /* Success! Return to _commit_modified_property(). */
- received_notification = true;
+ /* Success! Return to _commit_modified_property(). */
+ received_notification = true;
- if (has_yielded == true)
- {
- this._commit_modified_property.callback ();
- }
- });
- }
- else
- {
- signal_id = ((!) this._ebookview).objects_modified.connect (
- (_contacts) =>
+ if (has_yielded == true)
{
- unowned GLib.List<E.Contact> contacts =
- (GLib.List<E.Contact>) _contacts;
-
- /* Ignore other personas. */
- foreach (E.Contact c in contacts)
- {
- var iid = Edsf.Persona.build_iid_from_contact (this.id, c);
- if (iid != persona.iid)
- {
- continue;
- }
-
- /* Success! Return to _commit_modified_property(), but do
- * it via the idle queue so that the notification is
- * queued after the actual contact updates in
- * _contacts_changed_idle(). */
- this._idle_queue (() =>
- {
- received_notification = true;
-
- if (has_yielded == true)
- {
- this._commit_modified_property.callback ();
- }
-
- return false;
- });
-
- return;
- }
- });
- }
+ this._commit_modified_property.callback ();
+ }
+ });
/* Commit the modification. _addressbook is asserted as being non-null
* above. */
@@ -1466,14 +1427,10 @@ public class Edsf.PersonaStore : Folks.PersonaStore
finally
{
/* Remove the callbacks. */
- if (signal_id != 0 && property_name != null)
+ if (signal_id != 0)
{
persona.disconnect (signal_id);
}
- else if (signal_id != 0)
- {
- ((!) this._ebookview).disconnect (signal_id);
- }
if (timeout_id != 0)
{