From 60e5a01dfd445b941c1c612a27a09ac929614aea Mon Sep 17 00:00:00 2001 From: Chris Shoemaker Date: Sat, 2 Dec 2006 22:13:13 +0000 Subject: [PATCH] Fix bug #353450 - Crash on quit during save. Add a lock to the QofSession object, and use it in qof_session_save() to protect against re-entrance. The lock always starts at 1 and is 0 while inside qof_session_save(). If another call is made to qof_session_save() while one is in progress, the lock will momentarily drop below 0 before returning to zero. Note: The per-session nature of the lock would make it appear that we support concurrent saving of different sessions. In fact, we do not, because the file backend blocks the main process until the forked gzip process is finished, and it only knows how to keep track of one child pid at a time. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@15168 57a11ea4-9604-0410-9ed3-97b8803252fd --- lib/libqof/qof/qofsession-p.h | 1 + lib/libqof/qof/qofsession.c | 24 ++++++++++++++++++------ lib/libqof/qof/qofsession.h | 1 + src/gnome-utils/gnc-file.c | 3 ++- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/lib/libqof/qof/qofsession-p.h b/lib/libqof/qof/qofsession-p.h index 3ba3cb6080..1b22eebcf4 100644 --- a/lib/libqof/qof/qofsession-p.h +++ b/lib/libqof/qof/qofsession-p.h @@ -63,6 +63,7 @@ struct _QofSession /* Pointer to the backend that is actually used to move data * between the persistant store and the local engine. */ QofBackend *backend; + gint lock; }; diff --git a/lib/libqof/qof/qofsession.c b/lib/libqof/qof/qofsession.c index dbc46691af..d4bb1d14f8 100644 --- a/lib/libqof/qof/qofsession.c +++ b/lib/libqof/qof/qofsession.c @@ -197,6 +197,7 @@ qof_session_init (QofSession *session) session->books = g_list_append (NULL, qof_book_new ()); session->book_id = NULL; session->backend = NULL; + session->lock = 1; qof_session_clear_error (session); } @@ -1193,8 +1194,10 @@ qof_session_save (QofSession *session, int err; gint num; char *msg, *book_id; - + if (!session) return; + if (!g_atomic_int_dec_and_test(&session->lock)) + goto leave; ENTER ("sess=%p book_id=%s", session, session->book_id ? session->book_id : "(null)"); /* Partial book handling. */ @@ -1260,7 +1263,7 @@ qof_session_save (QofSession *session, session->book_id = NULL; qof_session_push_error (session, err, msg); LEAVE("changed backend error %d", err); - return; + goto leave; } if (msg != NULL) { @@ -1280,11 +1283,11 @@ qof_session_save (QofSession *session, p = p->next; } } - if(!session->backend) + if(!session->backend) { msg = g_strdup_printf("failed to load backend"); qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg); - return; + goto leave; } } /* If there is a backend, and the backend is reachable @@ -1308,7 +1311,8 @@ qof_session_save (QofSession *session, if (be->sync) { (be->sync)(be, abook); - if (save_error_handler(be, session)) return; + if (save_error_handler(be, session)) + goto leave; } } /* If we got to here, then the backend saved everything @@ -1316,7 +1320,7 @@ qof_session_save (QofSession *session, /* Return the book_id to previous value. */ qof_session_clear_error (session); LEAVE("Success"); - return; + goto leave; } else { @@ -1324,9 +1328,17 @@ qof_session_save (QofSession *session, qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg); } LEAVE("error -- No backend!"); + leave: + g_atomic_int_inc(&session->lock); + return; } /* ====================================================================== */ +gboolean +qof_session_save_in_progress(QofSession *session) +{ + return (session && g_atomic_int_get(&session->lock) != 1); +} void qof_session_end (QofSession *session) diff --git a/lib/libqof/qof/qofsession.h b/lib/libqof/qof/qofsession.h index 9afe62e020..6460bfecc3 100644 --- a/lib/libqof/qof/qofsession.h +++ b/lib/libqof/qof/qofsession.h @@ -222,6 +222,7 @@ const char * qof_session_get_url (QofSession *session); * if any data in the session hasn't been saved to long-term storage. */ gboolean qof_session_not_saved(QofSession *session); +gboolean qof_session_save_in_progress(QofSession *session); /** Allows the backend to warn the user if a dataset already exists. */ gboolean qof_session_save_may_clobber_data (QofSession *session); diff --git a/src/gnome-utils/gnc-file.c b/src/gnome-utils/gnc-file.c index 8ab553e726..9d8707b441 100644 --- a/src/gnome-utils/gnc-file.c +++ b/src/gnome-utils/gnc-file.c @@ -1157,5 +1157,6 @@ gnc_file_set_shutdown_callback (GNCShutdownCB cb) gboolean gnc_file_save_in_progress (void) { - return (save_in_progress > 0); + QofSession *session = gnc_get_current_session(); + return (qof_session_save_in_progress(session) || save_in_progress > 0); }