aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2013-04-13 01:50:25 +0800
committerMatthew Barnes <mbarnes@redhat.com>2013-04-13 06:35:11 +0800
commitebef28545a2a74d675142afd6921f5e0e65b4b76 (patch)
treed715ea0b2dcb436a1ccd98b25457c54cc331d939
parent01207c3c8ed00e6de1d66901b257bf3ffee7d350 (diff)
downloadgsoc2013-evolution-ebef28545a2a74d675142afd6921f5e0e65b4b76.tar.gz
gsoc2013-evolution-ebef28545a2a74d675142afd6921f5e0e65b4b76.tar.zst
gsoc2013-evolution-ebef28545a2a74d675142afd6921f5e0e65b4b76.zip
ECalModel: Make the ClientData queue thread-safe.
-rw-r--r--calendar/gui/e-cal-model.c180
1 files changed, 124 insertions, 56 deletions
diff --git a/calendar/gui/e-cal-model.c b/calendar/gui/e-cal-model.c
index db641278d6..1ed0720bec 100644
--- a/calendar/gui/e-cal-model.c
+++ b/calendar/gui/e-cal-model.c
@@ -70,6 +70,7 @@ struct _ECalModelPrivate {
/* Queue of ClientData structs */
GQueue clients;
+ GMutex clients_lock;
/* The default client in the list */
ECalClient *default_client;
@@ -282,25 +283,90 @@ client_data_unref (ClientData *client_data)
}
}
-static ClientData *
-cal_model_ref_client_data (ECalModel *model,
- ECalClient *client)
+static GList *
+cal_model_clients_list (ECalModel *model)
{
- GList *head, *link;
+ GList *list, *head;
+
+ g_mutex_lock (&model->priv->clients_lock);
head = g_queue_peek_head_link (&model->priv->clients);
+ list = g_list_copy_deep (head, (GCopyFunc) client_data_ref, NULL);
- for (link = head; link != NULL; link = g_list_next (link)) {
- ClientData *client_data;
+ g_mutex_unlock (&model->priv->clients_lock);
+
+ return list;
+}
+
+static ClientData *
+cal_model_clients_lookup (ECalModel *model,
+ ECalClient *client)
+{
+ ClientData *client_data = NULL;
+ GList *list, *link;
+
+ list = cal_model_clients_list (model);
- client_data = (ClientData *) link->data;
- g_return_val_if_fail (client_data != NULL, NULL);
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ClientData *candidate = link->data;
- if (client_data->client == client)
- return client_data_ref (client_data);
+ if (candidate->client == client) {
+ client_data = client_data_ref (candidate);
+ break;
+ }
}
- return NULL;
+ g_list_free_full (list, (GDestroyNotify) client_data_unref);
+
+ return client_data;
+}
+
+static ClientData *
+cal_model_clients_peek (ECalModel *model)
+{
+ ClientData *client_data;
+
+ g_mutex_lock (&model->priv->clients_lock);
+
+ client_data = g_queue_peek_head (&model->priv->clients);
+ if (client_data != NULL)
+ client_data_ref (client_data);
+
+ g_mutex_unlock (&model->priv->clients_lock);
+
+ return client_data;
+}
+
+static ClientData *
+cal_model_clients_pop (ECalModel *model)
+{
+ ClientData *client_data;
+
+ g_mutex_lock (&model->priv->clients_lock);
+
+ client_data = g_queue_pop_head (&model->priv->clients);
+
+ g_mutex_unlock (&model->priv->clients_lock);
+
+ return client_data;
+}
+
+static gboolean
+cal_model_clients_remove (ECalModel *model,
+ ClientData *client_data)
+{
+ gboolean removed = FALSE;
+
+ g_mutex_lock (&model->priv->clients_lock);
+
+ if (g_queue_remove (&model->priv->clients, client_data)) {
+ client_data_unref (client_data);
+ removed = TRUE;
+ }
+
+ g_mutex_unlock (&model->priv->clients_lock);
+
+ return removed;
}
static void
@@ -659,6 +725,8 @@ cal_model_finalize (GObject *object)
priv = E_CAL_MODEL_GET_PRIVATE (object);
+ g_mutex_clear (&priv->clients_lock);
+
g_free (priv->search_sexp);
g_free (priv->full_sexp);
@@ -1035,6 +1103,8 @@ e_cal_model_init (ECalModel *model)
{
model->priv = E_CAL_MODEL_GET_PRIVATE (model);
+ g_mutex_init (&model->priv->clients_lock);
+
/* match none by default */
model->priv->start = -1;
model->priv->end = -1;
@@ -2491,23 +2561,22 @@ e_cal_model_set_work_day_start_minute (ECalModel *model,
ECalClient *
e_cal_model_get_default_client (ECalModel *model)
{
- ECalModelPrivate *priv;
ClientData *client_data;
+ ECalClient *default_client = NULL;
g_return_val_if_fail (model != NULL, NULL);
g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
- priv = model->priv;
-
- /* FIXME Should we force the client to be open? */
-
- /* we always return a valid ECal, since we rely on it in many places */
- if (priv->default_client)
- return priv->default_client;
+ if (model->priv->default_client != NULL)
+ return model->priv->default_client;
- client_data = g_queue_peek_head (&priv->clients);
+ client_data = cal_model_clients_peek (model);
+ if (client_data != NULL) {
+ default_client = client_data->client;
+ client_data_unref (client_data);
+ }
- return client_data ? client_data->client : NULL;
+ return default_client;
}
void
@@ -2529,7 +2598,7 @@ e_cal_model_set_default_client (ECalModel *model,
if (priv->default_client == NULL) {
ClientData *client_data;
- client_data = cal_model_ref_client_data (
+ client_data = cal_model_clients_lookup (
model, priv->default_client);
if (client_data != NULL) {
if (!client_data->do_query)
@@ -2555,20 +2624,17 @@ GList *
e_cal_model_get_client_list (ECalModel *model)
{
GQueue results = G_QUEUE_INIT;
- GList *head, *link;
+ GList *list, *link;
ECalClient *default_client;
g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
default_client = model->priv->default_client;
- head = g_queue_peek_head_link (&model->priv->clients);
-
- for (link = head; link != NULL; link = g_list_next (link)) {
- ClientData *client_data;
+ list = cal_model_clients_list (model);
- client_data = (ClientData *) link->data;
- g_return_val_if_fail (client_data != NULL, NULL);
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ClientData *client_data = link->data;
/* Exclude the default client if we're not querying it. */
if (client_data->client == default_client) {
@@ -2579,6 +2645,8 @@ e_cal_model_get_client_list (ECalModel *model)
g_queue_push_tail (&results, client_data->client);
}
+ g_list_free_full (list, (GDestroyNotify) client_data_unref);
+
return g_queue_peek_head_link (&results);
}
@@ -2591,29 +2659,31 @@ ECalClient *
e_cal_model_get_client_for_source (ECalModel *model,
ESource *source)
{
- GList *head, *link;
+ ECalClient *match = NULL;
+ GList *list, *link;
g_return_val_if_fail (E_IS_CAL_MODEL (model), NULL);
g_return_val_if_fail (E_IS_SOURCE (source), NULL);
- head = g_queue_peek_head_link (&model->priv->clients);
+ list = cal_model_clients_list (model);
- for (link = head; link != NULL; link = g_list_next (link)) {
+ for (link = list; link != NULL; link = g_list_next (link)) {
ClientData *client_data = link->data;
ESource *client_source;
EClient *client;
- client_data = (ClientData *) link->data;
- g_return_val_if_fail (client_data != NULL, NULL);
-
client = E_CLIENT (client_data->client);
client_source = e_client_get_source (client);
- if (e_source_equal (source, client_source))
- return client_data->client;
+ if (e_source_equal (source, client_source)) {
+ match = client_data->client;
+ break;
+ }
}
- return NULL;
+ g_list_free_full (list, (GDestroyNotify) client_data_unref);
+
+ return match;
}
static ECalModelComponent *
@@ -2862,7 +2932,7 @@ process_added (ECalClientView *view,
if (e_cal_util_component_has_recurrences (l->data) && (priv->flags & E_CAL_MODEL_FLAGS_EXPAND_RECURRENCES)) {
ClientData *client_data;
- client_data = cal_model_ref_client_data (model, client);
+ client_data = cal_model_clients_lookup (model, client);
if (client_data != NULL) {
RecurrenceExpansionData *rdata = g_new0 (RecurrenceExpansionData, 1);
@@ -3352,7 +3422,7 @@ add_new_client (ECalModel *model,
gboolean update_view = TRUE;
/* Look to see if we already have this client */
- client_data = cal_model_ref_client_data (model, client);
+ client_data = cal_model_clients_lookup (model, client);
if (client_data != NULL) {
if (client_data->do_query)
update_view = FALSE;
@@ -3362,9 +3432,11 @@ add_new_client (ECalModel *model,
} else {
client_data = client_data_new (model, client, do_query);
+ g_mutex_lock (&model->priv->clients_lock);
g_queue_push_tail (
&model->priv->clients,
client_data_ref (client_data));
+ g_mutex_unlock (&model->priv->clients_lock);
}
if (update_view)
@@ -3423,7 +3495,6 @@ remove_client (ECalModel *model,
ClientData *client_data)
{
/* FIXME We might not want to disconnect the open signal for the default client */
- g_signal_handlers_disconnect_matched (client_data->client, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, model);
if (client_data->view)
g_signal_handlers_disconnect_matched (client_data->view, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, model);
@@ -3440,9 +3511,7 @@ remove_client (ECalModel *model,
if (model->priv->default_client == client_data->client)
model->priv->default_client = NULL;
- /* Remove the client from the queue. */
- if (g_queue_remove (&model->priv->clients, client_data))
- client_data_unref (client_data);
+ cal_model_clients_remove (model, client_data);
}
/**
@@ -3457,7 +3526,7 @@ e_cal_model_remove_client (ECalModel *model,
g_return_if_fail (E_IS_CAL_MODEL (model));
g_return_if_fail (E_IS_CAL_CLIENT (client));
- client_data = cal_model_ref_client_data (model, client);
+ client_data = cal_model_clients_lookup (model, client);
if (client_data != NULL) {
remove_client (model, client_data);
client_data_unref (client_data);
@@ -3470,13 +3539,13 @@ e_cal_model_remove_client (ECalModel *model,
void
e_cal_model_remove_all_clients (ECalModel *model)
{
- g_return_if_fail (E_IS_CAL_MODEL (model));
+ ClientData *client_data;
- while (!g_queue_is_empty (&model->priv->clients)) {
- ClientData *client_data;
+ g_return_if_fail (E_IS_CAL_MODEL (model));
- client_data = g_queue_pop_head (&model->priv->clients);
+ while ((client_data = cal_model_clients_pop (model)) != NULL) {
remove_client (model, client_data);
+ client_data_unref (client_data);
}
}
@@ -3547,7 +3616,7 @@ static void
redo_queries (ECalModel *model)
{
ECalModelPrivate *priv;
- GList *head, *link;
+ GList *list, *link;
struct cc_data data;
priv = model->priv;
@@ -3603,16 +3672,15 @@ redo_queries (ECalModel *model)
/* update the view for all clients */
- head = g_queue_peek_head_link (&priv->clients);
+ list = cal_model_clients_list (model);
- for (link = head; link != NULL; link = g_list_next (link)) {
- ClientData *client_data;
-
- client_data = (ClientData *) link->data;
- g_return_if_fail (client_data != NULL);
+ for (link = list; link != NULL; link = g_list_next (link)) {
+ ClientData *client_data = link->data;
update_e_cal_view_for_client (model, client_data);
}
+
+ g_list_free_full (list, (GDestroyNotify) client_data_unref);
}
void