Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / servers / exchange / lib / e2k-operation.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2
3 /* Copyright (C) 2003, 2004 Novell, Inc.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of version 2 of the GNU Lesser General Public
7  * License as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 /* e2k-operation.c: Cancellable operations */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27
28 #include "e2k-operation.h"
29
30 static GStaticMutex op_mutex = G_STATIC_MUTEX_INIT;
31 static GHashTable *active_ops = NULL;
32
33 /**
34  * e2k_operation_init:
35  * @op: an #E2kOperation
36  *
37  * This initializes the #E2kOperation pointed to by @op.
38  * This should be called before passing @op to a cancellable function.
39  **/
40 void
41 e2k_operation_init (E2kOperation *op)
42 {
43         g_return_if_fail (op != NULL);
44
45         memset (op, 0, sizeof (E2kOperation));
46
47         g_static_mutex_lock (&op_mutex);
48         if (!active_ops)
49                 active_ops = g_hash_table_new (NULL, NULL);
50         g_hash_table_insert (active_ops, op, op);
51         g_static_mutex_unlock (&op_mutex);
52 }
53
54 /**
55  * e2k_operation_free:
56  * @op: an #E2kOperation
57  *
58  * This frees @op and removes it from the list of active operations.
59  * It should be called after the function it was passed to returns.
60  **/
61 void
62 e2k_operation_free (E2kOperation *op)
63 {
64         g_return_if_fail (op != NULL);
65
66         g_static_mutex_lock (&op_mutex);
67         g_hash_table_remove (active_ops, op);
68         g_static_mutex_unlock (&op_mutex);
69 }
70
71
72 /**
73  * e2k_operation_start:
74  * @op: an #E2kOperation, or %NULL
75  * @canceller: the callback to invoke if @op is cancelled
76  * @owner: object that owns the operation
77  * @data: data to pass to @canceller
78  *
79  * This starts a single cancellable operation using @op. If @op has
80  * already been cancelled, this will invoke @canceller immediately.
81  *
82  * (If @op is %NULL, e2k_operation_start() is a no-op.)
83  **/
84 void
85 e2k_operation_start (E2kOperation *op,
86                      E2kOperationCancelFunc canceller,
87                      gpointer owner,
88                      gpointer data)
89 {
90         if (!op)
91                 return;
92
93         g_static_mutex_lock (&op_mutex);
94
95         op->canceller = canceller;
96         op->owner = owner;
97         op->data = data;
98
99         if (op->cancelled && op->canceller) {
100                 g_static_mutex_unlock (&op_mutex);
101                 op->canceller (op, op->owner, op->data);
102                 return;
103         }
104
105         g_static_mutex_unlock (&op_mutex);
106 }
107
108 /**
109  * e2k_operation_finish:
110  * @op: an #E2kOperation, or %NULL
111  *
112  * This finishes the current cancellable operation on @op. Attempting
113  * to cancel @op after this point will have no effect until another
114  * operation is started on it.
115  *
116  * (If @op is %NULL, e2k_operation_finish() is a no-op.)
117  **/
118 void
119 e2k_operation_finish (E2kOperation *op)
120 {
121         if (!op)
122                 return;
123
124         g_static_mutex_lock (&op_mutex);
125         op->canceller = NULL;
126         op->owner = NULL;
127         op->data = NULL;
128         g_static_mutex_unlock (&op_mutex);
129 }
130
131
132 /**
133  * e2k_operation_cancel:
134  * @op: an #E2kOperation
135  *
136  * This cancels @op, invoking its cancellation callback. If @op is not
137  * an active operation, or has already been cancelled, this has no
138  * effect.
139  **/
140 void
141 e2k_operation_cancel (E2kOperation *op)
142 {
143         g_return_if_fail (op != NULL);
144
145         g_static_mutex_lock (&op_mutex);
146
147         if (!g_hash_table_lookup (active_ops, op) || op->cancelled) {
148                 g_static_mutex_unlock (&op_mutex);
149                 return;
150         }
151
152         g_hash_table_remove (active_ops, op);
153         op->cancelled = TRUE;
154         g_static_mutex_unlock (&op_mutex);
155
156         if (op->canceller)
157                 op->canceller (op, op->owner, op->data);
158 }
159
160 /**
161  * e2k_operation_is_cancelled:
162  * @op: an #E2kOperation (or %NULL)
163  *
164  * Checks if @op has been cancelled. Should only be called while @op
165  * is active.
166  *
167  * Return value: whether or not @op has been cancelled.
168  **/
169 gboolean
170 e2k_operation_is_cancelled (E2kOperation *op)
171 {
172         return op && op->cancelled;
173 }