a31420bb2d514d11cc3ff0bccc72b5491e84911c
[platform/upstream/glib.git] / gio / gcancellable.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include <config.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <gioerror.h>
27 #include "gcancellable.h"
28 #include "glibintl.h"
29
30
31 /**
32  * SECTION:gcancellable
33  * @short_description: Thread-safe Operation Cancellation Stack
34  * @include: gio/gcancellable.h
35  *
36  * GCancellable is a thread-safe operation cancellation stack used 
37  * throughout GIO to allow for cancellation of asynchronous operations.
38  */
39
40 enum {
41   CANCELLED,
42   LAST_SIGNAL
43 };
44
45 struct _GCancellable
46 {
47   GObject parent_instance;
48
49   guint cancelled : 1;
50   guint allocated_pipe : 1;
51   int cancel_pipe[2];
52 };
53
54 static guint signals[LAST_SIGNAL] = { 0 };
55
56 G_DEFINE_TYPE (GCancellable, g_cancellable, G_TYPE_OBJECT);
57
58 static GStaticPrivate current_cancellable = G_STATIC_PRIVATE_INIT;
59 G_LOCK_DEFINE_STATIC(cancellable);
60   
61 static void
62 g_cancellable_finalize (GObject *object)
63 {
64   GCancellable *cancellable = G_CANCELLABLE (object);
65
66   if (cancellable->cancel_pipe[0] != -1)
67     close (cancellable->cancel_pipe[0]);
68   
69   if (cancellable->cancel_pipe[1] != -1)
70     close (cancellable->cancel_pipe[1]);
71   
72   if (G_OBJECT_CLASS (g_cancellable_parent_class)->finalize)
73     (*G_OBJECT_CLASS (g_cancellable_parent_class)->finalize) (object);
74 }
75
76 static void
77 g_cancellable_class_init (GCancellableClass *klass)
78 {
79   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
80   
81   gobject_class->finalize = g_cancellable_finalize;
82
83   /**
84    * GCancellable::cancelled:
85    * @cancellable: a #GCancellable.
86    * 
87    * Emitted when the operation has been cancelled from another thread.
88    */
89   signals[CANCELLED] =
90     g_signal_new (I_("cancelled"),
91                   G_TYPE_FROM_CLASS (gobject_class),
92                   G_SIGNAL_RUN_LAST,
93                   G_STRUCT_OFFSET (GCancellableClass, cancelled),
94                   NULL, NULL,
95                   g_cclosure_marshal_VOID__VOID,
96                   G_TYPE_NONE, 0);
97   
98 }
99
100 static void
101 set_fd_nonblocking (int fd)
102 {
103 #ifdef F_GETFL
104   glong fcntl_flags;
105   fcntl_flags = fcntl (fd, F_GETFL);
106
107 #ifdef O_NONBLOCK
108   fcntl_flags |= O_NONBLOCK;
109 #else
110   fcntl_flags |= O_NDELAY;
111 #endif
112
113   fcntl (fd, F_SETFL, fcntl_flags);
114 #endif
115 }
116
117 static void
118 g_cancellable_open_pipe (GCancellable *cancellable)
119 {
120   if (pipe (cancellable->cancel_pipe) == 0)
121     {
122       /* Make them nonblocking, just to be sure we don't block
123        * on errors and stuff
124        */
125       set_fd_nonblocking (cancellable->cancel_pipe[0]);
126       set_fd_nonblocking (cancellable->cancel_pipe[1]);
127     }
128   else
129     g_warning ("Failed to create pipe for GCancellable. Out of file descriptors?");
130 }
131
132 static void
133 g_cancellable_init (GCancellable *cancellable)
134 {
135   cancellable->cancel_pipe[0] = -1;
136   cancellable->cancel_pipe[1] = -1;
137 }
138
139 /**
140  * g_cancellable_new:
141  * 
142  * Creates a new #GCancellable object.
143  *  
144  * Returns: a #GCancellable.
145  **/
146 GCancellable *
147 g_cancellable_new (void)
148 {
149   return g_object_new (G_TYPE_CANCELLABLE, NULL);
150 }
151
152 /**
153  * g_push_current_cancellable:
154  * @cancellable: optional #GCancellable object, %NULL to ignore.
155  * 
156  * Pushes @cancellable onto the cancellable stack.
157  **/
158 void
159 g_push_current_cancellable (GCancellable *cancellable)
160 {
161   GSList *l;
162
163   g_assert (cancellable != NULL);
164   
165   l = g_static_private_get (&current_cancellable);
166   l = g_slist_prepend (l, cancellable);
167   g_static_private_set (&current_cancellable, l, NULL);
168 }
169
170 /**
171  * g_pop_current_cancellable:
172  * @cancellable: optional #GCancellable object, %NULL to ignore.
173  *
174  * Pops @cancellable off the cancellable stack if @cancellable 
175  * is on the top of the stack.
176  **/
177 void
178 g_pop_current_cancellable (GCancellable *cancellable)
179 {
180   GSList *l;
181   
182   l = g_static_private_get (&current_cancellable);
183   
184   g_assert (l != NULL);
185   g_assert (l->data == cancellable);
186
187   l = g_slist_delete_link (l, l);
188   g_static_private_set (&current_cancellable, l, NULL);
189 }
190
191 /**
192  * g_cancellable_get_current:
193  * 
194  * Gets the top cancellable from the stack.
195  * 
196  * Returns: a #GCancellable from the top of the stack, or %NULL
197  * if the stack is empty. 
198  **/
199 GCancellable *
200 g_cancellable_get_current  (void)
201 {
202   GSList *l;
203   
204   l = g_static_private_get (&current_cancellable);
205   if (l == NULL)
206     return NULL;
207
208   return G_CANCELLABLE (l->data);
209 }
210
211 /**
212  * g_cancellable_reset:
213  * @cancellable: a #GCancellable object.
214  * 
215  * Resets @cancellable to its uncancelled state. 
216  **/
217 void 
218 g_cancellable_reset (GCancellable *cancellable)
219 {
220   g_return_if_fail (G_IS_CANCELLABLE (cancellable));
221
222   G_LOCK(cancellable);
223   /* Make sure we're not leaving old cancel state around */
224   if (cancellable->cancelled)
225     {
226       char ch;
227       if (cancellable->cancel_pipe[0] != -1)
228         read (cancellable->cancel_pipe[0], &ch, 1);
229       cancellable->cancelled = FALSE;
230     }
231   G_UNLOCK(cancellable);
232 }
233
234 /**
235  * g_cancellable_is_cancelled:
236  * @cancellable: a #GCancellable or NULL.
237  * 
238  * Checks if a cancellable job has been cancelled.
239  * 
240  * Returns: %TRUE if @cancellable is is cancelled, 
241  * FALSE if called with %NULL or if item is not cancelled. 
242  **/
243 gboolean
244 g_cancellable_is_cancelled (GCancellable *cancellable)
245 {
246   return cancellable != NULL && cancellable->cancelled;
247 }
248
249 /**
250  * g_cancellable_set_error_if_cancelled:
251  * @cancellable: a #GCancellable object.
252  * @error: #GError to append error state to.
253  * 
254  * Sets the current error to notify that the operation was cancelled.
255  * 
256  * Returns: %TRUE if @cancellable was cancelled, %FALSE if it was not.
257  **/
258 gboolean
259 g_cancellable_set_error_if_cancelled (GCancellable  *cancellable,
260                                       GError       **error)
261 {
262   if (g_cancellable_is_cancelled (cancellable))
263     {
264       g_set_error (error,
265                    G_IO_ERROR,
266                    G_IO_ERROR_CANCELLED,
267                    _("Operation was cancelled"));
268       return TRUE;
269     }
270   
271   return FALSE;
272 }
273
274 /**
275  * g_cancellable_get_fd:
276  * @cancellable: a #GCancellable.
277  * 
278  * Gets the file descriptor for a cancellable job.
279  * 
280  * Returns: A valid file descriptor. %-1 if the file descriptor 
281  * is not supported, or on errors. 
282  **/
283 int
284 g_cancellable_get_fd (GCancellable *cancellable)
285 {
286   int fd;
287   if (cancellable == NULL)
288     return -1;
289   
290   G_LOCK(cancellable);
291   if (!cancellable->allocated_pipe)
292     {
293       cancellable->allocated_pipe = TRUE;
294       g_cancellable_open_pipe (cancellable);
295     }
296   
297   fd = cancellable->cancel_pipe[0];
298   G_UNLOCK(cancellable);
299   
300   return fd;
301 }
302
303 /**
304  * g_cancellable_cancel:
305  * @cancellable: a #GCancellable object.
306  * 
307  * Will set @cancellable to cancelled, and will emit the CANCELLED
308  * signal. This function is thread-safe.
309  **/
310 void
311 g_cancellable_cancel (GCancellable *cancellable)
312 {
313   gboolean cancel;
314
315   cancel = FALSE;
316   
317   G_LOCK(cancellable);
318   if (cancellable != NULL &&
319       !cancellable->cancelled)
320     {
321       char ch = 'x';
322       cancel = TRUE;
323       cancellable->cancelled = TRUE;
324       if (cancellable->cancel_pipe[1] != -1)
325         write (cancellable->cancel_pipe[1], &ch, 1);
326     }
327   G_UNLOCK(cancellable);
328
329   if (cancel)
330     {
331       g_object_ref (cancellable);
332       g_signal_emit (cancellable, signals[CANCELLED], 0);
333       g_object_unref (cancellable);
334     }
335 }
336
337