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