[evolution-data-server] Introduce cancellable locks
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Introduce cancellable locks
- Date: Fri, 14 Dec 2012 16:44:43 +0000 (UTC)
commit c155d7e1fb57bde5e90a056306b4e257b72e1264
Author: Milan Crha <mcrha redhat com>
Date: Fri Dec 14 17:42:41 2012 +0100
Introduce cancellable locks
There are currently two cancellable lock types, one extends GMutex,
the other extends GRecMutex, in a way that the waiting for a lock
can be cancelled.
libedataserver/Makefile.am | 2 +
libedataserver/e-cancellable-locks.c | 297 ++++++++++++++++++++++++++++++++++
libedataserver/e-cancellable-locks.h | 69 ++++++++
libedataserver/libedataserver.h | 1 +
4 files changed, 369 insertions(+), 0 deletions(-)
---
diff --git a/libedataserver/Makefile.am b/libedataserver/Makefile.am
index 3e684a0..1ceede0 100644
--- a/libedataserver/Makefile.am
+++ b/libedataserver/Makefile.am
@@ -46,6 +46,7 @@ libedataserver_1_2_la_CPPFLAGS = \
libedataserver_1_2_la_SOURCES = \
$(BUILT_SOURCES) \
+ e-cancellable-locks.c \
e-categories.c \
e-client.c \
e-client-private.h \
@@ -116,6 +117,7 @@ libedataserverincludedir = $(privincludedir)/libedataserver
libedataserverinclude_HEADERS = \
libedataserver.h \
+ e-cancellable-locks.h \
e-categories.h \
e-client.h \
e-credentials.h \
diff --git a/libedataserver/e-cancellable-locks.c b/libedataserver/e-cancellable-locks.c
new file mode 100644
index 0000000..dc8b11a
--- /dev/null
+++ b/libedataserver/e-cancellable-locks.c
@@ -0,0 +1,297 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-cancellable-locks.h"
+
+/**
+ * SECTION:cancellable_locks
+ * @title: Cancellable Locks
+ * @short_description: locks, which can listen for a #GCancellable during lock call
+ *
+ * An #ECancellableMutex and an #ECancellableRecMutex are similar to
+ * GLib's #GMutex and #GRecMutex, with one exception, their <i>lock</i>
+ * function takes also a @GCancellable instance, thus the waiting for a lock
+ * can be cancelled any time.
+ **/
+
+static void
+cancellable_locks_cancelled_cb (GCancellable *cancellable,
+ struct _ECancellableLocksBase *base)
+{
+ g_return_if_fail (base != NULL);
+
+ /* wake-up any waiting threads */
+ g_mutex_lock (&base->cond_mutex);
+ g_cond_broadcast (&base->cond);
+ g_mutex_unlock (&base->cond_mutex);
+}
+
+/**
+ * e_cancellable_mutex_init:
+ * @mutex: an #ECancellableMutex instance
+ *
+ * Initializes @mutex structure.
+ *
+ * Since: 3.8
+ **/
+void
+e_cancellable_mutex_init (ECancellableMutex *mutex)
+{
+ g_return_if_fail (mutex != NULL);
+
+ g_mutex_init (&mutex->mutex);
+ g_mutex_init (&mutex->base.cond_mutex);
+ g_cond_init (&mutex->base.cond);
+}
+
+/**
+ * e_cancellable_mutex_clear:
+ * @mutex: an #ECancellableMutex instance
+ *
+ * Frees memory allocated by e_cancellable_mutex_init().
+ *
+ * Since: 3.8
+ **/
+void
+e_cancellable_mutex_clear (ECancellableMutex *mutex)
+{
+ g_return_if_fail (mutex != NULL);
+
+ g_mutex_clear (&mutex->mutex);
+ g_mutex_clear (&mutex->base.cond_mutex);
+ g_cond_clear (&mutex->base.cond);
+}
+
+/**
+ * e_cancellable_mutex_lock:
+ * @mutex: an #ECancellableMutex instance
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ *
+ * Acquires lock on @mutex. The returned value indicates whether
+ * the lock was acquired, while %FALSE is returned only either or
+ * invalid arguments or the passed in @cancellable had been cancelled.
+ * In case of %NULL @cancellable the function blocks like g_mutex_lock().
+ *
+ * Returns: %TRUE, if lock had been acquired, %FALSE otherwise
+ *
+ * Since: 3.8
+ **/
+gboolean
+e_cancellable_mutex_lock (ECancellableMutex *mutex,
+ GCancellable *cancellable)
+{
+ gulong handler_id;
+ gboolean res = TRUE;
+
+ g_return_val_if_fail (mutex != NULL, FALSE);
+
+ g_mutex_lock (&mutex->base.cond_mutex);
+ if (!cancellable) {
+ g_mutex_unlock (&mutex->base.cond_mutex);
+ g_mutex_lock (&mutex->mutex);
+ return TRUE;
+ }
+
+ if (g_cancellable_is_cancelled (cancellable)) {
+ g_mutex_unlock (&mutex->base.cond_mutex);
+ return FALSE;
+ }
+
+ handler_id = g_signal_connect (cancellable, "cancelled",
+ G_CALLBACK (cancellable_locks_cancelled_cb), &mutex->base);
+
+ while (!g_mutex_trylock (&mutex->mutex)) {
+ /* recheck once per 10 seconds, just in case */
+ g_cond_wait_until (&mutex->base.cond, &mutex->base.cond_mutex,
+ g_get_monotonic_time () + (10 * G_TIME_SPAN_SECOND));
+
+ if (g_cancellable_is_cancelled (cancellable)) {
+ res = FALSE;
+ break;
+ }
+ }
+
+ g_signal_handler_disconnect (cancellable, handler_id);
+
+ g_mutex_unlock (&mutex->base.cond_mutex);
+
+ return res;
+}
+
+/**
+ * e_cancellable_mutex_unlock:
+ * @mutex: an #ECancellableMutex instance
+ *
+ * Releases lock previously acquired by e_cancellable_mutex_lock().
+ * Behaviour is undefined if this is called on a @mutex which returned
+ * %FALSE in e_cancellable_mutex_lock().
+ *
+ * Since: 3.8
+ **/
+void
+e_cancellable_mutex_unlock (ECancellableMutex *mutex)
+{
+ g_return_if_fail (mutex != NULL);
+
+ g_mutex_unlock (&mutex->mutex);
+
+ g_mutex_lock (&mutex->base.cond_mutex);
+ /* also wake-up any waiting threads */
+ g_cond_broadcast (&mutex->base.cond);
+ g_mutex_unlock (&mutex->base.cond_mutex);
+}
+
+/**
+ * e_cancellable_mutex_get_internal_mutex:
+ * @mutex: an #ECancellableMutex instance
+ *
+ * To get internal #GMutex. This is meant for cases when a lock is already
+ * acquired, and the caller needs to wait for a #GCond, in which case
+ * the returned #GMutex can be used to g_cond_wait() or g_cond_wait_until().
+ *
+ * Returns: Internal #GMutex, used in @mutex
+ *
+ * Since: 3.8
+ **/
+GMutex *
+e_cancellable_mutex_get_internal_mutex (ECancellableMutex *mutex)
+{
+ g_return_val_if_fail (mutex != NULL, NULL);
+
+ return &mutex->mutex;
+}
+
+/**
+ * e_cancellable_rec_mutex_init:
+ * @rec_mutex: an #ECancellableRecMutex instance
+ *
+ * Initializes @rec_mutex structure.
+ *
+ * Since: 3.8
+ **/
+void
+e_cancellable_rec_mutex_init (ECancellableRecMutex *rec_mutex)
+{
+ g_return_if_fail (rec_mutex != NULL);
+
+ g_rec_mutex_init (&rec_mutex->rec_mutex);
+ g_mutex_init (&rec_mutex->base.cond_mutex);
+ g_cond_init (&rec_mutex->base.cond);
+}
+
+/**
+ * e_cancellable_rec_mutex_clear:
+ * @rec_mutex: an #ECancellableRecMutex instance
+ *
+ * Frees memory allocated by e_cancellable_rec_mutex_init().
+ *
+ * Since: 3.8
+ **/
+void
+e_cancellable_rec_mutex_clear (ECancellableRecMutex *rec_mutex)
+{
+ g_return_if_fail (rec_mutex != NULL);
+
+ g_rec_mutex_clear (&rec_mutex->rec_mutex);
+ g_mutex_clear (&rec_mutex->base.cond_mutex);
+ g_cond_clear (&rec_mutex->base.cond);
+}
+
+/**
+ * e_cancellable_rec_mutex_lock:
+ * @rec_mutex: an #ECancellableRecMutex instance
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ *
+ * Acquires lock on @rec_mutex. The returned value indicates whether
+ * the lock was acquired, while %FALSE is returned only either or
+ * invalid arguments or the passed in @cancellable had been cancelled.
+ * In case of %NULL @cancellable the function blocks like g_rec_mutex_lock().
+ *
+ * Returns: %TRUE, if lock had been acquired, %FALSE otherwise
+ *
+ * Since: 3.8
+ **/
+gboolean
+e_cancellable_rec_mutex_lock (ECancellableRecMutex *rec_mutex,
+ GCancellable *cancellable)
+{
+ gulong handler_id;
+ gboolean res = TRUE;
+
+ g_return_val_if_fail (rec_mutex != NULL, FALSE);
+
+ g_mutex_lock (&rec_mutex->base.cond_mutex);
+ if (!cancellable) {
+ g_mutex_unlock (&rec_mutex->base.cond_mutex);
+ g_rec_mutex_lock (&rec_mutex->rec_mutex);
+ return TRUE;
+ }
+
+ if (g_cancellable_is_cancelled (cancellable)) {
+ g_mutex_unlock (&rec_mutex->base.cond_mutex);
+ return FALSE;
+ }
+
+ handler_id = g_signal_connect (cancellable, "cancelled",
+ G_CALLBACK (cancellable_locks_cancelled_cb), &rec_mutex->base);
+
+ while (!g_rec_mutex_trylock (&rec_mutex->rec_mutex)) {
+ /* recheck once per 10 seconds, just in case */
+ g_cond_wait_until (&rec_mutex->base.cond, &rec_mutex->base.cond_mutex,
+ g_get_monotonic_time () + (10 * G_TIME_SPAN_SECOND));
+
+ if (g_cancellable_is_cancelled (cancellable)) {
+ res = FALSE;
+ break;
+ }
+ }
+
+ g_signal_handler_disconnect (cancellable, handler_id);
+
+ g_mutex_unlock (&rec_mutex->base.cond_mutex);
+
+ return res;
+}
+
+/**
+ * e_cancellable_rec_mutex_unlock:
+ * @rec_mutex: an #ECancellableRecMutex instance
+ *
+ * Releases lock previously acquired by e_cancellable_rec_mutex_lock().
+ * Behaviour is undefined if this is called on a @rec_mutex which returned
+ * %FALSE in e_cancellable_rec_mutex_lock().
+ *
+ * Since: 3.8
+ **/
+void
+e_cancellable_rec_mutex_unlock (ECancellableRecMutex *rec_mutex)
+{
+ g_return_if_fail (rec_mutex != NULL);
+
+ g_rec_mutex_unlock (&rec_mutex->rec_mutex);
+
+ g_mutex_lock (&rec_mutex->base.cond_mutex);
+ /* also wake-up any waiting threads */
+ g_cond_broadcast (&rec_mutex->base.cond);
+ g_mutex_unlock (&rec_mutex->base.cond_mutex);
+}
diff --git a/libedataserver/e-cancellable-locks.h b/libedataserver/e-cancellable-locks.h
new file mode 100644
index 0000000..0ccb23c
--- /dev/null
+++ b/libedataserver/e-cancellable-locks.h
@@ -0,0 +1,69 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#if !defined (__LIBEDATASERVER_H_INSIDE__) && !defined (LIBEDATASERVER_COMPILATION)
+#error "Only <libedataserver/libedataserver.h> should be included directly."
+#endif
+
+#ifndef E_CANCELLABLE_LOCKS_H
+#define E_CANCELLABLE_LOCKS_H
+
+#include <glib.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+typedef struct _ECancellableMutex ECancellableMutex;
+typedef struct _ECancellableRecMutex ECancellableRecMutex;
+
+void e_cancellable_mutex_init (ECancellableMutex *mutex);
+void e_cancellable_mutex_clear (ECancellableMutex *mutex);
+gboolean e_cancellable_mutex_lock (ECancellableMutex *mutex,
+ GCancellable *cancellable);
+void e_cancellable_mutex_unlock (ECancellableMutex *mutex);
+GMutex * e_cancellable_mutex_get_internal_mutex
+ (ECancellableMutex *mutex);
+
+void e_cancellable_rec_mutex_init (ECancellableRecMutex *rec_mutex);
+void e_cancellable_rec_mutex_clear (ECancellableRecMutex *rec_mutex);
+gboolean e_cancellable_rec_mutex_lock (ECancellableRecMutex *rec_mutex,
+ GCancellable *cancellable);
+void e_cancellable_rec_mutex_unlock (ECancellableRecMutex *rec_mutex);
+
+/* private structures, members should not be accessed
+ otherwise than with above functions */
+
+struct _ECancellableLocksBase {
+ GMutex cond_mutex;
+ GCond cond;
+};
+
+struct _ECancellableMutex {
+ struct _ECancellableLocksBase base;
+ GMutex mutex;
+};
+
+struct _ECancellableRecMutex {
+ struct _ECancellableLocksBase base;
+ GRecMutex rec_mutex;
+};
+
+G_END_DECLS
+
+#endif /* E_CANCELLABLE_LOCKS_H */
diff --git a/libedataserver/libedataserver.h b/libedataserver/libedataserver.h
index ca98003..1bf689c 100644
--- a/libedataserver/libedataserver.h
+++ b/libedataserver/libedataserver.h
@@ -21,6 +21,7 @@
#define __LIBEDATASERVER_H_INSIDE__
+#include <libedataserver/e-cancellable-locks.h>
#include <libedataserver/e-categories.h>
#include <libedataserver/e-client.h>
#include <libedataserver/e-credentials.h>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]