#59544 Provide closure support for GMain



Here's a patch that adds g_source_set_closure() without moving GMain into libgobject.

I was able to do it quite transparently. The only public ugly parts are:

 * g_source_set_closure() is in -lgobject.

 * GSourceFuncs now has:

    GSourceDummyMarshal closure_marshal; /* Really is of type GClosureMarshal */

   The idea being that if you want closure support for your custom
   closure, you need to link to -lgobject and fill this in. (There is
   a bit of magic in gsourceclosure.c to deal with the GLib builtin
   source types.)

 * I needed to define GTypes for two GLib types in gobject ... GIOChannel
   and GIOCondition. 

There wouldn't be any real additional benefits from moving GMain into 
libgobject, but it would require people to link in -lgobject and call
g_type_init() when using the main loop.

If we wanted more integration, I would argue that GIOChannel, GSource,
GMainContext, GMarkup, should all be GObject types, and the best
approach would simply be to combine -lgobject and -lglib into a single
library. But that clearly isn't something we can do at this point.

I'd appreciate it if you would check over the closure handling in this patch;
gsignal.c isn't exactly a nice simple example.

Other things to note about the patch:

 - GIOCondition is done by hand rather than with glib-mkenums, since 
   it didn't seem worth it to set up glib-mkenums for one flags enumeration,
   and extracting one enumeration out of GLib would have been troublesome
   anyways.

 - There is a hand-written C marshaler for timeouts/idles, since glib-genmarshal
   can't deal with a marshaler without an identifiable instance. I did use
   glib-genmarshal for IO watches, since it seemed to work to treat the
   GIOChannel as the instance (even though it is a boxed type).

Regards,
                                        Owen

? glib/ghash.S
? tests/timeloop-closure
Index: docs/reference/glib/tmpl/main.sgml
===================================================================
RCS file: /cvs/gnome/glib/docs/reference/glib/tmpl/main.sgml,v
retrieving revision 1.13
diff -u -u -r1.13 main.sgml
--- docs/reference/glib/tmpl/main.sgml	2001/07/19 16:11:15	1.13
+++ docs/reference/glib/tmpl/main.sgml	2001/08/27 14:08:37
@@ -636,6 +636,8 @@
 @check: 
 @dispatch: 
 @finalize: 
+ closure_callback: 
+ closure_marshal: 
 
 <!-- ##### STRUCT GSourceCallbackFuncs ##### -->
 <para>
Index: glib/giochannel.h
===================================================================
RCS file: /cvs/gnome/glib/glib/giochannel.h,v
retrieving revision 1.13
diff -u -u -r1.13 giochannel.h
--- glib/giochannel.h	2001/08/23 15:24:35	1.13
+++ glib/giochannel.h	2001/08/27 14:08:37
@@ -284,6 +284,10 @@
 GIOChannel* g_io_channel_unix_new    (int         fd);
 gint        g_io_channel_unix_get_fd (GIOChannel *channel);
 
+
+/* Hook for GClosure / GSource integration. Don't touch */
+GLIB_VAR GSourceFuncs g_io_watch_funcs;
+
 #ifdef G_OS_WIN32
 
 #define G_WIN32_MSG_HANDLE 19981206
Index: glib/giounix.c
===================================================================
RCS file: /cvs/gnome/glib/glib/giounix.c,v
retrieving revision 1.20
diff -u -u -r1.20 giounix.c
--- glib/giounix.c	2001/08/16 23:50:13	1.20
+++ glib/giounix.c	2001/08/27 14:08:37
@@ -95,7 +95,7 @@
 				    gpointer     user_data);
 static void     g_io_unix_finalize (GSource     *source);
 
