aboutsummaryrefslogtreecommitdiffstats
path: root/camel/camel-folder-summary.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/camel-folder-summary.c')
-rw-r--r--camel/camel-folder-summary.c278
1 files changed, 232 insertions, 46 deletions
diff --git a/camel/camel-folder-summary.c b/camel/camel-folder-summary.c
index 6ee83348a4..b6d8fc910e 100644
--- a/camel/camel-folder-summary.c
+++ b/camel/camel-folder-summary.c
@@ -43,6 +43,21 @@
#include "e-util/md5-utils.h"
#include "e-util/e-memory.h"
+#include "camel-private.h"
+
+#ifdef ENABLE_THREADS
+#include <pthread.h>
+
+static pthread_mutex_t info_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* this lock is ONLY for the standalone messageinfo stuff */
+#define GLOBAL_INFO_LOCK(i) pthread_mutex_lock(&info_lock)
+#define GLOBAL_INFO_UNLOCK(i) pthread_mutex_unlock(&info_lock)
+#else
+#define GLOBAL_INFO_LOCK(i)
+#define GLOBAL_INFO_UNLOCK(i)
+#endif
+
/* this should probably be conditional on it existing */
#define USE_BSEARCH
@@ -55,17 +70,6 @@ extern int strdup_count, malloc_count, free_count;
#define CAMEL_FOLDER_SUMMARY_VERSION (11)
-struct _CamelFolderSummaryPrivate {
- GHashTable *filter_charset; /* CamelMimeFilterCharset's indexed by source charset */
-
- CamelMimeFilterIndex *filter_index;
- CamelMimeFilterBasic *filter_64;
- CamelMimeFilterBasic *filter_qp;
- CamelMimeFilterSave *filter_save;
-
- ibex *index;
-};
-
#define _PRIVATE(o) (((CamelFolderSummary *)(o))->priv)
/* trivial lists, just because ... */
@@ -155,6 +159,14 @@ camel_folder_summary_init (CamelFolderSummary *s)
s->messages = g_ptr_array_new();
s->messages_uid = g_hash_table_new(g_str_hash, g_str_equal);
+
+#ifdef ENABLE_THREADS
+ p->summary_lock = g_mutex_new();
+ p->io_lock = g_mutex_new();
+ p->filter_lock = g_mutex_new();
+ p->alloc_lock = g_mutex_new();
+ p->ref_lock = g_mutex_new();
+#endif
}
static void free_o_name(void *key, void *value, void *data)
@@ -194,6 +206,14 @@ camel_folder_summary_finalize (CamelObject *obj)
if (p->filter_save)
camel_object_unref ((CamelObject *)p->filter_save);
+#ifdef ENABLE_THREADS
+ g_mutex_free(p->summary_lock);
+ g_mutex_free(p->io_lock);
+ g_mutex_free(p->filter_lock);
+ g_mutex_free(p->alloc_lock);
+ g_mutex_free(p->ref_lock);
+#endif
+
g_free(p);
}
@@ -225,8 +245,7 @@ camel_folder_summary_get_type (void)
CamelFolderSummary *
camel_folder_summary_new (void)
{
- CamelFolderSummary *new = CAMEL_FOLDER_SUMMARY ( camel_object_new (camel_folder_summary_get_type ()));
- return new;
+ CamelFolderSummary *new = CAMEL_FOLDER_SUMMARY ( camel_object_new (camel_folder_summary_get_type ())); return new;
}
@@ -239,8 +258,12 @@ camel_folder_summary_new (void)
**/
void camel_folder_summary_set_filename(CamelFolderSummary *s, const char *name)
{
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+
g_free(s->summary_path);
s->summary_path = g_strdup(name);
+
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
}
/**
@@ -294,16 +317,33 @@ camel_folder_summary_count(CamelFolderSummary *s)
* @i:
*
* Retrieve a summary item by index number.
+ *
+ * A referenced to the summary item is returned, which may be
+ * ref'd or free'd as appropriate.
*
* Return value: The summary item, or NULL if the index @i is out
* of range.
+ * It must be freed using camel_folder_summary_info_free().
**/
CamelMessageInfo *
camel_folder_summary_index(CamelFolderSummary *s, int i)
{
+ CamelMessageInfo *info = NULL;
+
+ CAMEL_SUMMARY_LOCK(s, ref_lock);
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+
if (i<s->messages->len)
- return g_ptr_array_index(s->messages, i);
- return NULL;
+ info = g_ptr_array_index(s->messages, i);
+
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+ if (info)
+ info->refcount++;
+
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+
+ return info;
}
/**
@@ -312,14 +352,32 @@ camel_folder_summary_index(CamelFolderSummary *s, int i)
* @uid:
*
* Retrieve a summary item by uid.
+ *
+ * A referenced to the summary item is returned, which may be
+ * ref'd or free'd as appropriate.
*
* Return value: The summary item, or NULL if the uid @uid
* is not available.
+ * It must be freed using camel_folder_summary_info_free().
**/
CamelMessageInfo *
camel_folder_summary_uid(CamelFolderSummary *s, const char *uid)
{
- return g_hash_table_lookup(s->messages_uid, uid);
+ CamelMessageInfo *info;
+
+ CAMEL_SUMMARY_LOCK(s, ref_lock);
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+
+ info = g_hash_table_lookup(s->messages_uid, uid);
+
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+ if (info)
+ info->refcount++;
+
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+
+ return info;
}
/**
@@ -333,7 +391,14 @@ camel_folder_summary_uid(CamelFolderSummary *s, const char *uid)
**/
guint32 camel_folder_summary_next_uid(CamelFolderSummary *s)
{
- guint32 uid = s->nextuid++;
+ guint32 uid;
+
+
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+
+ uid = s->nextuid++;
+
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
/* FIXME: sync this to disk */
/* summary_header_save(s);*/
@@ -352,7 +417,11 @@ guint32 camel_folder_summary_next_uid(CamelFolderSummary *s)
void camel_folder_summary_set_uid(CamelFolderSummary *s, guint32 uid)
{
/* TODO: sync to disk? */
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+
s->nextuid = MAX(s->nextuid, uid);
+
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
}
/**
@@ -406,8 +475,10 @@ camel_folder_summary_load(CamelFolderSummary *s)
return -1;
}
+ CAMEL_SUMMARY_LOCK(s, io_lock);
if ( ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_load(s, in) == -1) {
fclose(in);
+ CAMEL_SUMMARY_UNLOCK(s, io_lock);
return -1;
}
@@ -422,6 +493,8 @@ camel_folder_summary_load(CamelFolderSummary *s)
camel_folder_summary_add(s, mi);
}
+
+ CAMEL_SUMMARY_UNLOCK(s, io_lock);
if (fclose(in) == -1)
return -1;
@@ -481,22 +554,29 @@ camel_folder_summary_save(CamelFolderSummary *s)
io(printf("saving header\n"));
+ CAMEL_SUMMARY_LOCK(s, io_lock);
+
if ( ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_save(s, out) == -1) {
fclose(out);
+ CAMEL_SUMMARY_UNLOCK(s, io_lock);
return -1;
}
/* now write out each message ... */
/* FIXME: check returns */
- count = camel_folder_summary_count(s);
+
+ count = s->messages->len;
for (i=0;i<count;i++) {
- mi = camel_folder_summary_index(s, i);
+ mi = s->messages->pdata[i];
((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_save(s, out, mi);
if (s->build_content) {
perform_content_info_save(s, out, mi->content);
}
}
+
+ CAMEL_SUMMARY_UNLOCK(s, io_lock);
+
if (fclose(out) == -1)
return -1;
@@ -515,12 +595,18 @@ summary_assign_uid(CamelFolderSummary *s, CamelMessageInfo *info)
uid = camel_message_info_uid(info);
}
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+
while (g_hash_table_lookup(s->messages_uid, uid)) {
g_warning("Trying to insert message with clashing uid (%s). new uid re-assigned", camel_message_info_uid(info));
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
camel_message_info_set_uid(info, camel_folder_summary_next_uid_string(s));
uid = camel_message_info_uid(info);
info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
}
+
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
}
/**
@@ -542,6 +628,8 @@ void camel_folder_summary_add(CamelFolderSummary *s, CamelMessageInfo *info)
summary_assign_uid(s, info);
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+
#ifdef DOESTRV
/* this is vitally important, and also if this is ever modified, then
the hash table needs to be resynced */
@@ -551,6 +639,8 @@ void camel_folder_summary_add(CamelFolderSummary *s, CamelMessageInfo *info)
g_ptr_array_add(s->messages, info);
g_hash_table_insert(s->messages_uid, (char *)camel_message_info_uid(info), info);
s->flags |= CAMEL_SUMMARY_DIRTY;
+
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
}
/**
@@ -668,6 +758,8 @@ CamelMessageInfo *camel_folder_summary_info_new_from_parser(CamelFolderSummary *
* know if we are going to store this in the summary, but no matter */
summary_assign_uid(s, info);
+ CAMEL_SUMMARY_LOCK(s, filter_lock);
+
if (p->index) {
if (p->filter_index == NULL)
p->filter_index = camel_mime_filter_index_new_ibex(p->index);
@@ -677,6 +769,9 @@ CamelMessageInfo *camel_folder_summary_info_new_from_parser(CamelFolderSummary *
/* always scan the content info, even if we dont save it */
info->content = summary_build_content_info(s, info, mp);
+
+ CAMEL_SUMMARY_UNLOCK(s, filter_lock);
+
info->size = camel_mime_parser_tell(mp) - start;
}
return info;
@@ -731,7 +826,7 @@ perform_content_info_free(CamelFolderSummary *s, CamelMessageContentInfo *ci)
* @s:
* @mi:
*
- * Free the message info @mi, and all associated memory.
+ * Unref and potentially free the message info @mi, and all associated memory.
**/
void camel_folder_summary_info_free(CamelFolderSummary *s, CamelMessageInfo *mi)
{
@@ -740,6 +835,18 @@ void camel_folder_summary_info_free(CamelFolderSummary *s, CamelMessageInfo *mi)
g_assert(mi);
g_assert(s);
+ CAMEL_SUMMARY_LOCK(s, ref_lock);
+
+ g_assert(mi->refcount >= 1);
+
+ mi->refcount--;
+ if (mi->refcount > 0) {
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+ return;
+ }
+
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+
ci = mi->content;
((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_free(s, mi);
@@ -749,6 +856,24 @@ void camel_folder_summary_info_free(CamelFolderSummary *s, CamelMessageInfo *mi)
}
/**
+ * camel_folder_summary_info_ref:
+ * @s:
+ * @mi:
+ *
+ * Add an extra reference to @mi.
+ **/
+void camel_folder_summary_info_ref(CamelFolderSummary *s, CamelMessageInfo *mi)
+{
+ g_assert(mi);
+ g_assert(s);
+
+ CAMEL_SUMMARY_LOCK(s, ref_lock);
+ g_assert(mi->refcount >= 1);
+ mi->refcount++;
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+}
+
+/**
* camel_folder_summary_touch:
* @s:
*
@@ -757,7 +882,9 @@ void camel_folder_summary_info_free(CamelFolderSummary *s, CamelMessageInfo *mi)
void
camel_folder_summary_touch(CamelFolderSummary *s)
{
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
s->flags |= CAMEL_SUMMARY_DIRTY;
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
}
/**
@@ -771,16 +898,20 @@ camel_folder_summary_clear(CamelFolderSummary *s)
{
int i;
- if (camel_folder_summary_count(s) == 0)
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+ if (camel_folder_summary_count(s) == 0) {
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
return;
+ }
- for (i=0;i<camel_folder_summary_count(s);i++)
- camel_folder_summary_info_free(s, camel_folder_summary_index(s, i));
+ for (i=0;i<s->messages->len;i++)
+ camel_folder_summary_info_free(s, s->messages->pdata[i]);
g_ptr_array_set_size(s->messages, 0);
g_hash_table_destroy(s->messages_uid);
s->messages_uid = g_hash_table_new(g_str_hash, g_str_equal);
s->flags |= CAMEL_SUMMARY_DIRTY;
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
}
/**
@@ -792,10 +923,13 @@ camel_folder_summary_clear(CamelFolderSummary *s)
**/
void camel_folder_summary_remove(CamelFolderSummary *s, CamelMessageInfo *info)
{
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
g_hash_table_remove(s->messages_uid, camel_message_info_uid(info));
g_ptr_array_remove(s->messages, info);
- camel_folder_summary_info_free(s, info);
s->flags |= CAMEL_SUMMARY_DIRTY;
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+ camel_folder_summary_info_free(s, info);
}
/**
@@ -810,10 +944,19 @@ void camel_folder_summary_remove_uid(CamelFolderSummary *s, const char *uid)
CamelMessageInfo *oldinfo;
char *olduid;
+ CAMEL_SUMMARY_LOCK(s, ref_lock);
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
if (g_hash_table_lookup_extended(s->messages_uid, uid, (void *)&olduid, (void *)&oldinfo)) {
+ /* make sure it doesn't vanish while we're removing it */
+ oldinfo->refcount++;
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
camel_folder_summary_remove(s, oldinfo);
- g_free(olduid);
- }
+ camel_folder_summary_info_free(s, oldinfo);
+ } else {
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+ }
}
/**
@@ -825,11 +968,20 @@ void camel_folder_summary_remove_uid(CamelFolderSummary *s, const char *uid)
**/
void camel_folder_summary_remove_index(CamelFolderSummary *s, int index)
{
- CamelMessageInfo *oldinfo;
-
- oldinfo = camel_folder_summary_index (s, index);
- if (oldinfo)
- camel_folder_summary_remove(s, oldinfo);
+ CAMEL_SUMMARY_LOCK(s, ref_lock);
+ CAMEL_SUMMARY_LOCK(s, summary_lock);
+ if (index < s->messages->len) {
+ CamelMessageInfo *info = s->messages->pdata[index];
+ /* make sure it doesn't vanish while we're not looking */
+ info->refcount++;
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+ camel_folder_summary_remove(s, info);
+ camel_folder_summary_info_free(s, info);
+ } else {
+ CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+ CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+ }
}
/**
@@ -1430,13 +1582,17 @@ camel_folder_summary_info_new(CamelFolderSummary *s)
{
CamelMessageInfo *mi;
+ CAMEL_SUMMARY_LOCK(s, alloc_lock);
if (s->message_info_chunks == NULL)
s->message_info_chunks = e_memchunk_new(32, s->message_info_size);
mi = e_memchunk_alloc(s->message_info_chunks);
+ CAMEL_SUMMARY_UNLOCK(s, alloc_lock);
+
memset(mi, 0, s->message_info_size);
#ifdef DOESTRV
mi->strings = e_strv_new(s->message_info_strings);
#endif
+ mi->refcount = 1;
return mi;
}
@@ -1445,9 +1601,12 @@ content_info_alloc(CamelFolderSummary *s)
{
CamelMessageContentInfo *ci;
+ CAMEL_SUMMARY_LOCK(s, alloc_lock);
if (s->content_info_chunks == NULL)
s->content_info_chunks = e_memchunk_new(32, s->content_info_size);
ci = e_memchunk_alloc(s->content_info_chunks);
+ CAMEL_SUMMARY_UNLOCK(s, alloc_lock);
+
memset(ci, 0, s->content_info_size);
return ci;
}
@@ -1769,6 +1928,7 @@ next_uid_string(CamelFolderSummary *s)
and any indexing and what not is performed
*/
+/* must have filter_lock before calling this function */
static CamelMessageContentInfo *
summary_build_content_info(CamelFolderSummary *s, CamelMessageInfo *msginfo, CamelMimeParser *mp)
{
@@ -1892,6 +2052,7 @@ summary_build_content_info(CamelFolderSummary *s, CamelMessageInfo *msginfo, Cam
}
/* build the content-info, from a message */
+/* this needs no lock, as we copy all data, and ibex is threadsafe */
static CamelMessageContentInfo *
summary_build_content_info_message(CamelFolderSummary *s, CamelMessageInfo *msginfo, CamelMimePart *object)
{
@@ -2212,14 +2373,29 @@ camel_message_info_new (void)
{
CamelMessageInfo *info;
- info = g_new0 (CamelMessageInfo, 1);
+ info = g_malloc0(sizeof(*info));
#ifdef DOESTRV
info->strings = e_strv_new (CAMEL_MESSAGE_INFO_LAST);
#endif
-
+ info->refcount = 1;
+
return info;
}
+/**
+ * camel_message_info_ref:
+ * @info:
+ *
+ * Reference an info.
+ *
+ * NOTE: This interface is not MT-SAFE, like the others.
+ **/
+void camel_message_info_ref(CamelMessageInfo *info)
+{
+ GLOBAL_INFO_LOCK(info);
+ info->refcount++;
+ GLOBAL_INFO_UNLOCK(info);
+}
/**
* camel_message_info_new_from_header:
@@ -2238,20 +2414,13 @@ camel_message_info_new_from_header (struct _header_raw *header)
to = camel_folder_summary_format_address (header, "to");
cc = camel_folder_summary_format_address (header, "cc");
- info = g_new0 (CamelMessageInfo, 1);
-#ifdef DOESTRV
- info->strings = e_strv_new (CAMEL_MESSAGE_INFO_LAST);
+ info = camel_message_info_new();
+
camel_message_info_set_subject (info, subject);
camel_message_info_set_from (info, from);
camel_message_info_set_to (info, to);
camel_message_info_set_cc (info, cc);
-#else
- info->subject = subject;
- info->from = from;
- info->to = to;
- info->cc = cc;
-#endif
-
+
return info;
}
@@ -2276,6 +2445,7 @@ camel_message_info_dup_to(const CamelMessageInfo *from, CamelMessageInfo *to)
to->size = from->size;
to->date_sent = from->date_sent;
to->date_received = from->date_received;
+ to->refcount = 1;
/* Copy strings */
#ifdef DOESTRV
@@ -2325,15 +2495,27 @@ camel_message_info_dup_to(const CamelMessageInfo *from, CamelMessageInfo *to)
* camel_message_info_free:
* @mi: the message info
*
- * Frees a CamelMessageInfo and its contents.
+ * Unref's and potentially frees a CamelMessageInfo and its contents.
*
* Can only be used to free CamelMessageInfo's created with
* camel_message_info_dup_to.
*
+ * NOTE: This interface is not MT-SAFE, like the others.
+ *
**/
void
camel_message_info_free(CamelMessageInfo *mi)
{
+ g_return_if_fail(mi != NULL);
+
+ GLOBAL_INFO_LOCK(info);
+ mi->refcount--;
+ if (mi->refcount > 0) {
+ GLOBAL_INFO_UNLOCK(info);
+ return;
+ }
+ GLOBAL_INFO_UNLOCK(info);
+
#ifdef DOESTRV
e_strv_destroy(mi->strings);
#else
@@ -2468,7 +2650,9 @@ int main(int argc, char **argv)
printf("Printing summary\n");
for (i=0;i<camel_folder_summary_count(s);i++) {
- message_info_dump(camel_folder_summary_index(s, i));
+ CamelMessageInfo *info = camel_folder_summary_index(s, i);
+ message_info_dump(info);
+ camel_folder_summary_info_free(info);
}
printf("Saivng summary\n");
@@ -2486,7 +2670,9 @@ int main(int argc, char **argv)
printf("Printing summary\n");
for (i=0;i<camel_folder_summary_count(n);i++) {
- message_info_dump(camel_folder_summary_index(n, i));
+ CamelMessageInfo *info = camel_folder_summary_index(s, i);
+ message_info_dump(info);
+ camel_folder_summary_info_free(info);
}
camel_object_unref(n);
}