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