-GSourceFuncs unix_watch_funcs = {
+GSourceFuncs g_io_watch_funcs = {
   g_io_unix_prepare,
   g_io_unix_check,
   g_io_unix_dispatch,
@@ -324,7 +324,7 @@
   GIOUnixWatch *watch;
 
 
-  source = g_source_new (&unix_watch_funcs, sizeof (GIOUnixWatch));
+  source = g_source_new (&g_io_watch_funcs, sizeof (GIOUnixWatch));
   watch = (GIOUnixWatch *)source;
   
   watch->channel = channel;
Index: glib/giowin32.c
===================================================================
RCS file: /cvs/gnome/glib/glib/giowin32.c,v
retrieving revision 1.31
diff -u -u -r1.31 giowin32.c
--- glib/giowin32.c	2001/07/22 21:15:22	1.31
+++ glib/giowin32.c	2001/08/27 14:08:37
@@ -595,7 +595,7 @@
   g_io_channel_unref (watch->channel);
 }
 
-static GSourceFuncs win32_watch_funcs = {
+GSourceFuncs g_io_watch_funcs = {
   g_io_win32_prepare,
   g_io_win32_check,
   g_io_win32_dispatch,
@@ -611,7 +611,7 @@
   GIOWin32Watch *watch;
   GSource *source;
 
-  source = g_source_new (&win32_watch_funcs, sizeof (GIOWin32Watch));
+  source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
   watch = (GIOWin32Watch *)source;
   
   watch->channel = channel;
Index: glib/glib-object.h
===================================================================
RCS file: /cvs/gnome/glib/glib/glib-object.h,v
retrieving revision 1.6
diff -u -u -r1.6 glib-object.h
--- glib/glib-object.h	2001/03/07 14:46:41	1.6
+++ glib/glib-object.h	2001/08/27 14:08:37
@@ -27,6 +27,7 @@
 #include	<gobject/gparam.h>
 #include	<gobject/gparamspecs.h>
 #include	<gobject/gsignal.h>
+#include	<gobject/gsourceclosure.h>
 #include	<gobject/gtype.h>
 #include	<gobject/gtypemodule.h>
 #include	<gobject/gtypeplugin.h>
Index: glib/gmain.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gmain.c,v
retrieving revision 1.65
diff -u -u -r1.65 gmain.c
--- glib/gmain.c	2001/08/20 01:37:50	1.65
+++ glib/gmain.c	2001/08/27 14:08:37
@@ -220,7 +220,7 @@
 G_LOCK_DEFINE_STATIC (main_loop);
 static GMainContext *default_main_context;
 
-static GSourceFuncs timeout_funcs =
+GSourceFuncs g_timeout_funcs =
 {
   g_timeout_prepare,
   g_timeout_check,
@@ -228,7 +228,7 @@
   NULL
 };
 
-static GSourceFuncs idle_funcs =
+GSourceFuncs g_idle_funcs =
 {
   g_idle_prepare,
   g_idle_check,
@@ -1057,6 +1057,7 @@
 
 static void
 g_source_callback_get (gpointer     cb_data,
+		       GSource     *source, 
 		       GSourceFunc *func,
 		       gpointer    *data)
 {
@@ -1588,7 +1589,7 @@
 	  UNLOCK_CONTEXT (context);
 
 	  if (cb_funcs)
-	    cb_funcs->get (cb_data, &callback, &user_data);
+	    cb_funcs->get (cb_data, source, &callback, &user_data);
 
 	  need_destroy = ! dispatch (source,
 				     callback,
@@ -2972,7 +2973,7 @@
 GSource *
 g_timeout_source_new (guint interval)
 {
-  GSource *source = g_source_new (&timeout_funcs, sizeof (GTimeoutSource));
+  GSource *source = g_source_new (&g_timeout_funcs, sizeof (GTimeoutSource));
   GTimeoutSource *timeout_source = (GTimeoutSource *)source;
   GTimeVal current_time;
 
@@ -3110,7 +3111,7 @@
 GSource *
 g_idle_source_new (void)
 {
-  return g_source_new (&idle_funcs, sizeof (GSource));
+  return g_source_new (&g_idle_funcs, sizeof (GSource));
 }
 
 /**
@@ -3181,6 +3182,6 @@
 gboolean
 g_idle_remove_by_data (gpointer data)
 {
-  return g_source_remove_by_funcs_user_data (&idle_funcs, data);
+  return g_source_remove_by_funcs_user_data (&g_idle_funcs, data);
 }
 
Index: glib/gmain.h
===================================================================
RCS file: /cvs/gnome/glib/glib/gmain.h,v
retrieving revision 1.11
diff -u -u -r1.11 gmain.h
--- glib/gmain.h	2001/06/30 20:06:16	1.11
+++ glib/gmain.h	2001/08/27 14:08:37
@@ -59,10 +59,13 @@
   void (*ref)   (gpointer     cb_data);
   void (*unref) (gpointer     cb_data);
   void (*get)   (gpointer     cb_data,
+		 GSource     *source, 
 		 GSourceFunc *func,
 		 gpointer    *data);
 };
 
+typedef void (*GSourceDummyMarshal) (void);
+
 struct _GSourceFuncs
 {
   gboolean (*prepare)  (GSource    *source,
@@ -72,6 +75,10 @@
 			GSourceFunc callback,
 			gpointer    user_data);
   void     (*finalize) (GSource    *source); /* Can be NULL */
+
+  /* For use by g_source_set_closure */
+  GSourceFunc     closure_callback;	   
+  GSourceDummyMarshal closure_marshal; /* Really is of type GClosureMarshal */
 };
 
 /* Any definitions using GPollFD or GPollFunc are primarily
@@ -285,6 +292,10 @@
 					 gpointer	data,
 					 GDestroyNotify notify);
 gboolean	g_idle_remove_by_data	(gpointer	data);
+
+/* Hook for GClosure / GSource integration. Don't touch */
+GLIB_VAR GSourceFuncs g_timeout_funcs;
+GLIB_VAR GSourceFuncs g_idle_funcs;
 
 #ifdef G_OS_WIN32
 
Index: gobject/Makefile.am
===================================================================
RCS file: /cvs/gnome/glib/gobject/Makefile.am,v
retrieving revision 1.36
diff -u -u -r1.36 Makefile.am
--- gobject/Makefile.am	2001/06/26 16:01:18	1.36
+++ gobject/Makefile.am	2001/08/27 14:08:37
@@ -46,6 +46,7 @@
 	gparam.h		\
 	gparamspecs.h		\
 	gsignal.h		\
+	gsourceclosure.h	\
 	gtype.h			\
 	gtypemodule.h		\
 	gtypeplugin.h		\
@@ -68,6 +69,7 @@
 	gparam.c		\
 	gparamspecs.c		\
 	gsignal.c		\
+	gsourceclosure.c	\
 	gtype.c			\
 	gtypemodule.c		\
 	gtypeplugin.c		\
Index: gobject/gmarshal.list
===================================================================
RCS file: /cvs/gnome/glib/gobject/gmarshal.list,v
retrieving revision 1.3
diff -u -u -r1.3 gmarshal.list
--- gobject/gmarshal.list	2001/03/09 14:02:30	1.3
+++ gobject/gmarshal.list	2001/08/27 14:08:37
@@ -44,3 +44,4 @@
 
 # GRuntime specific marshallers
 VOID:UINT,POINTER
+BOOL:FLAGS
Index: gobject/gsourceclosure.c
===================================================================
RCS file: gsourceclosure.c
diff -N gsourceclosure.c
--- /dev/null	Tue May  5 16:32:27 1998
+++ gsourceclosure.c	Mon Aug 27 10:08:37 2001
@@ -0,0 +1,201 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2001 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gsourceclosure.h"
+#include "gboxed.h"
+#include "genums.h"
+#include "gmarshal.h"
+#include "gvalue.h"
+#include "gvaluetypes.h"
+
+GType
+g_io_channel_get_type (void)
+{
+  static GType our_type = 0;
+  
+  if (our_type == 0)
+    our_type = g_boxed_type_register_static ("GIOChannel",
+					     NULL,
+					     (GBoxedCopyFunc) g_io_channel_ref,
+					     (GBoxedFreeFunc) g_io_channel_unref,
+					     FALSE);
+
+  return our_type;
+}
+
+GType
+g_io_condition_get_type (void)
+{
+  static GType etype = 0;
+  if (etype == 0)
+    {
+      static const GFlagsValue values[] = {
+	{ G_IO_IN,   "G_IO_IN",   "in" },
+	{ G_IO_OUT,  "G_IO_OUT",  "out" },
+	{ G_IO_PRI,  "G_IO_PRI",  "pri" },
+	{ G_IO_ERR,  "G_IO_ERR",  "err" },
+	{ G_IO_HUP,  "G_IO_HUP",  "hup" },
+	{ G_IO_NVAL, "G_IO_NVAL", "nval" },
+	{ 0, NULL, NULL }
+      };
+      etype = g_flags_register_static ("GIOCondition", values);
+    }
+  return etype;
+}
+
+/* We need to hand-write this marshaler, since it doesn't have an
+ * instance object.
+ */
+void
+source_closure_marshal_BOOLEAN__VOID (GClosure     *closure,
+				      GValue       *return_value,
+				      guint         n_param_values,
+				      const GValue *param_values,
+				      gpointer      invocation_hint,
+				      gpointer      marshal_data)
+{
+  GSourceFunc callback;
+  GCClosure *cc = (GCClosure*) closure;
+  gboolean v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 0);
+
+  callback = (GSourceFunc) (marshal_data ? marshal_data : cc->callback);
+
+  v_return = callback (closure->data);
+
+  g_value_set_boolean (return_value, v_return);
+}
+
+gboolean
+io_watch_closure_callback (GIOChannel   *channel,
+			   GIOCondition  condition,
+			   gpointer      data)
+{
+  GClosure *closure = data;
+
+  GValue params[2] = { { 0, }, { 0, } };
+  GValue result_value = { 0, };
+  gboolean result;
+
+  g_value_init (&result_value, G_TYPE_BOOLEAN);
+  g_value_init (&params[0], G_TYPE_IO_CHANNEL);
+  g_value_set_boxed (&params[0], channel);
+		     
+  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);
+
+  result = g_value_get_boolean (&result_value);
+  g_value_unset (&result_value);
+  g_value_unset (&params[0]);
+  g_value_unset (&params[1]);
+
+  return result;
+}
+
+gboolean
+source_closure_callback (gpointer data)
+{
+  GClosure *closure = data;
+  GValue result_value = { 0, };
+  gboolean result;
+
+  g_value_init (&result_value, G_TYPE_BOOLEAN);
+  
+  g_closure_invoke (closure, &result_value, 0, NULL, NULL);
+
+  result = g_value_get_boolean (&result_value);
+  g_value_unset (&result_value);
+
+  return result;
+}
+
+static void
+closure_callback_get (gpointer     cb_data,
+		      GSource     *source,
+		      GSourceFunc *func,
+		      gpointer    *data)
+{
+  GSourceFunc closure_callback = source->source_funcs->closure_callback;
+
+  if (!closure_callback)
+    {
+      if (source->source_funcs == &g_io_watch_funcs)
+	closure_callback = (GSourceFunc)io_watch_closure_callback;
+      else if (source->source_funcs == &g_timeout_funcs ||
+	       source->source_funcs == &g_idle_funcs)
+	closure_callback = source_closure_callback;
+    }
+
+  *func = closure_callback;
+  *data = cb_data;
+}
+
+GSourceCallbackFuncs closure_callback_funcs = {
+  (void (*) (gpointer)) g_closure_ref,
+  (void (*) (gpointer)) g_closure_unref,
+  closure_callback_get
+};
+
+/**
+ * g_source_set_callback:
+ * @source: the source
+ * @func: a #GClosure
+ *
+ * Set the callback for a source as a #GClosure.
+ *
+ * If the source is not one of the standard GLib types, the closure_callback
+ * and closure_marshal fields of the GSourceFuncs structure must have been
+ * filled in with pointers to appropriate functions.
+ **/
+void
+g_source_set_closure (GSource  *source,
+		      GClosure *closure)
+{
+  if (!source->source_funcs->closure_callback &&
+      source->source_funcs != &g_io_watch_funcs &&
+      source->source_funcs != &g_timeout_funcs &&
+      source->source_funcs != &g_idle_funcs)
+    {
+      g_critical (G_STRLOC "closure can not be set on closure without GSourceFuncs::closure_callback\n");
+      return;
+    }
+
+  g_closure_ref (closure);
+  g_closure_sink (closure);
+  g_source_set_callback_indirect (source, closure, &closure_callback_funcs);
+
+  if (G_CLOSURE_NEEDS_MARSHAL (closure))
+    {
+      GClosureMarshal marshal = (GClosureMarshal)source->source_funcs->closure_marshal;
+      if (!marshal)
+	{
+	  if (source->source_funcs == &g_idle_funcs ||
+	      source->source_funcs == &g_timeout_funcs)
+	    marshal = source_closure_marshal_BOOLEAN__VOID;
+	  else if (source->source_funcs == &g_io_watch_funcs)
+	    marshal = g_cclosure_marshal_BOOLEAN__FLAGS;
+	}
+      if (marshal)
+	g_closure_set_marshal (closure, marshal);
+    }
+}
Index: gobject/gsourceclosure.h
===================================================================
RCS file: gsourceclosure.h
diff -N gsourceclosure.h
--- /dev/null	Tue May  5 16:32:27 1998
+++ gsourceclosure.h	Mon Aug 27 10:08:37 2001
@@ -0,0 +1,37 @@
+/* GObject - GLib Type, Object, Parameter and Signal Library
+ * Copyright (C) 2001 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __G_SOURCECLOSURE_H__
+
+#include <gobject/gclosure.h>
+
+G_BEGIN_DECLS
+
+void g_source_set_closure (GSource  *source,
+			   GClosure *closure);
+
+GType g_io_channel_get_type   (void);
+GType g_io_condition_get_type (void);
+
+#define G_TYPE_IO_CHANNEL (g_io_channel_get_type ())
+#define G_TYPE_IO_CONDITION (g_io_condition_get_type ())
+
+G_END_DECLS
+
+#endif /* __G_SOURCECLOSURE_H__ */
Index: tests/Makefile.am
===================================================================
RCS file: /cvs/gnome/glib/tests/Makefile.am,v
retrieving revision 1.41
diff -u -u -r1.41 Makefile.am
--- tests/Makefile.am	2001/08/12 14:12:02	1.41
+++ tests/Makefile.am	2001/08/27 14:08:37
@@ -37,7 +37,7 @@
 endif
 
 if ENABLE_TIMELOOP
-timeloop = timeloop
+timeloop = timeloop timeloop-closure
 endif
 noinst_PROGRAMS = testglib testgdate testgdateparser unicode-normalize unicode-collate $(timeloop)
 testglib_LDADD = $(libglib)
@@ -47,6 +47,7 @@
 unicode_collate_LDADD = $(libglib)
 if ENABLE_TIMELOOP
 timeloop_LDADD = $(libglib)
+timeloop_closure_LDADD = $(libglib) $(libgobject)
 endif
 
 test_programs =					\
Index: tests/timeloop-closure.c
===================================================================
RCS file: timeloop-closure.c
diff -N timeloop-closure.c
--- /dev/null	Tue May  5 16:32:27 1998
+++ timeloop-closure.c	Mon Aug 27 10:08:37 2001
@@ -0,0 +1,219 @@
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#include <glib.h>
+#include <glib-object.h>
+
+static int n_children = 3;
+static int n_active_children;
+static int n_iters = 10000;
+static GMainLoop *loop;
+
+static void
+io_pipe (GIOChannel **channels)
+{
+  int fds[2];
+
+  if (pipe(fds) < 0)
+    {
+      fprintf (stderr, "Cannot create pipe %s\n", g_strerror (errno));
+      exit (1);
+    }
+
+  channels[0] = g_io_channel_unix_new (fds[0]);
+  channels[1] = g_io_channel_unix_new (fds[1]);
+}
+
+static gboolean
+read_all (GIOChannel *channel, char *buf, int len)
+{
+  gsize bytes_read = 0;
+  gsize count;
+  GIOError err;
+
+  while (bytes_read < len)
+    {
+      err = g_io_channel_read (channel, buf + bytes_read, len - bytes_read, &count);
+      if (err)
+	{
+	  if (err != G_IO_ERROR_AGAIN)
+	    return FALSE;
+	}
+      else if (count == 0)
+	return FALSE;
+
+      bytes_read += count;
+    }
+
+  return TRUE;
+}
+
+static gboolean
+write_all (GIOChannel *channel, char *buf, int len)
+{
+  gsize bytes_written = 0;
+  gsize count;
+  GIOError err;
+
+  while (bytes_written < len)
+    {
+      err = g_io_channel_write (channel, buf + bytes_written, len - bytes_written, &count);
+      if (err && err != G_IO_ERROR_AGAIN)
+	return FALSE;
+
+      bytes_written += count;
+    }
+
+  return TRUE;
+}
+
+static void
+run_child (GIOChannel *in_channel, GIOChannel *out_channel)
+{
+  int i;
+  int val = 1;
+  GTimer *timer = g_timer_new();
+
+  for (i = 0; i < n_iters; i++)
+    {
+      write_all (out_channel, (char *)&val, sizeof (val));
+      read_all (in_channel, (char *)&val, sizeof (val));
+    }
+
+  val = 0;
+  write_all (out_channel, (char *)&val, sizeof (val));
+
+  val = g_timer_elapsed (timer, NULL) * 1000;
+  
+  write_all (out_channel, (char *)&val, sizeof (val));
+  g_timer_destroy (timer);
+
+  exit (0);
+}
+
+static gboolean
+input_callback (GIOChannel   *source,
+		GIOCondition  condition,
+		gpointer      data)
+{
+  int val;
+  GIOChannel *dest = (GIOChannel *)data;
+  
+  if (!read_all (source, (char *)&val, sizeof(val)))
+    {
+      fprintf (stderr, "Unexpected EOF\n");
+      exit (1);
+    }
+
+  if (val)
+    {
+      write_all (dest, (char *)&val, sizeof(val));
+      
+      return TRUE;
+    }
+  else
+    {
+      g_io_channel_close (source);
+      g_io_channel_close (dest);
+      
+      g_io_channel_unref (source);
+      g_io_channel_unref (dest);
+
+      n_active_children--;
+      if (n_active_children == 0)
+	g_main_loop_quit (loop);
+      
+      return FALSE;
+    }
+}
+
+static void
+create_child ()
+{
+  int pid;
+  GIOChannel *in_channels[2];
+  GIOChannel *out_channels[2];
+  GSource *source;
+  
+  io_pipe (in_channels);
+  io_pipe (out_channels);
+
+  pid = fork ();
+
+  if (pid > 0)			/* Parent */
+    {
+      g_io_channel_close (in_channels[0]);
+      g_io_channel_close (out_channels[1]);
+
+      source = g_io_create_watch (out_channels[0], G_IO_IN | G_IO_HUP);
+      g_source_set_closure (source,
+			    g_cclosure_new (G_CALLBACK (input_callback), in_channels[1], NULL));
+      g_source_attach (source, NULL);
+    }
+  else if (pid == 0)		/* Child */
+    {
+      g_io_channel_close (in_channels[1]);
+      g_io_channel_close (out_channels[0]);
+
+      setsid ();
+
+      run_child (in_channels[0], out_channels[1]);
+    }
+  else				/* Error */
+    {
+      fprintf (stderr, "Cannot fork: %s\n", g_strerror (errno));
+      exit (1);
+    }
+}
+
+static double 
+difftimeval (struct timeval *old, struct timeval *new)
+{
+  return
+    (new->tv_sec - old->tv_sec) * 1000. + (new->tv_usec - old->tv_usec) / 1000;
+}
+
+int 
+main (int argc, char **argv)
+{
+  int i;
+  struct rusage old_usage;
+  struct rusage new_usage;
+
+  g_type_init ();
+  
+  if (argc > 1)
+    n_children = atoi(argv[1]);
+
+  if (argc > 2)
+    n_iters = atoi(argv[2]);
+
+  printf ("Children: %d     Iters: %d\n", n_children, n_iters);
+
+  n_active_children = n_children;
+  for (i = 0; i < n_children; i++)
+    create_child ();
+
+  getrusage (RUSAGE_SELF, &old_usage);
+  loop = g_main_loop_new (NULL, FALSE);
+  g_main_loop_run (loop);
+  getrusage (RUSAGE_SELF, &new_usage);
+
+  printf ("Elapsed user: %g\n",
+	  difftimeval (&old_usage.ru_utime, &new_usage.ru_utime));
+  printf ("Elapsed system: %g\n",
+	  difftimeval (&old_usage.ru_stime, &new_usage.ru_stime));
+  printf ("Elapsed total: %g\n",
+	  difftimeval (&old_usage.ru_utime, &new_usage.ru_utime) +	   
+	  difftimeval (&old_usage.ru_stime, &new_usage.ru_stime));
+  printf ("total / iteration: %g\n",
+	  (difftimeval (&old_usage.ru_utime, &new_usage.ru_utime) +	   
+	   difftimeval (&old_usage.ru_stime, &new_usage.ru_stime)) /
+	  (n_iters * n_children));
+
+  return 0;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]