From 6de256c2a2b23f30d35e4a2213ad5839bf141d06 Mon Sep 17 00:00:00 2001 From: Not Zed Date: Sun, 24 Dec 2000 00:46:20 +0000 Subject: Lock the command channel while searching. (imap_body_contains): If 2000-12-24 Not Zed * providers/imap/camel-imap-search.c (imap_body_contains): Lock the command channel while searching. (imap_body_contains): If performing a whole uid search, then add references to our own summary items, dont look it up in the folder. This way they can't vanish unexpectedly. * providers/imap/camel-imap-folder.h (CamelImapFolder): Added a private field. * providers/imap/camel-imap-private.h: Added lock for imap searches. * Merge from camel-mt-branch. * providers/imap/camel-imap-folder.c (imap_update_summary): Merge fix, use the folder->summary. (imap_get_message_flags, imap_set_message_flags, imap_get_message_user_flag, imap_set_message_user_flag): Removed again. (camel_imap_folder_init): Setup private data/lock. (imap_finalize): Free private data/search lock. (imap_search_free): Lock the search_lock. (imap_search_by_expression): Lock the search lock when using the search object. Also copy/ref hte summary, rather than getting it directly. (imap_refresh_info): Free any info lookups. Use folder->summary not imap_folder->summary. And lock around commands. svn path=/trunk/; revision=7150 --- camel/camel-folder-summary.c | 278 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 232 insertions(+), 46 deletions(-) (limited to 'camel/camel-folder-summary.c') 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 + +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 (imessages->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;imessages->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); @@ -748,6 +855,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;imessages->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