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