win32: use overlapped events for streams
[platform/upstream/glib.git] / gio / gasynchelper.c
index 98bce1b..fa6c816 100644 (file)
  * Author: Alexander Larsson <alexl@redhat.com>
  */
 
-#include <config.h>
+#include "config.h"
 
 #include "gasynchelper.h"
 
-/**
+
+/*< private >
  * SECTION:gasynchelper
  * @short_description: Asynchronous Helper Functions
- * @see_also: #GAsyncReady.
+ * @include: gio/gio.h
+ * @see_also: #GAsyncResult
  * 
  * Provides helper functions for asynchronous operations.
  *
  **/
 
-static void
-async_result_free (gpointer data)
-{
-  GAsyncResultData *res = data;
-
-  if (res->error)
-    g_error_free (res->error);
-
-  g_object_unref (res->async_object);
-  
-  g_free (res);
-}
-
-void
-_g_queue_async_result (GAsyncResultData *result,
-                      gpointer        async_object,
-                      GError         *error,
-                      gpointer        user_data,
-                      GSourceFunc     source_func)
-{
-  GSource *source;
-
-  g_return_if_fail (G_IS_OBJECT (async_object));
-  
-  result->async_object = g_object_ref (async_object);
-  result->user_data = user_data;
-  result->error = error;
-
-  source = g_idle_source_new ();
-  g_source_set_priority (source, G_PRIORITY_DEFAULT);
-  g_source_set_callback (source, source_func, result, async_result_free);
-  g_source_attach (source, NULL);
-  g_source_unref (source);
-}
-
 /*************************************************************************
  *             fd source                                                 *
  ************************************************************************/
@@ -76,28 +43,22 @@ typedef struct
 {
   GSource source;
   GPollFD pollfd;
-  GCancellable *cancellable;
-  gulong cancelled_tag;
 } FDSource;
 
 static gboolean 
-fd_source_prepare (GSource  *source,
-                  gint     *timeout)
+fd_source_prepare (GSource *source,
+                  gint    *timeout)
 {
-  FDSource *fd_source = (FDSource *)source;
   *timeout = -1;
-  
-  return g_cancellable_is_cancelled (fd_source->cancellable);
+  return FALSE;
 }
 
 static gboolean 
-fd_source_check (GSource  *source)
+fd_source_check (GSource *source)
 {
   FDSource *fd_source = (FDSource *)source;
 
-  return
-    g_cancellable_is_cancelled  (fd_source->cancellable) ||
-    fd_source->pollfd.revents != 0;
+  return fd_source->pollfd.revents != 0;
 }
 
 static gboolean
@@ -109,43 +70,81 @@ fd_source_dispatch (GSource     *source,
   GFDSourceFunc func = (GFDSourceFunc)callback;
   FDSource *fd_source = (FDSource *)source;
 
-  g_assert (func != NULL);
+  g_warn_if_fail (func != NULL);
 
-  return (*func) (user_data, fd_source->pollfd.revents, fd_source->pollfd.fd);
+  return (*func) (fd_source->pollfd.fd, fd_source->pollfd.revents, user_data);
 }
 
 static void 
 fd_source_finalize (GSource *source)
 {
-  FDSource *fd_source = (FDSource *)source;
+}
+
+static gboolean
+fd_source_closure_callback (int           fd,
+                           GIOCondition  condition,
+                           gpointer      data)
+{
+  GClosure *closure = data;
+
+  GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
+  GValue result_value = G_VALUE_INIT;
+  gboolean result;
+
+  g_value_init (&result_value, G_TYPE_BOOLEAN);
+
+  g_value_init (&params[0], G_TYPE_INT);
+  g_value_set_int (&params[0], fd);
+
+  g_value_init (&params[1], G_TYPE_IO_CONDITION);
+  g_value_set_flags (&params[1], condition);
+
+  g_closure_invoke (closure, &result_value, 2, params, NULL);
 
-  if (fd_source->cancelled_tag)
-    g_signal_handler_disconnect (fd_source->cancellable,
-                                fd_source->cancelled_tag);
+  result = g_value_get_boolean (&result_value);
+  g_value_unset (&result_value);
+  g_value_unset (&params[0]);
+  g_value_unset (&params[1]);
 
-  if (fd_source->cancellable)
-    g_object_unref (fd_source->cancellable);
+  return result;
+}
+
+static void
+fd_source_closure_marshal (GClosure     *closure,
+                          GValue       *return_value,
+                          guint         n_param_values,
+                          const GValue *param_values,
+                          gpointer      invocation_hint,
+                          gpointer      marshal_data)
+{
+  GFDSourceFunc callback;
+  GCClosure *cc = (GCClosure*) closure;
+  gboolean v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 0);
+
+  callback = (GFDSourceFunc) (marshal_data ? marshal_data : cc->callback);
+
+  v_return = callback (g_value_get_int (param_values),
+                       g_value_get_flags (param_values + 1),
+                      closure->data);
+
+  g_value_set_boolean (return_value, v_return);
 }
 
 static GSourceFuncs fd_source_funcs = {
   fd_source_prepare,
   fd_source_check,
   fd_source_dispatch,
-  fd_source_finalize
+  fd_source_finalize,
+  (GSourceFunc)fd_source_closure_callback,
+  (GSourceDummyMarshal)fd_source_closure_marshal,
 };
 
-/* Might be called on another thread */
-static void
-fd_source_cancelled_cb (GCancellable *cancellable,
-                       gpointer data)
-{
-  /* Wake up the mainloop in case we're waiting on async calls with FDSource */
-  g_main_context_wakeup (NULL);
-}
-
 GSource *
-_g_fd_source_new (int fd,
-                 gushort events,
+_g_fd_source_new (int           fd,
+                 gushort       events,
                  GCancellable *cancellable)
 {
   GSource *source;
@@ -154,19 +153,46 @@ _g_fd_source_new (int fd,
   source = g_source_new (&fd_source_funcs, sizeof (FDSource));
   fd_source = (FDSource *)source;
 
-  if (cancellable)
-    fd_source->cancellable = g_object_ref (cancellable);
-  
   fd_source->pollfd.fd = fd;
   fd_source->pollfd.events = events;
   g_source_add_poll (source, &fd_source->pollfd);
 
   if (cancellable)
-    fd_source->cancelled_tag =
-      g_signal_connect_data (cancellable, "cancelled",
-                            (GCallback)fd_source_cancelled_cb,
-                            NULL, NULL,
-                            0);
-  
+    {
+      GSource *cancellable_source = g_cancellable_source_new (cancellable);
+
+      g_source_set_dummy_callback (cancellable_source);
+      g_source_add_child_source (source, cancellable_source);
+      g_source_unref (cancellable_source);
+    }
+
   return source;
 }
+
+#ifdef G_OS_WIN32
+gboolean
+_g_win32_overlap_wait_result (HANDLE           hfile,
+                              OVERLAPPED      *overlap,
+                              DWORD           *transferred,
+                              GCancellable    *cancellable G_GNUC_UNUSED)
+{
+  GPollFD pollfd[1] = { 0, };
+  gboolean result = FALSE;
+  gint num, npoll;
+
+  pollfd[0].fd = (gint)overlap->hEvent;
+  pollfd[0].events = G_IO_IN;
+  num = 1;
+
+  npoll = g_poll (pollfd, num, -1);
+  if (npoll <= 0)
+    /* error out, should never happen */
+    goto end;
+
+  /* either cancelled or IO completed, either way get the result */
+  result = GetOverlappedResult (overlap->hEvent, overlap, transferred, TRUE);
+
+end:
+  return result;
+}
+#endif