pull in gasynchelper (won't need this once gnio is merged into gio)
[cascardo/gnio.git] / gnio / gasynchelper.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
25 #include "gasynchelper.h"
26
27 /**
28  * SECTION:gasynchelper
29  * @short_description: Asynchronous Helper Functions
30  * @include: gio/gio.h
31  * @see_also: #GAsyncReady
32  * 
33  * Provides helper functions for asynchronous operations.
34  *
35  **/
36
37 static void
38 async_result_free (gpointer data)
39 {
40   GAsyncResultData *res = data;
41
42   if (res->error)
43     g_error_free (res->error);
44
45   g_object_unref (res->async_object);
46   
47   g_free (res);
48 }
49
50 void
51 _g_queue_async_result (GAsyncResultData *result,
52                        gpointer          async_object,
53                        GError           *error,
54                        gpointer          user_data,
55                        GSourceFunc       source_func)
56 {
57   GSource *source;
58
59   g_return_if_fail (G_IS_OBJECT (async_object));
60   
61   result->async_object = g_object_ref (async_object);
62   result->user_data = user_data;
63   result->error = error;
64
65   source = g_idle_source_new ();
66   g_source_set_priority (source, G_PRIORITY_DEFAULT);
67   g_source_set_callback (source, source_func, result, async_result_free);
68   g_source_attach (source, NULL);
69   g_source_unref (source);
70 }
71
72 /*************************************************************************
73  *             fd source                                                 *
74  ************************************************************************/
75
76 typedef struct 
77 {
78   GSource source;
79   GPollFD pollfd;
80   GCancellable *cancellable;
81   gulong cancelled_tag;
82 } FDSource;
83
84 static gboolean 
85 fd_source_prepare (GSource *source,
86                    gint    *timeout)
87 {
88   FDSource *fd_source = (FDSource *)source;
89   *timeout = -1;
90   
91   return g_cancellable_is_cancelled (fd_source->cancellable);
92 }
93
94 static gboolean 
95 fd_source_check (GSource *source)
96 {
97   FDSource *fd_source = (FDSource *)source;
98
99   return
100     g_cancellable_is_cancelled  (fd_source->cancellable) ||
101     fd_source->pollfd.revents != 0;
102 }
103
104 static gboolean
105 fd_source_dispatch (GSource     *source,
106                     GSourceFunc  callback,
107                     gpointer     user_data)
108
109 {
110   GFDSourceFunc func = (GFDSourceFunc)callback;
111   FDSource *fd_source = (FDSource *)source;
112
113   g_warn_if_fail (func != NULL);
114
115   return (*func) (user_data, fd_source->pollfd.revents, fd_source->pollfd.fd);
116 }
117
118 static void 
119 fd_source_finalize (GSource *source)
120 {
121   FDSource *fd_source = (FDSource *)source;
122
123   if (fd_source->cancelled_tag)
124     g_signal_handler_disconnect (fd_source->cancellable,
125                                  fd_source->cancelled_tag);
126
127   if (fd_source->cancellable)
128     g_object_unref (fd_source->cancellable);
129 }
130
131 static GSourceFuncs fd_source_funcs = {
132   fd_source_prepare,
133   fd_source_check,
134   fd_source_dispatch,
135   fd_source_finalize
136 };
137
138 /* Might be called on another thread */
139 static void
140 fd_source_cancelled_cb (GCancellable *cancellable,
141                         gpointer      data)
142 {
143   /* Wake up the mainloop in case we're waiting on async calls with FDSource */
144   g_main_context_wakeup (NULL);
145 }
146
147 GSource *
148 _g_fd_source_new (int           fd,
149                   gushort       events,
150                   GCancellable *cancellable)
151 {
152   GSource *source;
153   FDSource *fd_source;
154
155   source = g_source_new (&fd_source_funcs, sizeof (FDSource));
156   fd_source = (FDSource *)source;
157
158   if (cancellable)
159     fd_source->cancellable = g_object_ref (cancellable);
160   
161   fd_source->pollfd.fd = fd;
162   fd_source->pollfd.events = events;
163   g_source_add_poll (source, &fd_source->pollfd);
164
165   if (cancellable)
166     fd_source->cancelled_tag =
167       g_signal_connect_data (cancellable, "cancelled",
168                              (GCallback)fd_source_cancelled_cb,
169                              NULL, NULL,
170                              0);
171   
172   return source;
173 }