1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
5 * This library is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation.
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this library; if not, see <http://www.gnu.org/licenses/>.
22 #include "e-cancellable-locks.h"
25 * SECTION:e-cancellable-locks
26 * @title: Cancellable Locks
27 * @short_description: locks, which can listen for a #GCancellable during lock call
29 * An #ECancellableMutex and an #ECancellableRecMutex are similar to
30 * GLib's #GMutex and #GRecMutex, with one exception, their <i>lock</i>
31 * function takes also a @GCancellable instance, thus the waiting for a lock
32 * can be cancelled any time.
36 cancellable_locks_cancelled_cb (GCancellable *cancellable,
37 struct _ECancellableLocksBase *base)
39 g_return_if_fail (base != NULL);
41 /* wake-up any waiting threads */
42 g_mutex_lock (&base->cond_mutex);
43 g_cond_broadcast (&base->cond);
44 g_mutex_unlock (&base->cond_mutex);
48 * e_cancellable_mutex_init:
49 * @mutex: an #ECancellableMutex instance
51 * Initializes @mutex structure.
55 * Deprecated: 3.12: If you think you need this, you're using mutexes wrong.
58 e_cancellable_mutex_init (ECancellableMutex *mutex)
60 g_return_if_fail (mutex != NULL);
62 g_mutex_init (&mutex->mutex);
63 g_mutex_init (&mutex->base.cond_mutex);
64 g_cond_init (&mutex->base.cond);
68 * e_cancellable_mutex_clear:
69 * @mutex: an #ECancellableMutex instance
71 * Frees memory allocated by e_cancellable_mutex_init().
75 * Deprecated: 3.12: If you think you need this, you're using mutexes wrong.
78 e_cancellable_mutex_clear (ECancellableMutex *mutex)
80 g_return_if_fail (mutex != NULL);
82 g_mutex_clear (&mutex->mutex);
83 g_mutex_clear (&mutex->base.cond_mutex);
84 g_cond_clear (&mutex->base.cond);
88 * e_cancellable_mutex_lock:
89 * @mutex: an #ECancellableMutex instance
90 * @cancellable: (allow-none): a #GCancellable, or %NULL
92 * Acquires lock on @mutex. The returned value indicates whether
93 * the lock was acquired, while %FALSE is returned only either or
94 * invalid arguments or the passed in @cancellable had been cancelled.
95 * In case of %NULL @cancellable the function blocks like g_mutex_lock().
97 * Returns: %TRUE, if lock had been acquired, %FALSE otherwise
101 * Deprecated: 3.12: If you think you need this, you're using mutexes wrong.
104 e_cancellable_mutex_lock (ECancellableMutex *mutex,
105 GCancellable *cancellable)
110 g_return_val_if_fail (mutex != NULL, FALSE);
112 g_mutex_lock (&mutex->base.cond_mutex);
114 g_mutex_unlock (&mutex->base.cond_mutex);
115 g_mutex_lock (&mutex->mutex);
119 if (g_cancellable_is_cancelled (cancellable)) {
120 g_mutex_unlock (&mutex->base.cond_mutex);
124 handler_id = g_signal_connect (
125 cancellable, "cancelled",
126 G_CALLBACK (cancellable_locks_cancelled_cb), &mutex->base);
128 while (!g_mutex_trylock (&mutex->mutex)) {
129 /* recheck once per 10 seconds, just in case */
131 &mutex->base.cond, &mutex->base.cond_mutex,
132 g_get_monotonic_time () + (10 * G_TIME_SPAN_SECOND));
134 if (g_cancellable_is_cancelled (cancellable)) {
140 g_signal_handler_disconnect (cancellable, handler_id);
142 g_mutex_unlock (&mutex->base.cond_mutex);
148 * e_cancellable_mutex_unlock:
149 * @mutex: an #ECancellableMutex instance
151 * Releases lock previously acquired by e_cancellable_mutex_lock().
152 * Behaviour is undefined if this is called on a @mutex which returned
153 * %FALSE in e_cancellable_mutex_lock().
157 * Deprecated: 3.12: If you think you need this, you're using mutexes wrong.
160 e_cancellable_mutex_unlock (ECancellableMutex *mutex)
162 g_return_if_fail (mutex != NULL);
164 g_mutex_unlock (&mutex->mutex);
166 g_mutex_lock (&mutex->base.cond_mutex);
167 /* also wake-up any waiting threads */
168 g_cond_broadcast (&mutex->base.cond);
169 g_mutex_unlock (&mutex->base.cond_mutex);
173 * e_cancellable_mutex_get_internal_mutex:
174 * @mutex: an #ECancellableMutex instance
176 * To get internal #GMutex. This is meant for cases when a lock is already
177 * acquired, and the caller needs to wait for a #GCond, in which case
178 * the returned #GMutex can be used to g_cond_wait() or g_cond_wait_until().
180 * Returns: Internal #GMutex, used in @mutex
184 * Deprecated: 3.12: If you think you need this, you're using mutexes wrong.
187 e_cancellable_mutex_get_internal_mutex (ECancellableMutex *mutex)
189 g_return_val_if_fail (mutex != NULL, NULL);
191 return &mutex->mutex;
195 * e_cancellable_rec_mutex_init:
196 * @rec_mutex: an #ECancellableRecMutex instance
198 * Initializes @rec_mutex structure.
202 * Deprecated: 3.12: If you think you need this, you're using mutexes wrong.
205 e_cancellable_rec_mutex_init (ECancellableRecMutex *rec_mutex)
207 g_return_if_fail (rec_mutex != NULL);
209 g_rec_mutex_init (&rec_mutex->rec_mutex);
210 g_mutex_init (&rec_mutex->base.cond_mutex);
211 g_cond_init (&rec_mutex->base.cond);
215 * e_cancellable_rec_mutex_clear:
216 * @rec_mutex: an #ECancellableRecMutex instance
218 * Frees memory allocated by e_cancellable_rec_mutex_init().
222 * Deprecated: 3.12: If you think you need this, you're using mutexes wrong.
225 e_cancellable_rec_mutex_clear (ECancellableRecMutex *rec_mutex)
227 g_return_if_fail (rec_mutex != NULL);
229 g_rec_mutex_clear (&rec_mutex->rec_mutex);
230 g_mutex_clear (&rec_mutex->base.cond_mutex);
231 g_cond_clear (&rec_mutex->base.cond);
235 * e_cancellable_rec_mutex_lock:
236 * @rec_mutex: an #ECancellableRecMutex instance
237 * @cancellable: (allow-none): a #GCancellable, or %NULL
239 * Acquires lock on @rec_mutex. The returned value indicates whether
240 * the lock was acquired, while %FALSE is returned only either or
241 * invalid arguments or the passed in @cancellable had been cancelled.
242 * In case of %NULL @cancellable the function blocks like g_rec_mutex_lock().
244 * Returns: %TRUE, if lock had been acquired, %FALSE otherwise
248 * Deprecated: 3.12: If you think you need this, you're using mutexes wrong.
251 e_cancellable_rec_mutex_lock (ECancellableRecMutex *rec_mutex,
252 GCancellable *cancellable)
257 g_return_val_if_fail (rec_mutex != NULL, FALSE);
259 g_mutex_lock (&rec_mutex->base.cond_mutex);
261 g_mutex_unlock (&rec_mutex->base.cond_mutex);
262 g_rec_mutex_lock (&rec_mutex->rec_mutex);
266 if (g_cancellable_is_cancelled (cancellable)) {
267 g_mutex_unlock (&rec_mutex->base.cond_mutex);
271 handler_id = g_signal_connect (
272 cancellable, "cancelled",
273 G_CALLBACK (cancellable_locks_cancelled_cb), &rec_mutex->base);
275 while (!g_rec_mutex_trylock (&rec_mutex->rec_mutex)) {
276 /* recheck once per 10 seconds, just in case */
278 &rec_mutex->base.cond, &rec_mutex->base.cond_mutex,
279 g_get_monotonic_time () + (10 * G_TIME_SPAN_SECOND));
281 if (g_cancellable_is_cancelled (cancellable)) {
287 g_signal_handler_disconnect (cancellable, handler_id);
289 g_mutex_unlock (&rec_mutex->base.cond_mutex);
295 * e_cancellable_rec_mutex_unlock:
296 * @rec_mutex: an #ECancellableRecMutex instance
298 * Releases lock previously acquired by e_cancellable_rec_mutex_lock().
299 * Behaviour is undefined if this is called on a @rec_mutex which returned
300 * %FALSE in e_cancellable_rec_mutex_lock().
304 * Deprecated: 3.12: If you think you need this, you're using mutexes wrong.
307 e_cancellable_rec_mutex_unlock (ECancellableRecMutex *rec_mutex)
309 g_return_if_fail (rec_mutex != NULL);
311 g_rec_mutex_unlock (&rec_mutex->rec_mutex);
313 g_mutex_lock (&rec_mutex->base.cond_mutex);
314 /* also wake-up any waiting threads */
315 g_cond_broadcast (&rec_mutex->base.cond);
316 g_mutex_unlock (&rec_mutex->base.cond_mutex);