Major change in API for creating sources to handle multiple main loops

Tue Dec  5 12:23:04 2000  Owen Taylor  <otaylor@redhat.com>

        * gmain.[hc]: Major change in API for creating sources
	to handle multiple main loops (GMainContext *).

	GSources are now exposed as GSource * and implemented
	with structure derivation.

	* giochannel.[ch]: Changed vtable for GIOChannel to correspond
	to the new mainloop API, add g_io_channel_create_watch().

	* gtypes.h: Move GTimeVal here.

	* gthread.h: Remove gmain.h include to avoid circularity.

        * giounix.c: Update for new GMain API.

	* giowin32.c: Update for new GMain API. (No check for
	proper compilation or working.)

	* timeloop.c timeloop-basic.c: A benchmarking program for
	the main loop comparing the main loop against a
	hand-written (timeloop-basic.c) variant.

	* tests/mainloop-test.c: New torture test of mainloop.

	* docs/Changes-2.0.txt: Started. Added text about
	changes to GMain.

	* gmain.c (g_main_add_poll_unlocked): Initial fd->revents
	to zero. (#8482, Benjamin Kahn)
This commit is contained in:
Owen Taylor 2000-12-05 20:45:33 +00:00 committed by Owen Taylor
parent 5791ec5b85
commit e2fd4e2bd0
37 changed files with 6441 additions and 1940 deletions

View File

@ -28,6 +28,8 @@ stamp-h.in
testgdate testgdate
testgdateparser testgdateparser
testglib testglib
timeloop
timeloop-basic
annotations annotations
logs logs
glib.rc glib.rc

View File

@ -1,3 +1,35 @@
Tue Dec 5 12:23:04 2000 Owen Taylor <otaylor@redhat.com>
* gmain.[hc]: Major change in API for creating sources
to handle multiple main loops (GMainContext *).
GSources are now exposed as GSource * and implemented
with structure derivation.
* giochannel.[ch]: Changed vtable for GIOChannel to correspond
to the new mainloop API, add g_io_channel_create_watch().
* gtypes.h: Move GTimeVal here.
* gthread.h: Remove gmain.h include to avoid circularity.
* giounix.c: Update for new GMain API.
* giowin32.c: Update for new GMain API. (No check for
proper compilation or working.)
* timeloop.c timeloop-basic.c: A benchmarking program for
the main loop comparing the main loop against a
hand-written (timeloop-basic.c) variant.
* tests/mainloop-test.c: New torture test of mainloop.
* docs/Changes-2.0.txt: Started. Added text about
changes to GMain.
* gmain.c (g_main_add_poll_unlocked): Initial fd->revents
to zero. (#8482, Benjamin Kahn)
2000-12-01 Tor Lillqvist <tml@iki.fi> 2000-12-01 Tor Lillqvist <tml@iki.fi>
* {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir. * {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir.

View File

@ -1,3 +1,35 @@
Tue Dec 5 12:23:04 2000 Owen Taylor <otaylor@redhat.com>
* gmain.[hc]: Major change in API for creating sources
to handle multiple main loops (GMainContext *).
GSources are now exposed as GSource * and implemented
with structure derivation.
* giochannel.[ch]: Changed vtable for GIOChannel to correspond
to the new mainloop API, add g_io_channel_create_watch().
* gtypes.h: Move GTimeVal here.
* gthread.h: Remove gmain.h include to avoid circularity.
* giounix.c: Update for new GMain API.
* giowin32.c: Update for new GMain API. (No check for
proper compilation or working.)
* timeloop.c timeloop-basic.c: A benchmarking program for
the main loop comparing the main loop against a
hand-written (timeloop-basic.c) variant.
* tests/mainloop-test.c: New torture test of mainloop.
* docs/Changes-2.0.txt: Started. Added text about
changes to GMain.
* gmain.c (g_main_add_poll_unlocked): Initial fd->revents
to zero. (#8482, Benjamin Kahn)
2000-12-01 Tor Lillqvist <tml@iki.fi> 2000-12-01 Tor Lillqvist <tml@iki.fi>
* {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir. * {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir.

View File

@ -1,3 +1,35 @@
Tue Dec 5 12:23:04 2000 Owen Taylor <otaylor@redhat.com>
* gmain.[hc]: Major change in API for creating sources
to handle multiple main loops (GMainContext *).
GSources are now exposed as GSource * and implemented
with structure derivation.
* giochannel.[ch]: Changed vtable for GIOChannel to correspond
to the new mainloop API, add g_io_channel_create_watch().
* gtypes.h: Move GTimeVal here.
* gthread.h: Remove gmain.h include to avoid circularity.
* giounix.c: Update for new GMain API.
* giowin32.c: Update for new GMain API. (No check for
proper compilation or working.)
* timeloop.c timeloop-basic.c: A benchmarking program for
the main loop comparing the main loop against a
hand-written (timeloop-basic.c) variant.
* tests/mainloop-test.c: New torture test of mainloop.
* docs/Changes-2.0.txt: Started. Added text about
changes to GMain.
* gmain.c (g_main_add_poll_unlocked): Initial fd->revents
to zero. (#8482, Benjamin Kahn)
2000-12-01 Tor Lillqvist <tml@iki.fi> 2000-12-01 Tor Lillqvist <tml@iki.fi>
* {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir. * {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir.

View File

@ -1,3 +1,35 @@
Tue Dec 5 12:23:04 2000 Owen Taylor <otaylor@redhat.com>
* gmain.[hc]: Major change in API for creating sources
to handle multiple main loops (GMainContext *).
GSources are now exposed as GSource * and implemented
with structure derivation.
* giochannel.[ch]: Changed vtable for GIOChannel to correspond
to the new mainloop API, add g_io_channel_create_watch().
* gtypes.h: Move GTimeVal here.
* gthread.h: Remove gmain.h include to avoid circularity.
* giounix.c: Update for new GMain API.
* giowin32.c: Update for new GMain API. (No check for
proper compilation or working.)
* timeloop.c timeloop-basic.c: A benchmarking program for
the main loop comparing the main loop against a
hand-written (timeloop-basic.c) variant.
* tests/mainloop-test.c: New torture test of mainloop.
* docs/Changes-2.0.txt: Started. Added text about
changes to GMain.
* gmain.c (g_main_add_poll_unlocked): Initial fd->revents
to zero. (#8482, Benjamin Kahn)
2000-12-01 Tor Lillqvist <tml@iki.fi> 2000-12-01 Tor Lillqvist <tml@iki.fi>
* {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir. * {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir.

View File

@ -1,3 +1,35 @@
Tue Dec 5 12:23:04 2000 Owen Taylor <otaylor@redhat.com>
* gmain.[hc]: Major change in API for creating sources
to handle multiple main loops (GMainContext *).
GSources are now exposed as GSource * and implemented
with structure derivation.
* giochannel.[ch]: Changed vtable for GIOChannel to correspond
to the new mainloop API, add g_io_channel_create_watch().
* gtypes.h: Move GTimeVal here.
* gthread.h: Remove gmain.h include to avoid circularity.
* giounix.c: Update for new GMain API.
* giowin32.c: Update for new GMain API. (No check for
proper compilation or working.)
* timeloop.c timeloop-basic.c: A benchmarking program for
the main loop comparing the main loop against a
hand-written (timeloop-basic.c) variant.
* tests/mainloop-test.c: New torture test of mainloop.
* docs/Changes-2.0.txt: Started. Added text about
changes to GMain.
* gmain.c (g_main_add_poll_unlocked): Initial fd->revents
to zero. (#8482, Benjamin Kahn)
2000-12-01 Tor Lillqvist <tml@iki.fi> 2000-12-01 Tor Lillqvist <tml@iki.fi>
* {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir. * {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir.

View File

@ -1,3 +1,35 @@
Tue Dec 5 12:23:04 2000 Owen Taylor <otaylor@redhat.com>
* gmain.[hc]: Major change in API for creating sources
to handle multiple main loops (GMainContext *).
GSources are now exposed as GSource * and implemented
with structure derivation.
* giochannel.[ch]: Changed vtable for GIOChannel to correspond
to the new mainloop API, add g_io_channel_create_watch().
* gtypes.h: Move GTimeVal here.
* gthread.h: Remove gmain.h include to avoid circularity.
* giounix.c: Update for new GMain API.
* giowin32.c: Update for new GMain API. (No check for
proper compilation or working.)
* timeloop.c timeloop-basic.c: A benchmarking program for
the main loop comparing the main loop against a
hand-written (timeloop-basic.c) variant.
* tests/mainloop-test.c: New torture test of mainloop.
* docs/Changes-2.0.txt: Started. Added text about
changes to GMain.
* gmain.c (g_main_add_poll_unlocked): Initial fd->revents
to zero. (#8482, Benjamin Kahn)
2000-12-01 Tor Lillqvist <tml@iki.fi> 2000-12-01 Tor Lillqvist <tml@iki.fi>
* {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir. * {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir.

View File

@ -1,3 +1,35 @@
Tue Dec 5 12:23:04 2000 Owen Taylor <otaylor@redhat.com>
* gmain.[hc]: Major change in API for creating sources
to handle multiple main loops (GMainContext *).
GSources are now exposed as GSource * and implemented
with structure derivation.
* giochannel.[ch]: Changed vtable for GIOChannel to correspond
to the new mainloop API, add g_io_channel_create_watch().
* gtypes.h: Move GTimeVal here.
* gthread.h: Remove gmain.h include to avoid circularity.
* giounix.c: Update for new GMain API.
* giowin32.c: Update for new GMain API. (No check for
proper compilation or working.)
* timeloop.c timeloop-basic.c: A benchmarking program for
the main loop comparing the main loop against a
hand-written (timeloop-basic.c) variant.
* tests/mainloop-test.c: New torture test of mainloop.
* docs/Changes-2.0.txt: Started. Added text about
changes to GMain.
* gmain.c (g_main_add_poll_unlocked): Initial fd->revents
to zero. (#8482, Benjamin Kahn)
2000-12-01 Tor Lillqvist <tml@iki.fi> 2000-12-01 Tor Lillqvist <tml@iki.fi>
* {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir. * {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir.

View File

@ -1,3 +1,35 @@
Tue Dec 5 12:23:04 2000 Owen Taylor <otaylor@redhat.com>
* gmain.[hc]: Major change in API for creating sources
to handle multiple main loops (GMainContext *).
GSources are now exposed as GSource * and implemented
with structure derivation.
* giochannel.[ch]: Changed vtable for GIOChannel to correspond
to the new mainloop API, add g_io_channel_create_watch().
* gtypes.h: Move GTimeVal here.
* gthread.h: Remove gmain.h include to avoid circularity.
* giounix.c: Update for new GMain API.
* giowin32.c: Update for new GMain API. (No check for
proper compilation or working.)
* timeloop.c timeloop-basic.c: A benchmarking program for
the main loop comparing the main loop against a
hand-written (timeloop-basic.c) variant.
* tests/mainloop-test.c: New torture test of mainloop.
* docs/Changes-2.0.txt: Started. Added text about
changes to GMain.
* gmain.c (g_main_add_poll_unlocked): Initial fd->revents
to zero. (#8482, Benjamin Kahn)
2000-12-01 Tor Lillqvist <tml@iki.fi> 2000-12-01 Tor Lillqvist <tml@iki.fi>
* {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir. * {.,*}/makefile.msc.in: Include make.msc from GLib's build subdir.

View File

@ -165,10 +165,11 @@ libglib_1_3_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
-export-dynamic -export-dynamic
noinst_PROGRAMS = testglib testgdate testgdateparser noinst_PROGRAMS = testglib testgdate testgdateparser timeloop
testglib_LDADD = libglib-1.3.la testglib_LDADD = libglib-1.3.la
testgdate_LDADD = libglib-1.3.la testgdate_LDADD = libglib-1.3.la
testgdateparser_LDADD = libglib-1.3.la testgdateparser_LDADD = libglib-1.3.la
timeloop_LDADD = libglib-1.3.la
m4datadir = $(datadir)/aclocal m4datadir = $(datadir)/aclocal
m4data_DATA = glib-2.0.m4 m4data_DATA = glib-2.0.m4

24
docs/Changes-2.0.txt Normal file
View File

@ -0,0 +1,24 @@
* The event loop functionality GMain has extensively been revised to
support multiple separate main loops in separate threads. All sources
(timeouts, idle functions, etc.) are associated with a GMainContext.
Compatibility functions exist so that most application code dealing with
the main loop will continue to work. However, code that creates
new custom types of sources will require modification.
The main changes here are:
- Sources are now exposed as GSource *, rather than simply as numeric
IDS.
- New types of sources are created by structure "derivation" from GSource,
so the source_data parameter to the GSource vfuncs has been
replaced with a GSource *.
- Sources are first created, then later added to a specific GMainContext
- Dispatching has been modified so both the callback and data are passed
in to the ->dispatch() vfunc.
To go along with this change, the vtable for GIOChannel has changed and
add_watch() has been replaced by create_watch().

View File

@ -27,6 +27,7 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <sys/types.h> #include <sys/types.h>

View File

@ -104,6 +104,15 @@ g_io_channel_close (GIOChannel *channel)
channel->funcs->io_close (channel); channel->funcs->io_close (channel);
} }
GSource *
g_io_create_watch (GIOChannel *channel,
GIOCondition condition)
{
g_return_val_if_fail (channel != NULL, NULL);
return channel->funcs->io_create_watch (channel, condition);
}
guint guint
g_io_add_watch_full (GIOChannel *channel, g_io_add_watch_full (GIOChannel *channel,
gint priority, gint priority,
@ -112,10 +121,17 @@ g_io_add_watch_full (GIOChannel *channel,
gpointer user_data, gpointer user_data,
GDestroyNotify notify) GDestroyNotify notify)
{ {
GSource *source;
g_return_val_if_fail (channel != NULL, 0); g_return_val_if_fail (channel != NULL, 0);
return channel->funcs->io_add_watch (channel, priority, condition, source = g_io_create_watch (channel, condition);
func, user_data, notify);
if (priority != G_PRIORITY_DEFAULT)
g_source_set_priority (source, priority);
g_source_set_callback (source, (GSourceFunc)func, user_data, notify);
return g_source_attach (source, NULL);
} }
guint guint
@ -124,5 +140,5 @@ g_io_add_watch (GIOChannel *channel,
GIOFunc func, GIOFunc func,
gpointer user_data) gpointer user_data)
{ {
return g_io_add_watch_full (channel, 0, condition, func, user_data, NULL); return g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, condition, func, user_data, NULL);
} }

View File

@ -27,6 +27,7 @@
#ifndef __G_IOCHANNEL_H__ #ifndef __G_IOCHANNEL_H__
#define __G_IOCHANNEL_H__ #define __G_IOCHANNEL_H__
#include <gmain.h>
#include <gtypes.h> #include <gtypes.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -83,12 +84,8 @@ struct _GIOFuncs
gint offset, gint offset,
GSeekType type); GSeekType type);
void (*io_close) (GIOChannel *channel); void (*io_close) (GIOChannel *channel);
guint (*io_add_watch) (GIOChannel *channel, GSource * (*io_create_watch) (GIOChannel *channel,
gint priority, GIOCondition condition);
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify);
void (*io_free) (GIOChannel *channel); void (*io_free) (GIOChannel *channel);
}; };
@ -113,6 +110,8 @@ guint g_io_add_watch_full (GIOChannel *channel,
GIOFunc func, GIOFunc func,
gpointer user_data, gpointer user_data,
GDestroyNotify notify); GDestroyNotify notify);
GSource *g_io_create_watch (GIOChannel *channel,
GIOCondition condition);
guint g_io_add_watch (GIOChannel *channel, guint g_io_add_watch (GIOChannel *channel,
GIOCondition condition, GIOCondition condition,
GIOFunc func, GIOFunc func,

View File

@ -43,12 +43,15 @@
typedef struct _GIOUnixChannel GIOUnixChannel; typedef struct _GIOUnixChannel GIOUnixChannel;
typedef struct _GIOUnixWatch GIOUnixWatch; typedef struct _GIOUnixWatch GIOUnixWatch;
struct _GIOUnixChannel { struct _GIOUnixChannel
{
GIOChannel channel; GIOChannel channel;
gint fd; gint fd;
}; };
struct _GIOUnixWatch { struct _GIOUnixWatch
{
GSource source;
GPollFD pollfd; GPollFD pollfd;
GIOChannel *channel; GIOChannel *channel;
GIOCondition condition; GIOCondition condition;
@ -60,7 +63,6 @@ static GIOError g_io_unix_read (GIOChannel *channel,
gchar *buf, gchar *buf,
guint count, guint count,
guint *bytes_written); guint *bytes_written);
static GIOError g_io_unix_write (GIOChannel *channel, static GIOError g_io_unix_write (GIOChannel *channel,
gchar *buf, gchar *buf,
guint count, guint count,
@ -70,23 +72,16 @@ static GIOError g_io_unix_seek (GIOChannel *channel,
GSeekType type); GSeekType type);
static void g_io_unix_close (GIOChannel *channel); static void g_io_unix_close (GIOChannel *channel);
static void g_io_unix_free (GIOChannel *channel); static void g_io_unix_free (GIOChannel *channel);
static guint g_io_unix_add_watch (GIOChannel *channel, static GSource *g_io_unix_create_watch (GIOChannel *channel,
gint priority, GIOCondition condition);
GIOCondition condition,
GIOFunc func, static gboolean g_io_unix_prepare (GSource *source,
gpointer user_data, gint *timeout);
GDestroyNotify notify); static gboolean g_io_unix_check (GSource *source);
static gboolean g_io_unix_prepare (gpointer source_data, static gboolean g_io_unix_dispatch (GSource *source,
GTimeVal *current_time, GSourceFunc callback,
gint *timeout,
gpointer user_data); gpointer user_data);
static gboolean g_io_unix_check (gpointer source_data, static void g_io_unix_destroy (GSource *source);
GTimeVal *current_time,
gpointer user_data);
static gboolean g_io_unix_dispatch (gpointer source_data,
GTimeVal *current_time,
gpointer user_data);
static void g_io_unix_destroy (gpointer source_data);
GSourceFuncs unix_watch_funcs = { GSourceFuncs unix_watch_funcs = {
g_io_unix_prepare, g_io_unix_prepare,
@ -100,51 +95,53 @@ GIOFuncs unix_channel_funcs = {
g_io_unix_write, g_io_unix_write,
g_io_unix_seek, g_io_unix_seek,
g_io_unix_close, g_io_unix_close,
g_io_unix_add_watch, g_io_unix_create_watch,
g_io_unix_free, g_io_unix_free,
}; };
static gboolean static gboolean
g_io_unix_prepare (gpointer source_data, g_io_unix_prepare (GSource *source,
GTimeVal *current_time, gint *timeout)
gint *timeout,
gpointer user_data)
{ {
*timeout = -1; *timeout = -1;
return FALSE; return FALSE;
} }
static gboolean static gboolean
g_io_unix_check (gpointer source_data, g_io_unix_check (GSource *source)
GTimeVal *current_time,
gpointer user_data)
{ {
GIOUnixWatch *data = source_data; GIOUnixWatch *watch = (GIOUnixWatch *)source;
return (data->pollfd.revents & data->condition); return (watch->pollfd.revents & watch->condition);
} }
static gboolean static gboolean
g_io_unix_dispatch (gpointer source_data, g_io_unix_dispatch (GSource *source,
GTimeVal *current_time, GSourceFunc callback,
gpointer user_data) gpointer user_data)
{ {
GIOUnixWatch *data = source_data; GIOFunc func = (GIOFunc)callback;
GIOUnixWatch *watch = (GIOUnixWatch *)source;
return (*data->callback)(data->channel, if (!func)
data->pollfd.revents & data->condition, {
g_warning ("IO watch dispatched without callback\n"
"You must call g_source_connect().");
return FALSE;
}
return (*func) (watch->channel,
watch->pollfd.revents & watch->condition,
user_data); user_data);
} }
static void static void
g_io_unix_destroy (gpointer source_data) g_io_unix_destroy (GSource *source)
{ {
GIOUnixWatch *data = source_data; GIOUnixWatch *watch = (GIOUnixWatch *)source;
g_main_remove_poll (&data->pollfd); g_io_channel_unref (watch->channel);
g_io_channel_unref (data->channel);
g_free (data);
} }
static GIOError static GIOError
@ -269,29 +266,29 @@ g_io_unix_free (GIOChannel *channel)
g_free (unix_channel); g_free (unix_channel);
} }
static guint static GSource *
g_io_unix_add_watch (GIOChannel *channel, g_io_unix_create_watch (GIOChannel *channel,
gint priority, GIOCondition condition)
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify)
{ {
GIOUnixWatch *watch = g_new (GIOUnixWatch, 1);
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel; GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
GSource *source;
GIOUnixWatch *watch;
source = g_source_new (&unix_watch_funcs, sizeof (GIOUnixWatch));
watch = (GIOUnixWatch *)source;
watch->channel = channel; watch->channel = channel;
g_io_channel_ref (channel); g_io_channel_ref (channel);
watch->callback = func;
watch->condition = condition; watch->condition = condition;
watch->pollfd.fd = unix_channel->fd; watch->pollfd.fd = unix_channel->fd;
watch->pollfd.events = condition; watch->pollfd.events = condition;
g_main_add_poll (&watch->pollfd, priority); g_source_add_poll (source, &watch->pollfd);
return g_source_add (priority, TRUE, &unix_watch_funcs, watch, user_data, notify); return source;
} }
GIOChannel * GIOChannel *

View File

@ -102,6 +102,7 @@ struct _GIOWin32Channel {
#define UNLOCK(mutex) LeaveCriticalSection (&mutex) #define UNLOCK(mutex) LeaveCriticalSection (&mutex)
struct _GIOWin32Watch { struct _GIOWin32Watch {
GSource source;
GPollFD pollfd; GPollFD pollfd;
GIOChannel *channel; GIOChannel *channel;
GIOCondition condition; GIOCondition condition;
@ -319,10 +320,8 @@ buffer_read (GIOWin32Channel *channel,
} }
static gboolean static gboolean
g_io_win32_prepare (gpointer source_data, g_io_win32_prepare (GSource *source,
GTimeVal *current_time, gint *timeout)
gint *timeout,
gpointer user_data)
{ {
*timeout = -1; *timeout = -1;
@ -330,12 +329,10 @@ g_io_win32_prepare (gpointer source_data,
} }
static gboolean static gboolean
g_io_win32_check (gpointer source_data, g_io_win32_check (GSource *source)
GTimeVal *current_time,
gpointer user_data)
{ {
GIOWin32Watch *data = source_data; GIOWin32Watch *watch = (GIOWin32Watch *)source;
GIOWin32Channel *channel = (GIOWin32Channel *) data->channel; GIOWin32Channel *channel = (GIOWin32Channel *) watch->channel;
/* If the thread has died, we have encountered EOF. If the buffer /* If the thread has died, we have encountered EOF. If the buffer
* also is emtpty set the HUP bit. * also is emtpty set the HUP bit.
@ -345,34 +342,31 @@ g_io_win32_check (gpointer source_data,
if (channel->debug) if (channel->debug)
g_print ("g_io_win32_check: setting G_IO_HUP thread %#x rdp=%d wrp=%d\n", g_print ("g_io_win32_check: setting G_IO_HUP thread %#x rdp=%d wrp=%d\n",
channel->thread_id, channel->rdp, channel->wrp); channel->thread_id, channel->rdp, channel->wrp);
data->pollfd.revents |= G_IO_HUP; watch->pollfd.revents |= G_IO_HUP;
return TRUE; return TRUE;
} }
return (data->pollfd.revents & data->condition); return (watch->pollfd.revents & watch->condition);
} }
static gboolean static gboolean
g_io_win32_dispatch (gpointer source_data, g_io_win32_dispatch (GSource *source,
GTimeVal *current_time, GSourceFunc callback,
gpointer user_data) gpointer user_data)
{ {
GIOWin32Watch *data = source_data; GIOWin32Watch *watch = (GIOWin32Watch *)source;
return (*data->callback) (data->channel, return (*callback) (watch->channel,
data->pollfd.revents & data->condition, watch->pollfd.revents & watch->condition,
user_data); user_data);
} }
static void static void
g_io_win32_destroy (gpointer source_data) g_io_win32_destroy (GSource *source)
{ {
GIOWin32Watch *data = source_data; GIOWin32Watch *watch = (GIOWin32Watch *)source;
g_main_remove_poll (&data->pollfd); g_io_channel_unref (watch->channel);
g_io_channel_unref (data->channel);
g_free (data);
} }
static GSourceFuncs win32_watch_funcs = { static GSourceFuncs win32_watch_funcs = {
@ -382,22 +376,21 @@ static GSourceFuncs win32_watch_funcs = {
g_io_win32_destroy g_io_win32_destroy
}; };
static guint static GSource *
g_io_win32_add_watch (GIOChannel *channel, g_io_win32_create_watch (GIOChannel *channel,
gint priority,
GIOCondition condition, GIOCondition condition,
GIOFunc func, int (*reader) (int, guchar *, int)))
gpointer user_data,
GDestroyNotify notify,
int (*reader) (int, guchar *, int))
{ {
GIOWin32Watch *watch = g_new (GIOWin32Watch, 1);
GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel; GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
GIOWin32Watch *watch;
GSource *source;
source = g_source_new (&win32_watch_funcs, sizeof (GIOWin32Watch));
watch = (GIOWin32Watch *)source;
watch->channel = channel; watch->channel = channel;
g_io_channel_ref (channel); g_io_channel_ref (channel);
watch->callback = func;
watch->condition = condition; watch->condition = condition;
if (win32_channel->data_avail_event == NULL) if (win32_channel->data_avail_event == NULL)
@ -407,16 +400,15 @@ g_io_win32_add_watch (GIOChannel *channel,
watch->pollfd.events = condition; watch->pollfd.events = condition;
if (win32_channel->debug) if (win32_channel->debug)
g_print ("g_io_win32_add_watch: fd:%d handle:%#x\n", g_print ("g_io_win32_create_watch: fd:%d handle:%#x\n",
win32_channel->fd, watch->pollfd.fd); win32_channel->fd, watch->pollfd.fd);
if (win32_channel->thread_id == 0) if (win32_channel->thread_id == 0)
create_reader_thread (win32_channel, reader); create_reader_thread (win32_channel, reader);
g_main_add_poll (&watch->pollfd, priority); g_source_add_poll (source, &watch->pollfd);
return g_source_add (priority, TRUE, &win32_watch_funcs, watch, return source;
user_data, notify);
} }
static GIOError static GIOError
@ -490,29 +482,27 @@ g_io_win32_free (GIOChannel *channel)
g_free (win32_channel); g_free (win32_channel);
} }
static guint static GSource *
g_io_win32_msg_add_watch (GIOChannel *channel, g_io_win32_msg_create_watch (GIOChannel *channel,
gint priority, GIOCondition condition)
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify)
{ {
GIOWin32Watch *watch = g_new (GIOWin32Watch, 1); GIOWin32Watch *watch;
GSource *source;
source = g_source_new (&win32_watch_funcs, sizeof (GIOWin32Watch));
watch = (GIOWin32Watch *)source;
watch->channel = channel; watch->channel = channel;
g_io_channel_ref (channel); g_io_channel_ref (channel);
watch->callback = func;
watch->condition = condition; watch->condition = condition;
watch->pollfd.fd = G_WIN32_MSG_HANDLE; watch->pollfd.fd = G_WIN32_MSG_HANDLE;
watch->pollfd.events = condition; watch->pollfd.events = condition;
g_main_add_poll (&watch->pollfd, priority); g_source_add_poll (source, &watch->pollfd);
return g_source_add (priority, TRUE, &win32_watch_funcs, return source;
watch, user_data, notify);
} }
static GIOError static GIOError
@ -653,16 +643,11 @@ fd_reader (int fd,
return read (fd, buf, len); return read (fd, buf, len);
} }
static guint static GSource *
g_io_win32_fd_add_watch (GIOChannel *channel, g_io_win32_fd_create_watch (GIOChannel *channel,
gint priority, GIOCondition condition)
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify)
{ {
return g_io_win32_add_watch (channel, priority, condition, return g_io_win32_create_watch (channel, condition, fd_reader);
func, user_data, notify, fd_reader);
} }
static GIOError static GIOError
@ -752,16 +737,11 @@ sock_reader (int fd,
return recv (fd, buf, len, 0); return recv (fd, buf, len, 0);
} }
static guint static GSource *
g_io_win32_sock_add_watch (GIOChannel *channel, g_io_win32_sock_create_watch (GIOChannel *channel,
gint priority, GIOCondition condition)
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify)
{ {
return g_io_win32_add_watch (channel, priority, condition, return g_io_win32_add_watch (channel, condition, sock_reader);
func, user_data, notify, sock_reader);
} }
static GIOFuncs win32_channel_msg_funcs = { static GIOFuncs win32_channel_msg_funcs = {
@ -769,7 +749,7 @@ static GIOFuncs win32_channel_msg_funcs = {
g_io_win32_msg_write, g_io_win32_msg_write,
g_io_win32_no_seek, g_io_win32_no_seek,
g_io_win32_msg_close, g_io_win32_msg_close,
g_io_win32_msg_add_watch, g_io_win32_msg_create_watch,
g_io_win32_free g_io_win32_free
}; };
@ -778,7 +758,7 @@ static GIOFuncs win32_channel_fd_funcs = {
g_io_win32_fd_write, g_io_win32_fd_write,
g_io_win32_fd_seek, g_io_win32_fd_seek,
g_io_win32_fd_close, g_io_win32_fd_close,
g_io_win32_fd_add_watch, g_io_win32_fd_create_watch,
g_io_win32_free g_io_win32_free
}; };
@ -787,7 +767,7 @@ static GIOFuncs win32_channel_sock_funcs = {
g_io_win32_sock_write, g_io_win32_sock_write,
g_io_win32_no_seek, g_io_win32_no_seek,
g_io_win32_sock_close, g_io_win32_sock_close,
g_io_win32_sock_add_watch, g_io_win32_sock_create_watch,
g_io_win32_free g_io_win32_free
}; };

View File

@ -165,10 +165,11 @@ libglib_1_3_la_LDFLAGS = \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
-export-dynamic -export-dynamic
noinst_PROGRAMS = testglib testgdate testgdateparser noinst_PROGRAMS = testglib testgdate testgdateparser timeloop
testglib_LDADD = libglib-1.3.la testglib_LDADD = libglib-1.3.la
testgdate_LDADD = libglib-1.3.la testgdate_LDADD = libglib-1.3.la
testgdateparser_LDADD = libglib-1.3.la testgdateparser_LDADD = libglib-1.3.la
timeloop_LDADD = libglib-1.3.la
m4datadir = $(datadir)/aclocal m4datadir = $(datadir)/aclocal
m4data_DATA = glib-2.0.m4 m4data_DATA = glib-2.0.m4

View File

@ -27,6 +27,7 @@
#include <unistd.h> #include <unistd.h>
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <sys/types.h> #include <sys/types.h>

View File

@ -104,6 +104,15 @@ g_io_channel_close (GIOChannel *channel)
channel->funcs->io_close (channel); channel->funcs->io_close (channel);
} }
GSource *
g_io_create_watch (GIOChannel *channel,
GIOCondition condition)
{
g_return_val_if_fail (channel != NULL, NULL);
return channel->funcs->io_create_watch (channel, condition);
}
guint guint
g_io_add_watch_full (GIOChannel *channel, g_io_add_watch_full (GIOChannel *channel,
gint priority, gint priority,
@ -112,10 +121,17 @@ g_io_add_watch_full (GIOChannel *channel,
gpointer user_data, gpointer user_data,
GDestroyNotify notify) GDestroyNotify notify)
{ {
GSource *source;
g_return_val_if_fail (channel != NULL, 0); g_return_val_if_fail (channel != NULL, 0);
return channel->funcs->io_add_watch (channel, priority, condition, source = g_io_create_watch (channel, condition);
func, user_data, notify);
if (priority != G_PRIORITY_DEFAULT)
g_source_set_priority (source, priority);
g_source_set_callback (source, (GSourceFunc)func, user_data, notify);
return g_source_attach (source, NULL);
} }
guint guint
@ -124,5 +140,5 @@ g_io_add_watch (GIOChannel *channel,
GIOFunc func, GIOFunc func,
gpointer user_data) gpointer user_data)
{ {
return g_io_add_watch_full (channel, 0, condition, func, user_data, NULL); return g_io_add_watch_full (channel, G_PRIORITY_DEFAULT, condition, func, user_data, NULL);
} }

View File

@ -27,6 +27,7 @@
#ifndef __G_IOCHANNEL_H__ #ifndef __G_IOCHANNEL_H__
#define __G_IOCHANNEL_H__ #define __G_IOCHANNEL_H__
#include <gmain.h>
#include <gtypes.h> #include <gtypes.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -83,12 +84,8 @@ struct _GIOFuncs
gint offset, gint offset,
GSeekType type); GSeekType type);
void (*io_close) (GIOChannel *channel); void (*io_close) (GIOChannel *channel);
guint (*io_add_watch) (GIOChannel *channel, GSource * (*io_create_watch) (GIOChannel *channel,
gint priority, GIOCondition condition);
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify);
void (*io_free) (GIOChannel *channel); void (*io_free) (GIOChannel *channel);
}; };
@ -113,6 +110,8 @@ guint g_io_add_watch_full (GIOChannel *channel,
GIOFunc func, GIOFunc func,
gpointer user_data, gpointer user_data,
GDestroyNotify notify); GDestroyNotify notify);
GSource *g_io_create_watch (GIOChannel *channel,
GIOCondition condition);
guint g_io_add_watch (GIOChannel *channel, guint g_io_add_watch (GIOChannel *channel,
GIOCondition condition, GIOCondition condition,
GIOFunc func, GIOFunc func,

View File

@ -43,12 +43,15 @@
typedef struct _GIOUnixChannel GIOUnixChannel; typedef struct _GIOUnixChannel GIOUnixChannel;
typedef struct _GIOUnixWatch GIOUnixWatch; typedef struct _GIOUnixWatch GIOUnixWatch;
struct _GIOUnixChannel { struct _GIOUnixChannel
{
GIOChannel channel; GIOChannel channel;
gint fd; gint fd;
}; };
struct _GIOUnixWatch { struct _GIOUnixWatch
{
GSource source;
GPollFD pollfd; GPollFD pollfd;
GIOChannel *channel; GIOChannel *channel;
GIOCondition condition; GIOCondition condition;
@ -60,7 +63,6 @@ static GIOError g_io_unix_read (GIOChannel *channel,
gchar *buf, gchar *buf,
guint count, guint count,
guint *bytes_written); guint *bytes_written);
static GIOError g_io_unix_write (GIOChannel *channel, static GIOError g_io_unix_write (GIOChannel *channel,
gchar *buf, gchar *buf,
guint count, guint count,
@ -70,23 +72,16 @@ static GIOError g_io_unix_seek (GIOChannel *channel,
GSeekType type); GSeekType type);
static void g_io_unix_close (GIOChannel *channel); static void g_io_unix_close (GIOChannel *channel);
static void g_io_unix_free (GIOChannel *channel); static void g_io_unix_free (GIOChannel *channel);
static guint g_io_unix_add_watch (GIOChannel *channel, static GSource *g_io_unix_create_watch (GIOChannel *channel,
gint priority, GIOCondition condition);
GIOCondition condition,
GIOFunc func, static gboolean g_io_unix_prepare (GSource *source,
gpointer user_data, gint *timeout);
GDestroyNotify notify); static gboolean g_io_unix_check (GSource *source);
static gboolean g_io_unix_prepare (gpointer source_data, static gboolean g_io_unix_dispatch (GSource *source,
GTimeVal *current_time, GSourceFunc callback,
gint *timeout,
gpointer user_data); gpointer user_data);
static gboolean g_io_unix_check (gpointer source_data, static void g_io_unix_destroy (GSource *source);
GTimeVal *current_time,
gpointer user_data);
static gboolean g_io_unix_dispatch (gpointer source_data,
GTimeVal *current_time,
gpointer user_data);
static void g_io_unix_destroy (gpointer source_data);
GSourceFuncs unix_watch_funcs = { GSourceFuncs unix_watch_funcs = {
g_io_unix_prepare, g_io_unix_prepare,
@ -100,51 +95,53 @@ GIOFuncs unix_channel_funcs = {
g_io_unix_write, g_io_unix_write,
g_io_unix_seek, g_io_unix_seek,
g_io_unix_close, g_io_unix_close,
g_io_unix_add_watch, g_io_unix_create_watch,
g_io_unix_free, g_io_unix_free,
}; };
static gboolean static gboolean
g_io_unix_prepare (gpointer source_data, g_io_unix_prepare (GSource *source,
GTimeVal *current_time, gint *timeout)
gint *timeout,
gpointer user_data)
{ {
*timeout = -1; *timeout = -1;
return FALSE; return FALSE;
} }
static gboolean static gboolean
g_io_unix_check (gpointer source_data, g_io_unix_check (GSource *source)
GTimeVal *current_time,
gpointer user_data)
{ {
GIOUnixWatch *data = source_data; GIOUnixWatch *watch = (GIOUnixWatch *)source;
return (data->pollfd.revents & data->condition); return (watch->pollfd.revents & watch->condition);
} }
static gboolean static gboolean
g_io_unix_dispatch (gpointer source_data, g_io_unix_dispatch (GSource *source,
GTimeVal *current_time, GSourceFunc callback,
gpointer user_data) gpointer user_data)
{ {
GIOUnixWatch *data = source_data; GIOFunc func = (GIOFunc)callback;
GIOUnixWatch *watch = (GIOUnixWatch *)source;
return (*data->callback)(data->channel, if (!func)
data->pollfd.revents & data->condition, {
g_warning ("IO watch dispatched without callback\n"
"You must call g_source_connect().");
return FALSE;
}
return (*func) (watch->channel,
watch->pollfd.revents & watch->condition,
user_data); user_data);
} }
static void static void
g_io_unix_destroy (gpointer source_data) g_io_unix_destroy (GSource *source)
{ {
GIOUnixWatch *data = source_data; GIOUnixWatch *watch = (GIOUnixWatch *)source;
g_main_remove_poll (&data->pollfd); g_io_channel_unref (watch->channel);
g_io_channel_unref (data->channel);
g_free (data);
} }
static GIOError static GIOError
@ -269,29 +266,29 @@ g_io_unix_free (GIOChannel *channel)
g_free (unix_channel); g_free (unix_channel);
} }
static guint static GSource *
g_io_unix_add_watch (GIOChannel *channel, g_io_unix_create_watch (GIOChannel *channel,
gint priority, GIOCondition condition)
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify)
{ {
GIOUnixWatch *watch = g_new (GIOUnixWatch, 1);
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel; GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
GSource *source;
GIOUnixWatch *watch;
source = g_source_new (&unix_watch_funcs, sizeof (GIOUnixWatch));
watch = (GIOUnixWatch *)source;
watch->channel = channel; watch->channel = channel;
g_io_channel_ref (channel); g_io_channel_ref (channel);
watch->callback = func;
watch->condition = condition; watch->condition = condition;
watch->pollfd.fd = unix_channel->fd; watch->pollfd.fd = unix_channel->fd;
watch->pollfd.events = condition; watch->pollfd.events = condition;
g_main_add_poll (&watch->pollfd, priority); g_source_add_poll (source, &watch->pollfd);
return g_source_add (priority, TRUE, &unix_watch_funcs, watch, user_data, notify); return source;
} }
GIOChannel * GIOChannel *

View File

@ -102,6 +102,7 @@ struct _GIOWin32Channel {
#define UNLOCK(mutex) LeaveCriticalSection (&mutex) #define UNLOCK(mutex) LeaveCriticalSection (&mutex)
struct _GIOWin32Watch { struct _GIOWin32Watch {
GSource source;
GPollFD pollfd; GPollFD pollfd;
GIOChannel *channel; GIOChannel *channel;
GIOCondition condition; GIOCondition condition;
@ -319,10 +320,8 @@ buffer_read (GIOWin32Channel *channel,
} }
static gboolean static gboolean
g_io_win32_prepare (gpointer source_data, g_io_win32_prepare (GSource *source,
GTimeVal *current_time, gint *timeout)
gint *timeout,
gpointer user_data)
{ {
*timeout = -1; *timeout = -1;
@ -330,12 +329,10 @@ g_io_win32_prepare (gpointer source_data,
} }
static gboolean static gboolean
g_io_win32_check (gpointer source_data, g_io_win32_check (GSource *source)
GTimeVal *current_time,
gpointer user_data)
{ {
GIOWin32Watch *data = source_data; GIOWin32Watch *watch = (GIOWin32Watch *)source;
GIOWin32Channel *channel = (GIOWin32Channel *) data->channel; GIOWin32Channel *channel = (GIOWin32Channel *) watch->channel;
/* If the thread has died, we have encountered EOF. If the buffer /* If the thread has died, we have encountered EOF. If the buffer
* also is emtpty set the HUP bit. * also is emtpty set the HUP bit.
@ -345,34 +342,31 @@ g_io_win32_check (gpointer source_data,
if (channel->debug) if (channel->debug)
g_print ("g_io_win32_check: setting G_IO_HUP thread %#x rdp=%d wrp=%d\n", g_print ("g_io_win32_check: setting G_IO_HUP thread %#x rdp=%d wrp=%d\n",
channel->thread_id, channel->rdp, channel->wrp); channel->thread_id, channel->rdp, channel->wrp);
data->pollfd.revents |= G_IO_HUP; watch->pollfd.revents |= G_IO_HUP;
return TRUE; return TRUE;
} }
return (data->pollfd.revents & data->condition); return (watch->pollfd.revents & watch->condition);
} }
static gboolean static gboolean
g_io_win32_dispatch (gpointer source_data, g_io_win32_dispatch (GSource *source,
GTimeVal *current_time, GSourceFunc callback,
gpointer user_data) gpointer user_data)
{ {
GIOWin32Watch *data = source_data; GIOWin32Watch *watch = (GIOWin32Watch *)source;
return (*data->callback) (data->channel, return (*callback) (watch->channel,
data->pollfd.revents & data->condition, watch->pollfd.revents & watch->condition,
user_data); user_data);
} }
static void static void
g_io_win32_destroy (gpointer source_data) g_io_win32_destroy (GSource *source)
{ {
GIOWin32Watch *data = source_data; GIOWin32Watch *watch = (GIOWin32Watch *)source;
g_main_remove_poll (&data->pollfd); g_io_channel_unref (watch->channel);
g_io_channel_unref (data->channel);
g_free (data);
} }
static GSourceFuncs win32_watch_funcs = { static GSourceFuncs win32_watch_funcs = {
@ -382,22 +376,21 @@ static GSourceFuncs win32_watch_funcs = {
g_io_win32_destroy g_io_win32_destroy
}; };
static guint static GSource *
g_io_win32_add_watch (GIOChannel *channel, g_io_win32_create_watch (GIOChannel *channel,
gint priority,
GIOCondition condition, GIOCondition condition,
GIOFunc func, int (*reader) (int, guchar *, int)))
gpointer user_data,
GDestroyNotify notify,
int (*reader) (int, guchar *, int))
{ {
GIOWin32Watch *watch = g_new (GIOWin32Watch, 1);
GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel; GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
GIOWin32Watch *watch;
GSource *source;
source = g_source_new (&win32_watch_funcs, sizeof (GIOWin32Watch));
watch = (GIOWin32Watch *)source;
watch->channel = channel; watch->channel = channel;
g_io_channel_ref (channel); g_io_channel_ref (channel);
watch->callback = func;
watch->condition = condition; watch->condition = condition;
if (win32_channel->data_avail_event == NULL) if (win32_channel->data_avail_event == NULL)
@ -407,16 +400,15 @@ g_io_win32_add_watch (GIOChannel *channel,
watch->pollfd.events = condition; watch->pollfd.events = condition;
if (win32_channel->debug) if (win32_channel->debug)
g_print ("g_io_win32_add_watch: fd:%d handle:%#x\n", g_print ("g_io_win32_create_watch: fd:%d handle:%#x\n",
win32_channel->fd, watch->pollfd.fd); win32_channel->fd, watch->pollfd.fd);
if (win32_channel->thread_id == 0) if (win32_channel->thread_id == 0)
create_reader_thread (win32_channel, reader); create_reader_thread (win32_channel, reader);
g_main_add_poll (&watch->pollfd, priority); g_source_add_poll (source, &watch->pollfd);
return g_source_add (priority, TRUE, &win32_watch_funcs, watch, return source;
user_data, notify);
} }
static GIOError static GIOError
@ -490,29 +482,27 @@ g_io_win32_free (GIOChannel *channel)
g_free (win32_channel); g_free (win32_channel);
} }
static guint static GSource *
g_io_win32_msg_add_watch (GIOChannel *channel, g_io_win32_msg_create_watch (GIOChannel *channel,
gint priority, GIOCondition condition)
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify)
{ {
GIOWin32Watch *watch = g_new (GIOWin32Watch, 1); GIOWin32Watch *watch;
GSource *source;
source = g_source_new (&win32_watch_funcs, sizeof (GIOWin32Watch));
watch = (GIOWin32Watch *)source;
watch->channel = channel; watch->channel = channel;
g_io_channel_ref (channel); g_io_channel_ref (channel);
watch->callback = func;
watch->condition = condition; watch->condition = condition;
watch->pollfd.fd = G_WIN32_MSG_HANDLE; watch->pollfd.fd = G_WIN32_MSG_HANDLE;
watch->pollfd.events = condition; watch->pollfd.events = condition;
g_main_add_poll (&watch->pollfd, priority); g_source_add_poll (source, &watch->pollfd);
return g_source_add (priority, TRUE, &win32_watch_funcs, return source;
watch, user_data, notify);
} }
static GIOError static GIOError
@ -653,16 +643,11 @@ fd_reader (int fd,
return read (fd, buf, len); return read (fd, buf, len);
} }
static guint static GSource *
g_io_win32_fd_add_watch (GIOChannel *channel, g_io_win32_fd_create_watch (GIOChannel *channel,
gint priority, GIOCondition condition)
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify)
{ {
return g_io_win32_add_watch (channel, priority, condition, return g_io_win32_create_watch (channel, condition, fd_reader);
func, user_data, notify, fd_reader);
} }
static GIOError static GIOError
@ -752,16 +737,11 @@ sock_reader (int fd,
return recv (fd, buf, len, 0); return recv (fd, buf, len, 0);
} }
static guint static GSource *
g_io_win32_sock_add_watch (GIOChannel *channel, g_io_win32_sock_create_watch (GIOChannel *channel,
gint priority, GIOCondition condition)
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify)
{ {
return g_io_win32_add_watch (channel, priority, condition, return g_io_win32_add_watch (channel, condition, sock_reader);
func, user_data, notify, sock_reader);
} }
static GIOFuncs win32_channel_msg_funcs = { static GIOFuncs win32_channel_msg_funcs = {
@ -769,7 +749,7 @@ static GIOFuncs win32_channel_msg_funcs = {
g_io_win32_msg_write, g_io_win32_msg_write,
g_io_win32_no_seek, g_io_win32_no_seek,
g_io_win32_msg_close, g_io_win32_msg_close,
g_io_win32_msg_add_watch, g_io_win32_msg_create_watch,
g_io_win32_free g_io_win32_free
}; };
@ -778,7 +758,7 @@ static GIOFuncs win32_channel_fd_funcs = {
g_io_win32_fd_write, g_io_win32_fd_write,
g_io_win32_fd_seek, g_io_win32_fd_seek,
g_io_win32_fd_close, g_io_win32_fd_close,
g_io_win32_fd_add_watch, g_io_win32_fd_create_watch,
g_io_win32_free g_io_win32_free
}; };
@ -787,7 +767,7 @@ static GIOFuncs win32_channel_sock_funcs = {
g_io_win32_sock_write, g_io_win32_sock_write,
g_io_win32_no_seek, g_io_win32_no_seek,
g_io_win32_sock_close, g_io_win32_sock_close,
g_io_win32_sock_add_watch, g_io_win32_sock_create_watch,
g_io_win32_free g_io_win32_free
}; };

File diff suppressed because it is too large Load Diff

View File

@ -1,122 +1,87 @@
/* GLIB - Library of useful routines for C programming /* gmain.h - the GLib Main loop
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * Copyright (C) 1998-2000 Red Hat, Inc.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version. * version 2 of the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Library General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the * License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
/*
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GLib Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GLib at ftp://ftp.gtk.org/pub/gtk/.
*/
#ifndef __G_MAIN_H__ #ifndef __G_MAIN_H__
#define __G_MAIN_H__ #define __G_MAIN_H__
#include <gtypes.h> #include <gslist.h>
#include <gthread.h>
G_BEGIN_DECLS G_BEGIN_DECLS
/* Main loop typedef struct _GMainContext GMainContext; /* Opaque */
*/
typedef struct _GTimeVal GTimeVal;
typedef struct _GSourceFuncs GSourceFuncs;
typedef struct _GMainLoop GMainLoop; /* Opaque */ typedef struct _GMainLoop GMainLoop; /* Opaque */
typedef struct _GSource GSource;
struct _GTimeVal typedef struct _GSourceCallbackFuncs GSourceCallbackFuncs;
{ typedef struct _GSourceFuncs GSourceFuncs;
glong tv_sec;
glong tv_usec;
};
struct _GSourceFuncs
{
gboolean (*prepare) (gpointer source_data,
GTimeVal *current_time,
gint *timeout,
gpointer user_data);
gboolean (*check) (gpointer source_data,
GTimeVal *current_time,
gpointer user_data);
gboolean (*dispatch) (gpointer source_data,
GTimeVal *dispatch_time,
gpointer user_data);
GDestroyNotify destroy;
};
/* Standard priorities */
#define G_PRIORITY_HIGH -100
#define G_PRIORITY_DEFAULT 0
#define G_PRIORITY_HIGH_IDLE 100
#define G_PRIORITY_DEFAULT_IDLE 200
#define G_PRIORITY_LOW 300
typedef gboolean (*GSourceFunc) (gpointer data); typedef gboolean (*GSourceFunc) (gpointer data);
/* Hooks for adding to the main loop */ struct _GSource
guint g_source_add (gint priority, {
gboolean can_recurse, /*< private >*/
GSourceFuncs *funcs, gpointer callback_data;
gpointer source_data, GSourceCallbackFuncs *callback_funcs;
gpointer user_data,
GDestroyNotify notify); GSourceFuncs *source_funcs;
gboolean g_source_remove (guint tag); guint ref_count;
gboolean g_source_remove_by_user_data (gpointer user_data);
gboolean g_source_remove_by_source_data (gpointer source_data); GMainContext *context;
gboolean g_source_remove_by_funcs_user_data (GSourceFuncs *funcs,
gint priority;
guint flags;
guint id;
GSList *poll_fds;
GSource *prev;
GSource *next;
};
struct _GSourceCallbackFuncs
{
void (*ref) (gpointer cb_data);
void (*unref) (gpointer cb_data);
void (*get) (gpointer cb_data,
GSourceFunc *func,
gpointer *data);
};
struct _GSourceFuncs
{
gboolean (*prepare) (GSource *source,
gint *timeout);
gboolean (*check) (GSource *source);
gboolean (*dispatch) (GSource *source,
GSourceFunc callback,
gpointer user_data); gpointer user_data);
void (*destroy) (GSource *source);
};
void g_get_current_time (GTimeVal *result); /* Any definitions using GPollFD or GPollFunc are primarily
* for Unix and not guaranteed to be the compatible on all
/* Running the main loop */ * operating systems on which GLib runs. Right now, the
GMainLoop* g_main_new (gboolean is_running); * GLib does use these functions on Win32 as well, but interprets
void g_main_run (GMainLoop *loop); * them in a fairly different way than on Unix. If you use
void g_main_quit (GMainLoop *loop); * these definitions, you are should be prepared to recode
void g_main_destroy (GMainLoop *loop); * for different operating systems.
gboolean g_main_is_running (GMainLoop *loop);
/* Run a single iteration of the mainloop. If block is FALSE,
* will never block
*/
gboolean g_main_iteration (gboolean may_block);
/* See if any events are pending */
gboolean g_main_pending (void);
/* Idles and timeouts */
guint g_timeout_add_full (gint priority,
guint interval,
GSourceFunc function,
gpointer data,
GDestroyNotify notify);
guint g_timeout_add (guint interval,
GSourceFunc function,
gpointer data);
guint g_idle_add (GSourceFunc function,
gpointer data);
guint g_idle_add_full (gint priority,
GSourceFunc function,
gpointer data,
GDestroyNotify destroy);
gboolean g_idle_remove_by_data (gpointer data);
/* GPollFD
* *
* System-specific IO and main loop calls
* *
* On Win32, the fd in a GPollFD should be Win32 HANDLE (*not* a file * On Win32, the fd in a GPollFD should be Win32 HANDLE (*not* a file
* descriptor as provided by the C runtime) that can be used by * descriptor as provided by the C runtime) that can be used by
@ -137,11 +102,11 @@ gboolean g_idle_remove_by_data (gpointer data);
* Win32. It's really only written for the GIMP's needs so * Win32. It's really only written for the GIMP's needs so
* far. * far.
*/ */
typedef struct _GPollFD GPollFD; typedef struct _GPollFD GPollFD;
typedef gint (*GPollFunc) (GPollFD *ufds, typedef gint (*GPollFunc) (GPollFD *ufds,
guint nfsd, guint nfsd,
gint timeout); gint timeout);
struct _GPollFD struct _GPollFD
{ {
gint fd; gint fd;
@ -149,20 +114,173 @@ struct _GPollFD
gushort revents; gushort revents;
}; };
void g_main_add_poll (GPollFD *fd, /* Standard priorities */
#define G_PRIORITY_HIGH -100
#define G_PRIORITY_DEFAULT 0
#define G_PRIORITY_HIGH_IDLE 100
#define G_PRIORITY_DEFAULT_IDLE 200
#define G_PRIORITY_LOW 300
/* GMainContext: */
GMainContext *g_main_context_get (GThread *thread);
GMainContext *g_main_context_default (void);
gboolean g_main_context_iteration (GMainContext *context,
gboolean may_block);
gboolean g_main_context_pending (GMainContext *context);
/* For implementation of legacy interfaces
*/
GSource *g_main_context_find_source_by_id (GMainContext *context,
guint id);
GSource *g_main_context_find_source_by_user_data (GMainContext *context,
gpointer user_data);
GSource *g_main_context_find_source_by_funcs_user_data (GMainContext *context,
GSourceFuncs *funcs,
gpointer user_data);
/* Low level functions for implementing custom main loops.
*/
gboolean g_main_context_prepare (GMainContext *context,
gint *priority);
gint g_main_context_query (GMainContext *context,
gint max_priority,
gint *timeout,
GPollFD *fds,
gint n_fds);
gint g_main_context_check (GMainContext *context,
gint max_priority,
GPollFD *fds,
gint n_fds);
void g_main_context_dispatch (GMainContext *context);
void g_main_context_set_poll_func (GMainContext *context,
GPollFunc func);
GPollFunc g_main_context_get_poll_func (GMainContext *context);
/* Low level functions for use by source implementations
*/
void g_main_context_add_poll (GMainContext *context,
GPollFD *fd,
gint priority); gint priority);
void g_main_remove_poll (GPollFD *fd); void g_main_context_remove_poll (GMainContext *context,
void g_main_set_poll_func (GPollFunc func); GPollFD *fd);
/* GMainLoop: */
GMainLoop *g_main_loop_new (GMainContext *context,
gboolean is_running);
void g_main_loop_run (GMainLoop *loop);
void g_main_loop_quit (GMainLoop *loop);
void g_main_loop_destroy (GMainLoop *loop);
gboolean g_main_loop_is_running (GMainLoop *loop);
/* GSource: */
GSource *g_source_new (GSourceFuncs *source_funcs,
guint struct_size);
GSource *g_source_ref (GSource *source);
void g_source_unref (GSource *source);
guint g_source_attach (GSource *source,
GMainContext *context);
void g_source_destroy (GSource *source);
void g_source_set_priority (GSource *source,
gint priority);
gint g_source_get_priority (GSource *source);
void g_source_set_can_recurse (GSource *source,
gboolean can_recurse);
gboolean g_source_get_can_recurse (GSource *source);
guint g_source_get_id (GSource *source);
GMainContext *g_source_get_context (GSource *source);
void g_source_set_callback (GSource *source,
GSourceFunc func,
gpointer data,
GDestroyNotify notify);
/* Used to implement g_source_connect_closure and internally*/
void g_source_set_callback_indirect (GSource *source,
gpointer callback_data,
GSourceCallbackFuncs *callback_funcs);
void g_source_add_poll (GSource *source,
GPollFD *fd);
void g_source_remove_poll (GSource *source,
GPollFD *fd);
void g_source_get_current_time (GSource *source,
GTimeVal *timeval);
/* void g_source_connect_closure (GSource *source,
GClosure *closure);
*/
/* Specific source types
*/
GSource *g_idle_source_new (void);
GSource *g_timeout_source_new (guint interval);
/* Miscellaneous functions
*/
void g_get_current_time (GTimeVal *result);
/* ============== Compat main loop stuff ================== */
/* Legacy names for GMainLoop functions
*/
#define g_main_new(is_running) g_main_loop_new (NULL, is_running);
#define g_main_run(loop) g_main_loop_run(loop)
#define g_main_quit(loop) g_main_loop_quit(loop)
#define g_main_destroy(loop) g_main_loop_destroy(loop)
#define g_main_is_running(loop) g_main_loop_is_running(loop)
/* Source manipulation by ID */
gboolean g_source_remove (guint tag);
gboolean g_source_remove_by_user_data (gpointer user_data);
gboolean g_source_remove_by_funcs_user_data (GSourceFuncs *funcs,
gpointer user_data);
/* Functions to manipulate the default main loop
*/
#define g_main_iteration(may_block) g_main_context_iteration (NULL, may_block)
#define g_main_pending() g_main_context_pending (NULL)
#define g_main_set_poll_func(func) g_main_context_set_poll_func (NULL, func)
/* Idles and timeouts */
guint g_timeout_add_full (gint priority,
guint interval,
GSourceFunc function,
gpointer data,
GDestroyNotify notify);
guint g_timeout_add (guint interval,
GSourceFunc function,
gpointer data);
guint g_idle_add (GSourceFunc function,
gpointer data);
guint g_idle_add_full (gint priority,
GSourceFunc function,
gpointer data,
GDestroyNotify notify);
gboolean g_idle_remove_by_data (gpointer data);
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
/* Useful on other platforms, too? */ /* This is used to add polling for Windows messages. GDK (GTK+) programs
* should *not* use this.
GPollFunc g_main_win32_get_poll_func (void); */
void g_main_poll_win32_msg_add (gint priority,
#endif GPollFD *fd,
guint hwnd);
#endif G_OS_WIN32
G_END_DECLS G_END_DECLS
#endif /* __G_MAIN_H__ */ #endif /* __G_MAIN_H__ */

View File

@ -28,7 +28,6 @@
#define __G_THREAD_H__ #define __G_THREAD_H__
#include <gerror.h> #include <gerror.h>
#include <gmain.h>
G_BEGIN_DECLS G_BEGIN_DECLS

View File

@ -314,6 +314,14 @@ union _GDoubleIEEE754
#error unknown ENDIAN type #error unknown ENDIAN type
#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */ #endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
typedef struct _GTimeVal GTimeVal;
struct _GTimeVal
{
glong tv_sec;
glong tv_usec;
};
G_END_DECLS G_END_DECLS
#endif /* __G_TYPES_H__ */ #endif /* __G_TYPES_H__ */

2714
gmain.c

File diff suppressed because it is too large Load Diff

322
gmain.h
View File

@ -1,122 +1,87 @@
/* GLIB - Library of useful routines for C programming /* gmain.h - the GLib Main loop
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald * Copyright (C) 1998-2000 Red Hat, Inc.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either * License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version. * version 2 of the License, or (at your option) any later version.
* *
* This library is distributed in the hope that it will be useful, * This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. * Library General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the * License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA. * Boston, MA 02111-1307, USA.
*/ */
/*
* Modified by the GLib Team and others 1997-2000. See the AUTHORS
* file for a list of people on the GLib Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GLib at ftp://ftp.gtk.org/pub/gtk/.
*/
#ifndef __G_MAIN_H__ #ifndef __G_MAIN_H__
#define __G_MAIN_H__ #define __G_MAIN_H__
#include <gtypes.h> #include <gslist.h>
#include <gthread.h>
G_BEGIN_DECLS G_BEGIN_DECLS
/* Main loop typedef struct _GMainContext GMainContext; /* Opaque */
*/
typedef struct _GTimeVal GTimeVal;
typedef struct _GSourceFuncs GSourceFuncs;
typedef struct _GMainLoop GMainLoop; /* Opaque */ typedef struct _GMainLoop GMainLoop; /* Opaque */
typedef struct _GSource GSource;
struct _GTimeVal typedef struct _GSourceCallbackFuncs GSourceCallbackFuncs;
{ typedef struct _GSourceFuncs GSourceFuncs;
glong tv_sec;
glong tv_usec;
};
struct _GSourceFuncs
{
gboolean (*prepare) (gpointer source_data,
GTimeVal *current_time,
gint *timeout,
gpointer user_data);
gboolean (*check) (gpointer source_data,
GTimeVal *current_time,
gpointer user_data);
gboolean (*dispatch) (gpointer source_data,
GTimeVal *dispatch_time,
gpointer user_data);
GDestroyNotify destroy;
};
/* Standard priorities */
#define G_PRIORITY_HIGH -100
#define G_PRIORITY_DEFAULT 0
#define G_PRIORITY_HIGH_IDLE 100
#define G_PRIORITY_DEFAULT_IDLE 200
#define G_PRIORITY_LOW 300
typedef gboolean (*GSourceFunc) (gpointer data); typedef gboolean (*GSourceFunc) (gpointer data);
/* Hooks for adding to the main loop */ struct _GSource
guint g_source_add (gint priority, {
gboolean can_recurse, /*< private >*/
GSourceFuncs *funcs, gpointer callback_data;
gpointer source_data, GSourceCallbackFuncs *callback_funcs;
gpointer user_data,
GDestroyNotify notify); GSourceFuncs *source_funcs;
gboolean g_source_remove (guint tag); guint ref_count;
gboolean g_source_remove_by_user_data (gpointer user_data);
gboolean g_source_remove_by_source_data (gpointer source_data); GMainContext *context;
gboolean g_source_remove_by_funcs_user_data (GSourceFuncs *funcs,
gint priority;
guint flags;
guint id;
GSList *poll_fds;
GSource *prev;
GSource *next;
};
struct _GSourceCallbackFuncs
{
void (*ref) (gpointer cb_data);
void (*unref) (gpointer cb_data);
void (*get) (gpointer cb_data,
GSourceFunc *func,
gpointer *data);
};
struct _GSourceFuncs
{
gboolean (*prepare) (GSource *source,
gint *timeout);
gboolean (*check) (GSource *source);
gboolean (*dispatch) (GSource *source,
GSourceFunc callback,
gpointer user_data); gpointer user_data);
void (*destroy) (GSource *source);
};
void g_get_current_time (GTimeVal *result); /* Any definitions using GPollFD or GPollFunc are primarily
* for Unix and not guaranteed to be the compatible on all
/* Running the main loop */ * operating systems on which GLib runs. Right now, the
GMainLoop* g_main_new (gboolean is_running); * GLib does use these functions on Win32 as well, but interprets
void g_main_run (GMainLoop *loop); * them in a fairly different way than on Unix. If you use
void g_main_quit (GMainLoop *loop); * these definitions, you are should be prepared to recode
void g_main_destroy (GMainLoop *loop); * for different operating systems.
gboolean g_main_is_running (GMainLoop *loop);
/* Run a single iteration of the mainloop. If block is FALSE,
* will never block
*/
gboolean g_main_iteration (gboolean may_block);
/* See if any events are pending */
gboolean g_main_pending (void);
/* Idles and timeouts */
guint g_timeout_add_full (gint priority,
guint interval,
GSourceFunc function,
gpointer data,
GDestroyNotify notify);
guint g_timeout_add (guint interval,
GSourceFunc function,
gpointer data);
guint g_idle_add (GSourceFunc function,
gpointer data);
guint g_idle_add_full (gint priority,
GSourceFunc function,
gpointer data,
GDestroyNotify destroy);
gboolean g_idle_remove_by_data (gpointer data);
/* GPollFD
* *
* System-specific IO and main loop calls
* *
* On Win32, the fd in a GPollFD should be Win32 HANDLE (*not* a file * On Win32, the fd in a GPollFD should be Win32 HANDLE (*not* a file
* descriptor as provided by the C runtime) that can be used by * descriptor as provided by the C runtime) that can be used by
@ -137,11 +102,11 @@ gboolean g_idle_remove_by_data (gpointer data);
* Win32. It's really only written for the GIMP's needs so * Win32. It's really only written for the GIMP's needs so
* far. * far.
*/ */
typedef struct _GPollFD GPollFD; typedef struct _GPollFD GPollFD;
typedef gint (*GPollFunc) (GPollFD *ufds, typedef gint (*GPollFunc) (GPollFD *ufds,
guint nfsd, guint nfsd,
gint timeout); gint timeout);
struct _GPollFD struct _GPollFD
{ {
gint fd; gint fd;
@ -149,20 +114,173 @@ struct _GPollFD
gushort revents; gushort revents;
}; };
void g_main_add_poll (GPollFD *fd, /* Standard priorities */
#define G_PRIORITY_HIGH -100
#define G_PRIORITY_DEFAULT 0
#define G_PRIORITY_HIGH_IDLE 100
#define G_PRIORITY_DEFAULT_IDLE 200
#define G_PRIORITY_LOW 300
/* GMainContext: */
GMainContext *g_main_context_get (GThread *thread);
GMainContext *g_main_context_default (void);
gboolean g_main_context_iteration (GMainContext *context,
gboolean may_block);
gboolean g_main_context_pending (GMainContext *context);
/* For implementation of legacy interfaces
*/
GSource *g_main_context_find_source_by_id (GMainContext *context,
guint id);
GSource *g_main_context_find_source_by_user_data (GMainContext *context,
gpointer user_data);
GSource *g_main_context_find_source_by_funcs_user_data (GMainContext *context,
GSourceFuncs *funcs,
gpointer user_data);
/* Low level functions for implementing custom main loops.
*/
gboolean g_main_context_prepare (GMainContext *context,
gint *priority);
gint g_main_context_query (GMainContext *context,
gint max_priority,
gint *timeout,
GPollFD *fds,
gint n_fds);
gint g_main_context_check (GMainContext *context,
gint max_priority,
GPollFD *fds,
gint n_fds);
void g_main_context_dispatch (GMainContext *context);
void g_main_context_set_poll_func (GMainContext *context,
GPollFunc func);
GPollFunc g_main_context_get_poll_func (GMainContext *context);
/* Low level functions for use by source implementations
*/
void g_main_context_add_poll (GMainContext *context,
GPollFD *fd,
gint priority); gint priority);
void g_main_remove_poll (GPollFD *fd); void g_main_context_remove_poll (GMainContext *context,
void g_main_set_poll_func (GPollFunc func); GPollFD *fd);
/* GMainLoop: */
GMainLoop *g_main_loop_new (GMainContext *context,
gboolean is_running);
void g_main_loop_run (GMainLoop *loop);
void g_main_loop_quit (GMainLoop *loop);
void g_main_loop_destroy (GMainLoop *loop);
gboolean g_main_loop_is_running (GMainLoop *loop);
/* GSource: */
GSource *g_source_new (GSourceFuncs *source_funcs,
guint struct_size);
GSource *g_source_ref (GSource *source);
void g_source_unref (GSource *source);
guint g_source_attach (GSource *source,
GMainContext *context);
void g_source_destroy (GSource *source);
void g_source_set_priority (GSource *source,
gint priority);
gint g_source_get_priority (GSource *source);
void g_source_set_can_recurse (GSource *source,
gboolean can_recurse);
gboolean g_source_get_can_recurse (GSource *source);
guint g_source_get_id (GSource *source);
GMainContext *g_source_get_context (GSource *source);
void g_source_set_callback (GSource *source,
GSourceFunc func,
gpointer data,
GDestroyNotify notify);
/* Used to implement g_source_connect_closure and internally*/
void g_source_set_callback_indirect (GSource *source,
gpointer callback_data,
GSourceCallbackFuncs *callback_funcs);
void g_source_add_poll (GSource *source,
GPollFD *fd);
void g_source_remove_poll (GSource *source,
GPollFD *fd);
void g_source_get_current_time (GSource *source,
GTimeVal *timeval);
/* void g_source_connect_closure (GSource *source,
GClosure *closure);
*/
/* Specific source types
*/
GSource *g_idle_source_new (void);
GSource *g_timeout_source_new (guint interval);
/* Miscellaneous functions
*/
void g_get_current_time (GTimeVal *result);
/* ============== Compat main loop stuff ================== */
/* Legacy names for GMainLoop functions
*/
#define g_main_new(is_running) g_main_loop_new (NULL, is_running);
#define g_main_run(loop) g_main_loop_run(loop)
#define g_main_quit(loop) g_main_loop_quit(loop)
#define g_main_destroy(loop) g_main_loop_destroy(loop)
#define g_main_is_running(loop) g_main_loop_is_running(loop)
/* Source manipulation by ID */
gboolean g_source_remove (guint tag);
gboolean g_source_remove_by_user_data (gpointer user_data);
gboolean g_source_remove_by_funcs_user_data (GSourceFuncs *funcs,
gpointer user_data);
/* Functions to manipulate the default main loop
*/
#define g_main_iteration(may_block) g_main_context_iteration (NULL, may_block)
#define g_main_pending() g_main_context_pending (NULL)
#define g_main_set_poll_func(func) g_main_context_set_poll_func (NULL, func)
/* Idles and timeouts */
guint g_timeout_add_full (gint priority,
guint interval,
GSourceFunc function,
gpointer data,
GDestroyNotify notify);
guint g_timeout_add (guint interval,
GSourceFunc function,
gpointer data);
guint g_idle_add (GSourceFunc function,
gpointer data);
guint g_idle_add_full (gint priority,
GSourceFunc function,
gpointer data,
GDestroyNotify notify);
gboolean g_idle_remove_by_data (gpointer data);
#ifdef G_OS_WIN32 #ifdef G_OS_WIN32
/* Useful on other platforms, too? */ /* This is used to add polling for Windows messages. GDK (GTK+) programs
* should *not* use this.
GPollFunc g_main_win32_get_poll_func (void); */
void g_main_poll_win32_msg_add (gint priority,
#endif GPollFD *fd,
guint hwnd);
#endif G_OS_WIN32
G_END_DECLS G_END_DECLS
#endif /* __G_MAIN_H__ */ #endif /* __G_MAIN_H__ */

View File

@ -28,7 +28,6 @@
#define __G_THREAD_H__ #define __G_THREAD_H__
#include <gerror.h> #include <gerror.h>
#include <gmain.h>
G_BEGIN_DECLS G_BEGIN_DECLS

View File

@ -314,6 +314,14 @@ union _GDoubleIEEE754
#error unknown ENDIAN type #error unknown ENDIAN type
#endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */ #endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
typedef struct _GTimeVal GTimeVal;
struct _GTimeVal
{
glong tv_sec;
glong tv_usec;
};
G_END_DECLS G_END_DECLS
#endif /* __G_TYPES_H__ */ #endif /* __G_TYPES_H__ */

View File

@ -11,6 +11,7 @@ date-test
dirname-test dirname-test
hash-test hash-test
list-test list-test
mainloop-test
markup-test markup-test
node-test node-test
queue-test queue-test

View File

@ -19,6 +19,7 @@ TESTS = \
gio-test \ gio-test \
hash-test \ hash-test \
list-test \ list-test \
mainloop-test \
markup-test \ markup-test \
node-test \ node-test \
queue-test \ queue-test \
@ -45,6 +46,7 @@ dirname_test_LDADD = $(progs_LDADD)
gio_test_LDADD = $(progs_LDADD) gio_test_LDADD = $(progs_LDADD)
hash_test_LDADD = $(progs_LDADD) hash_test_LDADD = $(progs_LDADD)
list_test_LDADD = $(progs_LDADD) list_test_LDADD = $(progs_LDADD)
mainloop_test_LDADD = $(thread_LDADD)
markup_test_LDADD = $(progs_LDADD) markup_test_LDADD = $(progs_LDADD)
node_test_LDADD = $(progs_LDADD) node_test_LDADD = $(progs_LDADD)
queue_test_LDADD = $(progs_LDADD) queue_test_LDADD = $(progs_LDADD)

396
tests/mainloop-test.c Normal file
View File

@ -0,0 +1,396 @@
#include <errno.h>
#include <glib.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#define ITERS 10000
#define INCREMENT 10
#define NTHREADS 4
#define NCRAWLERS 4
#define CRAWLER_TIMEOUT_RANGE 40
#define RECURSER_TIMEOUT 50
G_LOCK_DEFINE_STATIC (context_array_lock);
GPtrArray *context_array;
GMainLoop *main_loop;
G_LOCK_DEFINE_STATIC (crawler_array_lock);
GPtrArray *crawler_array;
typedef struct _AddrData AddrData;
typedef struct _TestData TestData;
struct _AddrData
{
GMainLoop *loop;
GIOChannel *dest;
gint count;
};
struct _TestData
{
gint current_val;
gint iters;
GIOChannel *in;
};
static void cleanup_crawlers (GMainContext *context);
gboolean
read_all (GIOChannel *channel, char *buf, int len)
{
int bytes_read = 0;
int 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;
}
gboolean
write_all (GIOChannel *channel, char *buf, int len)
{
int bytes_written = 0;
int 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;
}
gboolean
adder_callback (GIOChannel *source,
GIOCondition condition,
gpointer data)
{
char buf1[32];
char buf2[32];
char result[32];
AddrData *addr_data = data;
if (!read_all (source, buf1, 32) ||
!read_all (source, buf2, 32))
{
g_main_loop_quit (addr_data->loop);
return FALSE;
}
sprintf (result, "%d", atoi(buf1) + atoi(buf2));
write_all (addr_data->dest, result, 32);
return TRUE;
}
gboolean
timeout_callback (gpointer data)
{
AddrData *addr_data = data;
addr_data->count++;
return TRUE;
}
void
adder_thread (gpointer data)
{
GMainContext *context;
GSource *adder_source;
GSource *timeout_source;
GIOChannel **channels = data;
AddrData addr_data;
context = g_main_context_get (g_thread_self());
G_LOCK (context_array_lock);
g_ptr_array_add (context_array, context);
G_UNLOCK (context_array_lock);
addr_data.dest = channels[1];
addr_data.loop = g_main_loop_new (context, FALSE);
addr_data.count = 0;
adder_source = g_io_create_watch (channels[0], G_IO_IN | G_IO_HUP);
g_source_set_callback (adder_source, (GSourceFunc)adder_callback, &addr_data, NULL);
g_source_attach (adder_source, context);
timeout_source = g_timeout_source_new (10);
g_source_set_callback (timeout_source, (GSourceFunc)timeout_callback, &addr_data, NULL);
g_source_set_priority (timeout_source, G_PRIORITY_HIGH);
g_source_attach (timeout_source, context);
g_main_run (addr_data.loop);
g_io_channel_close (channels[0]);
g_io_channel_close (channels[1]);
g_io_channel_unref (channels[0]);
g_io_channel_unref (channels[1]);
g_free (channels);
g_main_loop_destroy (addr_data.loop);
g_print ("Timeout run %d times\n", addr_data.count);
G_LOCK (context_array_lock);
g_ptr_array_remove (context_array, context);
if (context_array->len == 0)
g_main_loop_quit (main_loop);
G_UNLOCK (context_array_lock);
cleanup_crawlers (context);
}
void
io_pipe (GIOChannel **channels)
{
gint fds[2];
if (pipe(fds) < 0)
{
g_warning ("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]);
}
void
do_add (GIOChannel *in, gint a, gint b)
{
char buf1[32];
char buf2[32];
sprintf (buf1, "%d", a);
sprintf (buf2, "%d", b);
write_all (in, buf1, 32);
write_all (in, buf2, 32);
}
gboolean
adder_response (GIOChannel *source,
GIOCondition condition,
gpointer data)
{
char result[32];
TestData *test_data = data;
if (!read_all (source, result, 32))
return FALSE;
test_data->current_val = atoi (result);
test_data->iters--;
if (test_data->iters == 0)
{
if (test_data->current_val != ITERS * INCREMENT)
{
g_print ("Addition failed: %d != %d\n",
test_data->current_val, ITERS * INCREMENT);
exit (1);
}
g_io_channel_close (source);
g_io_channel_close (test_data->in);
g_io_channel_unref (source);
g_io_channel_unref (test_data->in);
return FALSE;
}
do_add (test_data->in, test_data->current_val, INCREMENT);
return TRUE;
}
void
create_adder_thread (void)
{
GError *err = NULL;
TestData *test_data;
GIOChannel *in_channels[2];
GIOChannel *out_channels[2];
GIOChannel **sub_channels;
sub_channels = g_new (GIOChannel *, 2);
io_pipe (in_channels);
io_pipe (out_channels);
sub_channels[0] = in_channels[0];
sub_channels[1] = out_channels[1];
g_thread_create (adder_thread, sub_channels, 0,
FALSE, TRUE, G_THREAD_PRIORITY_NORMAL, &err);
if (err)
{
g_warning ("Cannot create thread: %s", err->message);
exit (1);
}
test_data = g_new (TestData, 1);
test_data->in = in_channels[1];
test_data->current_val = 0;
test_data->iters = ITERS;
g_io_add_watch (out_channels[0], G_IO_IN | G_IO_HUP,
adder_response, test_data);
do_add (test_data->in, test_data->current_val, INCREMENT);
}
static void create_crawler (void);
static void
remove_crawler (void)
{
GSource *other_source;
if (crawler_array->len > 0)
{
other_source = crawler_array->pdata[g_random_int_range (0, crawler_array->len)];
g_source_destroy (other_source);
g_assert (g_ptr_array_remove_fast (crawler_array, other_source));
}
}
static gint
crawler_callback (gpointer data)
{
GSource *source = data;
G_LOCK (crawler_array_lock);
if (!g_ptr_array_remove_fast (crawler_array, source))
remove_crawler();
remove_crawler();
G_UNLOCK (crawler_array_lock);
create_crawler();
create_crawler();
return FALSE;
}
static void
create_crawler (void)
{
GSource *source = g_timeout_source_new (g_random_int_range (0, CRAWLER_TIMEOUT_RANGE));
g_source_set_callback (source, (GSourceFunc)crawler_callback, source, NULL);
G_LOCK (context_array_lock);
g_source_attach (source, context_array->pdata[g_random_int_range (0, context_array->len)]);
G_UNLOCK (context_array_lock);
G_LOCK (crawler_array_lock);
g_ptr_array_add (crawler_array, source);
G_UNLOCK (crawler_array_lock);
}
static void
cleanup_crawlers (GMainContext *context)
{
gint i;
G_LOCK (crawler_array_lock);
for (i=0; i < crawler_array->len; i++)
{
if (g_source_get_context (crawler_array->pdata[i]) == context)
{
g_source_destroy (g_ptr_array_remove_index (crawler_array, i));
i--;
}
}
G_UNLOCK (crawler_array_lock);
}
static gboolean
recurser_idle (gpointer data)
{
GMainContext *context = data;
gint i;
for (i = 0; i < 10; i++)
g_main_context_iteration (context, TRUE);
return FALSE;
}
static gboolean
recurser_start (gpointer data)
{
GMainContext *context;
GSource *source;
G_LOCK (context_array_lock);
context = context_array->pdata[g_random_int_range (0, context_array->len)];
source = g_idle_source_new ();
g_source_set_callback (source, recurser_idle, context, NULL);
g_source_attach (source, context);
G_UNLOCK (context_array_lock);
return TRUE;
}
int
main (int argc,
char *argv[])
{
/* Only run the test, if threads are enabled and a default thread
implementation is available */
#if defined(G_THREADS_ENABLED) && ! defined(G_THREADS_IMPL_NONE)
gint i;
g_thread_init (NULL);
context_array = g_ptr_array_new ();
crawler_array = g_ptr_array_new ();
main_loop = g_main_loop_new (NULL, FALSE);
for (i = 0; i < NTHREADS; i++)
create_adder_thread ();
for (i = 0; i < NCRAWLERS; i++)
create_crawler ();
g_timeout_add (RECURSER_TIMEOUT, recurser_start, NULL);
g_main_loop_run (main_loop);
g_main_loop_destroy (main_loop);
#endif
return 0;
}

232
tests/timeloop-basic.c Normal file
View File

@ -0,0 +1,232 @@
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/poll.h>
#define TRUE 1
#define FALSE 0
static int n_children = 3;
static int n_active_children;
static int n_iters = 10000;
static int write_fds[1024];
static struct pollfd poll_fds[1024];
void
my_pipe (int *fds)
{
if (pipe(fds) < 0)
{
fprintf (stderr, "Cannot create pipe %s\n", strerror (errno));
exit (1);
}
}
int
read_all (int fd, char *buf, int len)
{
int bytes_read = 0;
int count;
while (bytes_read < len)
{
count = read (fd, buf + bytes_read, len - bytes_read);
if (count < 0)
{
if (errno != EAGAIN)
return FALSE;
}
else if (count == 0)
return FALSE;
bytes_read += count;
}
return TRUE;
}
int
write_all (int fd, char *buf, int len)
{
int bytes_written = 0;
int count;
while (bytes_written < len)
{
count = write (fd, buf + bytes_written, len - bytes_written);
if (count < 0)
{
if (errno != EAGAIN)
return FALSE;
}
bytes_written += count;
}
return TRUE;
}
void
run_child (int in_fd, int out_fd)
{
int i;
int val = 1;
for (i = 0; i < n_iters; i++)
{
write_all (out_fd, (char *)&val, sizeof (val));
read_all (in_fd, (char *)&val, sizeof (val));
}
val = 0;
write_all (out_fd, (char *)&val, sizeof (val));
exit (0);
}
int
input_callback (int source, int dest)
{
int val;
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
{
close (source);
close (dest);
n_active_children--;
return FALSE;
}
}
void
create_child (int pos)
{
int pid;
int in_fds[2];
int out_fds[2];
my_pipe (in_fds);
my_pipe (out_fds);
pid = fork ();
if (pid > 0) /* Parent */
{
close (in_fds[0]);
close (out_fds[1]);
write_fds[pos] = in_fds[1];
poll_fds[pos].fd = out_fds[0];
poll_fds[pos].events = POLLIN;
}
else if (pid == 0) /* Child */
{
close (in_fds[1]);
close (out_fds[0]);
setsid ();
run_child (in_fds[0], out_fds[1]);
}
else /* Error */
{
fprintf (stderr,"Cannot fork: %s\n", 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, j;
struct rusage old_usage;
struct rusage new_usage;
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 (i);
getrusage (RUSAGE_SELF, &old_usage);
while (n_active_children > 0)
{
int old_n_active_children = n_active_children;
poll (poll_fds, n_active_children, -1);
for (i=0; i<n_active_children; i++)
{
if (poll_fds[i].events & (POLLIN | POLLHUP))
{
if (!input_callback (poll_fds[i].fd, write_fds[i]))
write_fds[i] = -1;
}
}
if (old_n_active_children > n_active_children)
{
j = 0;
for (i=0; i<old_n_active_children; i++)
{
if (write_fds[i] != -1)
{
if (j < i)
{
poll_fds[j] = poll_fds[i];
write_fds[j] = write_fds[i];
}
j++;
}
}
}
}
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;
}

213
tests/timeloop.c Normal file
View File

@ -0,0 +1,213 @@
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <glib.h>
static int n_children = 3;
static int n_active_children;
static int n_iters = 10000;
static GMainLoop *loop;
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]);
}
gboolean
read_all (GIOChannel *channel, char *buf, int len)
{
int bytes_read = 0;
int 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;
}
gboolean
write_all (GIOChannel *channel, char *buf, int len)
{
int bytes_written = 0;
int 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;
}
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);
}
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_quit (loop);
return FALSE;
}
}
void
create_child ()
{
int pid;
GIOChannel *in_channels[2];
GIOChannel *out_channels[2];
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]);
g_io_add_watch (out_channels[0], G_IO_IN | G_IO_HUP,
input_callback, in_channels[1]);
}
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;
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_new (FALSE);
g_main_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;
}

232
timeloop-basic.c Normal file
View File

@ -0,0 +1,232 @@
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/poll.h>
#define TRUE 1
#define FALSE 0
static int n_children = 3;
static int n_active_children;
static int n_iters = 10000;
static int write_fds[1024];
static struct pollfd poll_fds[1024];
void
my_pipe (int *fds)
{
if (pipe(fds) < 0)
{
fprintf (stderr, "Cannot create pipe %s\n", strerror (errno));
exit (1);
}
}
int
read_all (int fd, char *buf, int len)
{
int bytes_read = 0;
int count;
while (bytes_read < len)
{
count = read (fd, buf + bytes_read, len - bytes_read);
if (count < 0)
{
if (errno != EAGAIN)
return FALSE;
}
else if (count == 0)
return FALSE;
bytes_read += count;
}
return TRUE;
}
int
write_all (int fd, char *buf, int len)
{
int bytes_written = 0;
int count;
while (bytes_written < len)
{
count = write (fd, buf + bytes_written, len - bytes_written);
if (count < 0)
{
if (errno != EAGAIN)
return FALSE;
}
bytes_written += count;
}
return TRUE;
}
void
run_child (int in_fd, int out_fd)
{
int i;
int val = 1;
for (i = 0; i < n_iters; i++)
{
write_all (out_fd, (char *)&val, sizeof (val));
read_all (in_fd, (char *)&val, sizeof (val));
}
val = 0;
write_all (out_fd, (char *)&val, sizeof (val));
exit (0);
}
int
input_callback (int source, int dest)
{
int val;
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
{
close (source);
close (dest);
n_active_children--;
return FALSE;
}
}
void
create_child (int pos)
{
int pid;
int in_fds[2];
int out_fds[2];
my_pipe (in_fds);
my_pipe (out_fds);
pid = fork ();
if (pid > 0) /* Parent */
{
close (in_fds[0]);
close (out_fds[1]);
write_fds[pos] = in_fds[1];
poll_fds[pos].fd = out_fds[0];
poll_fds[pos].events = POLLIN;
}
else if (pid == 0) /* Child */
{
close (in_fds[1]);
close (out_fds[0]);
setsid ();
run_child (in_fds[0], out_fds[1]);
}
else /* Error */
{
fprintf (stderr,"Cannot fork: %s\n", 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, j;
struct rusage old_usage;
struct rusage new_usage;
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 (i);
getrusage (RUSAGE_SELF, &old_usage);
while (n_active_children > 0)
{
int old_n_active_children = n_active_children;
poll (poll_fds, n_active_children, -1);
for (i=0; i<n_active_children; i++)
{
if (poll_fds[i].events & (POLLIN | POLLHUP))
{
if (!input_callback (poll_fds[i].fd, write_fds[i]))
write_fds[i] = -1;
}
}
if (old_n_active_children > n_active_children)
{
j = 0;
for (i=0; i<old_n_active_children; i++)
{
if (write_fds[i] != -1)
{
if (j < i)
{
poll_fds[j] = poll_fds[i];
write_fds[j] = write_fds[i];
}
j++;
}
}
}
}
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;
}

213
timeloop.c Normal file
View File

@ -0,0 +1,213 @@
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <glib.h>
static int n_children = 3;
static int n_active_children;
static int n_iters = 10000;
static GMainLoop *loop;
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]);
}
gboolean
read_all (GIOChannel *channel, char *buf, int len)
{
int bytes_read = 0;
int 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;
}
gboolean
write_all (GIOChannel *channel, char *buf, int len)
{
int bytes_written = 0;
int 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;
}
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);
}
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_quit (loop);
return FALSE;
}
}
void
create_child ()
{
int pid;
GIOChannel *in_channels[2];
GIOChannel *out_channels[2];
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]);
g_io_add_watch (out_channels[0], G_IO_IN | G_IO_HUP,
input_callback, in_channels[1]);
}
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;
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_new (FALSE);
g_main_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;
}