gsourceclosure: use g_cclosure_marshal_generic
[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
28 /*< private >
29  * SECTION:gasynchelper
30  * @short_description: Asynchronous Helper Functions
31  * @include: gio/gio.h
32  * @see_also: #GAsyncResult
33  * 
34  * Provides helper functions for asynchronous operations.
35  *
36  **/
37
38 /*************************************************************************
39  *             fd source                                                 *
40  ************************************************************************/
41
42 typedef struct 
43 {
44   GSource source;
45   GPollFD pollfd;
46 } FDSource;
47
48 static gboolean 
49 fd_source_prepare (GSource *source,
50                    gint    *timeout)
51 {
52   *timeout = -1;
53   return FALSE;
54 }
55
56 static gboolean 
57 fd_source_check (GSource *source)
58 {
59   FDSource *fd_source = (FDSource *)source;
60
61   return fd_source->pollfd.revents != 0;
62 }
63
64 static gboolean
65 fd_source_dispatch (GSource     *source,
66                     GSourceFunc  callback,
67                     gpointer     user_data)
68
69 {
70   GFDSourceFunc func = (GFDSourceFunc)callback;
71   FDSource *fd_source = (FDSource *)source;
72
73   g_warn_if_fail (func != NULL);
74
75   return (*func) (fd_source->pollfd.fd, fd_source->pollfd.revents, user_data);
76 }
77
78 static void 
79 fd_source_finalize (GSource *source)
80 {
81 }
82
83 static gboolean
84 fd_source_closure_callback (int           fd,
85                             GIOCondition  condition,
86                             gpointer      data)
87 {
88   GClosure *closure = data;
89
90   GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
91   GValue result_value = G_VALUE_INIT;
92   gboolean result;
93
94   g_value_init (&result_value, G_TYPE_BOOLEAN);
95
96   g_value_init (&params[0], G_TYPE_INT);
97   g_value_set_int (&params[0], fd);
98
99   g_value_init (&params[1], G_TYPE_IO_CONDITION);
100   g_value_set_flags (&params[1], condition);
101
102   g_closure_invoke (closure, &result_value, 2, params, NULL);
103
104   result = g_value_get_boolean (&result_value);
105   g_value_unset (&result_value);
106   g_value_unset (&params[0]);
107   g_value_unset (&params[1]);
108
109   return result;
110 }
111
112 static GSourceFuncs fd_source_funcs = {
113   fd_source_prepare,
114   fd_source_check,
115   fd_source_dispatch,
116   fd_source_finalize,
117   (GSourceFunc)fd_source_closure_callback,
118 };
119
120 GSource *
121 _g_fd_source_new (int           fd,
122                   gushort       events,
123                   GCancellable *cancellable)
124 {
125   GSource *source;
126   FDSource *fd_source;
127
128   source = g_source_new (&fd_source_funcs, sizeof (FDSource));
129   fd_source = (FDSource *)source;
130
131   fd_source->pollfd.fd = fd;
132   fd_source->pollfd.events = events;
133   g_source_add_poll (source, &fd_source->pollfd);
134
135   if (cancellable)
136     {
137       GSource *cancellable_source = g_cancellable_source_new (cancellable);
138
139       g_source_set_dummy_callback (cancellable_source);
140       g_source_add_child_source (source, cancellable_source);
141       g_source_unref (cancellable_source);
142     }
143
144   return source;
145 }
146
147 #ifdef G_OS_WIN32
148 gboolean
149 _g_win32_overlap_wait_result (HANDLE           hfile,
150                               OVERLAPPED      *overlap,
151                               DWORD           *transferred,
152                               GCancellable    *cancellable)
153 {
154   GPollFD pollfd[2];
155   gboolean result = FALSE;
156   gint num, npoll;
157
158   pollfd[0].fd = (gint)overlap->hEvent;
159   pollfd[0].events = G_IO_IN;
160   num = 1;
161
162   if (g_cancellable_make_pollfd (cancellable, &pollfd[1]))
163     num++;
164
165 loop:
166   npoll = g_poll (pollfd, num, -1);
167   if (npoll <= 0)
168     /* error out, should never happen */
169     goto end;
170
171   if (g_cancellable_is_cancelled (cancellable))
172     {
173       /* CancelIO only cancels pending operations issued by the
174        * current thread and since we're doing only sync operations,
175        * this is safe.... */
176       /* CancelIoEx is only Vista+. Since we have only one overlap
177        * operaton on this thread, we can just use: */
178       result = CancelIo (hfile);
179       g_warn_if_fail (result);
180     }
181
182   result = GetOverlappedResult (overlap->hEvent, overlap, transferred, FALSE);
183   if (result == FALSE &&
184       GetLastError () == ERROR_IO_INCOMPLETE &&
185       !g_cancellable_is_cancelled (cancellable))
186     goto loop;
187
188 end:
189   if (num > 1)
190     g_cancellable_release_fd (cancellable);
191
192   return result;
193 }
194 #endif