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
testgdateparser
testglib
timeloop
timeloop-basic
annotations
logs
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>
* {.,*}/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>
* {.,*}/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>
* {.,*}/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>
* {.,*}/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>
* {.,*}/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>
* {.,*}/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>
* {.,*}/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>
* {.,*}/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) \
-export-dynamic
noinst_PROGRAMS = testglib testgdate testgdateparser
noinst_PROGRAMS = testglib testgdate testgdateparser timeloop
testglib_LDADD = libglib-1.3.la
testgdate_LDADD = libglib-1.3.la
testgdateparser_LDADD = libglib-1.3.la
timeloop_LDADD = libglib-1.3.la
m4datadir = $(datadir)/aclocal
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>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>

View File

@ -104,6 +104,15 @@ g_io_channel_close (GIOChannel *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
g_io_add_watch_full (GIOChannel *channel,
gint priority,
@ -112,10 +121,17 @@ g_io_add_watch_full (GIOChannel *channel,
gpointer user_data,
GDestroyNotify notify)
{
GSource *source;
g_return_val_if_fail (channel != NULL, 0);
return channel->funcs->io_add_watch (channel, priority, condition,
func, user_data, notify);
source = g_io_create_watch (channel, condition);
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
@ -124,5 +140,5 @@ g_io_add_watch (GIOChannel *channel,
GIOFunc func,
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__
#define __G_IOCHANNEL_H__
#include <gmain.h>
#include <gtypes.h>
G_BEGIN_DECLS
@ -71,25 +72,21 @@ typedef gboolean (*GIOFunc) (GIOChannel *source,
gpointer data);
struct _GIOFuncs
{
GIOError (*io_read) (GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_read);
GIOError (*io_write) (GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_written);
GIOError (*io_seek) (GIOChannel *channel,
gint offset,
GSeekType type);
void (*io_close) (GIOChannel *channel);
guint (*io_add_watch) (GIOChannel *channel,
gint priority,
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify);
void (*io_free) (GIOChannel *channel);
GIOError (*io_read) (GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_read);
GIOError (*io_write) (GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_written);
GIOError (*io_seek) (GIOChannel *channel,
gint offset,
GSeekType type);
void (*io_close) (GIOChannel *channel);
GSource * (*io_create_watch) (GIOChannel *channel,
GIOCondition condition);
void (*io_free) (GIOChannel *channel);
};
void g_io_channel_init (GIOChannel *channel);
@ -113,6 +110,8 @@ guint g_io_add_watch_full (GIOChannel *channel,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify);
GSource *g_io_create_watch (GIOChannel *channel,
GIOCondition condition);
guint g_io_add_watch (GIOChannel *channel,
GIOCondition condition,
GIOFunc func,

131
giounix.c
View File

@ -43,12 +43,15 @@
typedef struct _GIOUnixChannel GIOUnixChannel;
typedef struct _GIOUnixWatch GIOUnixWatch;
struct _GIOUnixChannel {
struct _GIOUnixChannel
{
GIOChannel channel;
gint fd;
};
struct _GIOUnixWatch {
struct _GIOUnixWatch
{
GSource source;
GPollFD pollfd;
GIOChannel *channel;
GIOCondition condition;
@ -56,37 +59,29 @@ struct _GIOUnixWatch {
};
static GIOError g_io_unix_read (GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_written);
static GIOError g_io_unix_write(GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_written);
static GIOError g_io_unix_seek (GIOChannel *channel,
gint offset,
GSeekType type);
static void g_io_unix_close (GIOChannel *channel);
static void g_io_unix_free (GIOChannel *channel);
static guint g_io_unix_add_watch (GIOChannel *channel,
gint priority,
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify);
static gboolean g_io_unix_prepare (gpointer source_data,
GTimeVal *current_time,
gint *timeout,
gpointer user_data);
static gboolean g_io_unix_check (gpointer source_data,
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);
static GIOError g_io_unix_read (GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_written);
static GIOError g_io_unix_write (GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_written);
static GIOError g_io_unix_seek (GIOChannel *channel,
gint offset,
GSeekType type);
static void g_io_unix_close (GIOChannel *channel);
static void g_io_unix_free (GIOChannel *channel);
static GSource *g_io_unix_create_watch (GIOChannel *channel,
GIOCondition condition);
static gboolean g_io_unix_prepare (GSource *source,
gint *timeout);
static gboolean g_io_unix_check (GSource *source);
static gboolean g_io_unix_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data);
static void g_io_unix_destroy (GSource *source);
GSourceFuncs unix_watch_funcs = {
g_io_unix_prepare,
@ -100,51 +95,53 @@ GIOFuncs unix_channel_funcs = {
g_io_unix_write,
g_io_unix_seek,
g_io_unix_close,
g_io_unix_add_watch,
g_io_unix_create_watch,
g_io_unix_free,
};
static gboolean
g_io_unix_prepare (gpointer source_data,
GTimeVal *current_time,
gint *timeout,
gpointer user_data)
g_io_unix_prepare (GSource *source,
gint *timeout)
{
*timeout = -1;
return FALSE;
}
static gboolean
g_io_unix_check (gpointer source_data,
GTimeVal *current_time,
gpointer user_data)
g_io_unix_check (GSource *source)
{
GIOUnixWatch *data = source_data;
GIOUnixWatch *watch = (GIOUnixWatch *)source;
return (data->pollfd.revents & data->condition);
return (watch->pollfd.revents & watch->condition);
}
static gboolean
g_io_unix_dispatch (gpointer source_data,
GTimeVal *current_time,
gpointer user_data)
g_io_unix_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
GIOUnixWatch *data = source_data;
GIOFunc func = (GIOFunc)callback;
GIOUnixWatch *watch = (GIOUnixWatch *)source;
return (*data->callback)(data->channel,
data->pollfd.revents & data->condition,
user_data);
if (!func)
{
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);
}
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 (data->channel);
g_free (data);
g_io_channel_unref (watch->channel);
}
static GIOError
@ -269,29 +266,29 @@ g_io_unix_free (GIOChannel *channel)
g_free (unix_channel);
}
static guint
g_io_unix_add_watch (GIOChannel *channel,
gint priority,
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify)
static GSource *
g_io_unix_create_watch (GIOChannel *channel,
GIOCondition condition)
{
GIOUnixWatch *watch = g_new (GIOUnixWatch, 1);
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
GSource *source;
GIOUnixWatch *watch;
source = g_source_new (&unix_watch_funcs, sizeof (GIOUnixWatch));
watch = (GIOUnixWatch *)source;
watch->channel = channel;
g_io_channel_ref (channel);
watch->callback = func;
watch->condition = condition;
watch->pollfd.fd = unix_channel->fd;
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 *

View File

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

View File

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

View File

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

View File

@ -104,6 +104,15 @@ g_io_channel_close (GIOChannel *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
g_io_add_watch_full (GIOChannel *channel,
gint priority,
@ -112,10 +121,17 @@ g_io_add_watch_full (GIOChannel *channel,
gpointer user_data,
GDestroyNotify notify)
{
GSource *source;
g_return_val_if_fail (channel != NULL, 0);
return channel->funcs->io_add_watch (channel, priority, condition,
func, user_data, notify);
source = g_io_create_watch (channel, condition);
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
@ -124,5 +140,5 @@ g_io_add_watch (GIOChannel *channel,
GIOFunc func,
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__
#define __G_IOCHANNEL_H__
#include <gmain.h>
#include <gtypes.h>
G_BEGIN_DECLS
@ -71,25 +72,21 @@ typedef gboolean (*GIOFunc) (GIOChannel *source,
gpointer data);
struct _GIOFuncs
{
GIOError (*io_read) (GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_read);
GIOError (*io_write) (GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_written);
GIOError (*io_seek) (GIOChannel *channel,
gint offset,
GSeekType type);
void (*io_close) (GIOChannel *channel);
guint (*io_add_watch) (GIOChannel *channel,
gint priority,
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify);
void (*io_free) (GIOChannel *channel);
GIOError (*io_read) (GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_read);
GIOError (*io_write) (GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_written);
GIOError (*io_seek) (GIOChannel *channel,
gint offset,
GSeekType type);
void (*io_close) (GIOChannel *channel);
GSource * (*io_create_watch) (GIOChannel *channel,
GIOCondition condition);
void (*io_free) (GIOChannel *channel);
};
void g_io_channel_init (GIOChannel *channel);
@ -113,6 +110,8 @@ guint g_io_add_watch_full (GIOChannel *channel,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify);
GSource *g_io_create_watch (GIOChannel *channel,
GIOCondition condition);
guint g_io_add_watch (GIOChannel *channel,
GIOCondition condition,
GIOFunc func,

View File

@ -43,12 +43,15 @@
typedef struct _GIOUnixChannel GIOUnixChannel;
typedef struct _GIOUnixWatch GIOUnixWatch;
struct _GIOUnixChannel {
struct _GIOUnixChannel
{
GIOChannel channel;
gint fd;
};
struct _GIOUnixWatch {
struct _GIOUnixWatch
{
GSource source;
GPollFD pollfd;
GIOChannel *channel;
GIOCondition condition;
@ -56,37 +59,29 @@ struct _GIOUnixWatch {
};
static GIOError g_io_unix_read (GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_written);
static GIOError g_io_unix_write(GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_written);
static GIOError g_io_unix_seek (GIOChannel *channel,
gint offset,
GSeekType type);
static void g_io_unix_close (GIOChannel *channel);
static void g_io_unix_free (GIOChannel *channel);
static guint g_io_unix_add_watch (GIOChannel *channel,
gint priority,
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify);
static gboolean g_io_unix_prepare (gpointer source_data,
GTimeVal *current_time,
gint *timeout,
gpointer user_data);
static gboolean g_io_unix_check (gpointer source_data,
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);
static GIOError g_io_unix_read (GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_written);
static GIOError g_io_unix_write (GIOChannel *channel,
gchar *buf,
guint count,
guint *bytes_written);
static GIOError g_io_unix_seek (GIOChannel *channel,
gint offset,
GSeekType type);
static void g_io_unix_close (GIOChannel *channel);
static void g_io_unix_free (GIOChannel *channel);
static GSource *g_io_unix_create_watch (GIOChannel *channel,
GIOCondition condition);
static gboolean g_io_unix_prepare (GSource *source,
gint *timeout);
static gboolean g_io_unix_check (GSource *source);
static gboolean g_io_unix_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data);
static void g_io_unix_destroy (GSource *source);
GSourceFuncs unix_watch_funcs = {
g_io_unix_prepare,
@ -100,51 +95,53 @@ GIOFuncs unix_channel_funcs = {
g_io_unix_write,
g_io_unix_seek,
g_io_unix_close,
g_io_unix_add_watch,
g_io_unix_create_watch,
g_io_unix_free,
};
static gboolean
g_io_unix_prepare (gpointer source_data,
GTimeVal *current_time,
gint *timeout,
gpointer user_data)
g_io_unix_prepare (GSource *source,
gint *timeout)
{
*timeout = -1;
return FALSE;
}
static gboolean
g_io_unix_check (gpointer source_data,
GTimeVal *current_time,
gpointer user_data)
g_io_unix_check (GSource *source)
{
GIOUnixWatch *data = source_data;
GIOUnixWatch *watch = (GIOUnixWatch *)source;
return (data->pollfd.revents & data->condition);
return (watch->pollfd.revents & watch->condition);
}
static gboolean
g_io_unix_dispatch (gpointer source_data,
GTimeVal *current_time,
gpointer user_data)
g_io_unix_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
GIOUnixWatch *data = source_data;
GIOFunc func = (GIOFunc)callback;
GIOUnixWatch *watch = (GIOUnixWatch *)source;
return (*data->callback)(data->channel,
data->pollfd.revents & data->condition,
user_data);
if (!func)
{
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);
}
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 (data->channel);
g_free (data);
g_io_channel_unref (watch->channel);
}
static GIOError
@ -269,29 +266,29 @@ g_io_unix_free (GIOChannel *channel)
g_free (unix_channel);
}
static guint
g_io_unix_add_watch (GIOChannel *channel,
gint priority,
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify)
static GSource *
g_io_unix_create_watch (GIOChannel *channel,
GIOCondition condition)
{
GIOUnixWatch *watch = g_new (GIOUnixWatch, 1);
GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
GSource *source;
GIOUnixWatch *watch;
source = g_source_new (&unix_watch_funcs, sizeof (GIOUnixWatch));
watch = (GIOUnixWatch *)source;
watch->channel = channel;
g_io_channel_ref (channel);
watch->callback = func;
watch->condition = condition;
watch->pollfd.fd = unix_channel->fd;
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 *

View File

@ -102,6 +102,7 @@ struct _GIOWin32Channel {
#define UNLOCK(mutex) LeaveCriticalSection (&mutex)
struct _GIOWin32Watch {
GSource source;
GPollFD pollfd;
GIOChannel *channel;
GIOCondition condition;
@ -319,10 +320,8 @@ buffer_read (GIOWin32Channel *channel,
}
static gboolean
g_io_win32_prepare (gpointer source_data,
GTimeVal *current_time,
gint *timeout,
gpointer user_data)
g_io_win32_prepare (GSource *source,
gint *timeout)
{
*timeout = -1;
@ -330,12 +329,10 @@ g_io_win32_prepare (gpointer source_data,
}
static gboolean
g_io_win32_check (gpointer source_data,
GTimeVal *current_time,
gpointer user_data)
g_io_win32_check (GSource *source)
{
GIOWin32Watch *data = source_data;
GIOWin32Channel *channel = (GIOWin32Channel *) data->channel;
GIOWin32Watch *watch = (GIOWin32Watch *)source;
GIOWin32Channel *channel = (GIOWin32Channel *) watch->channel;
/* If the thread has died, we have encountered EOF. If the buffer
* also is emtpty set the HUP bit.
@ -345,34 +342,31 @@ g_io_win32_check (gpointer source_data,
if (channel->debug)
g_print ("g_io_win32_check: setting G_IO_HUP thread %#x rdp=%d wrp=%d\n",
channel->thread_id, channel->rdp, channel->wrp);
data->pollfd.revents |= G_IO_HUP;
watch->pollfd.revents |= G_IO_HUP;
return TRUE;
}
return (data->pollfd.revents & data->condition);
return (watch->pollfd.revents & watch->condition);
}
static gboolean
g_io_win32_dispatch (gpointer source_data,
GTimeVal *current_time,
gpointer user_data)
g_io_win32_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data)
{
GIOWin32Watch *data = source_data;
GIOWin32Watch *watch = (GIOWin32Watch *)source;
return (*data->callback) (data->channel,
data->pollfd.revents & data->condition,
user_data);
return (*callback) (watch->channel,
watch->pollfd.revents & watch->condition,
user_data);
}
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 (data->channel);
g_free (data);
g_io_channel_unref (watch->channel);
}
static GSourceFuncs win32_watch_funcs = {
@ -382,22 +376,21 @@ static GSourceFuncs win32_watch_funcs = {
g_io_win32_destroy
};
static guint
g_io_win32_add_watch (GIOChannel *channel,
gint priority,
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify,
int (*reader) (int, guchar *, int))
static GSource *
g_io_win32_create_watch (GIOChannel *channel,
GIOCondition condition,
int (*reader) (int, guchar *, int)))
{
GIOWin32Watch *watch = g_new (GIOWin32Watch, 1);
GIOWin32Channel *win32_channel = (GIOWin32Channel *) channel;
GIOWin32Watch *watch;
GSource *source;
source = g_source_new (&win32_watch_funcs, sizeof (GIOWin32Watch));
watch = (GIOWin32Watch *)source;
watch->channel = channel;
g_io_channel_ref (channel);
watch->callback = func;
watch->condition = condition;
if (win32_channel->data_avail_event == NULL)
@ -407,16 +400,15 @@ g_io_win32_add_watch (GIOChannel *channel,
watch->pollfd.events = condition;
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);
if (win32_channel->thread_id == 0)
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,
user_data, notify);
return source;
}
static GIOError
@ -490,29 +482,27 @@ g_io_win32_free (GIOChannel *channel)
g_free (win32_channel);
}
static guint
g_io_win32_msg_add_watch (GIOChannel *channel,
gint priority,
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify)
static GSource *
g_io_win32_msg_create_watch (GIOChannel *channel,
GIOCondition condition)
{
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;
g_io_channel_ref (channel);
watch->callback = func;
watch->condition = condition;
watch->pollfd.fd = G_WIN32_MSG_HANDLE;
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,
watch, user_data, notify);
return source;
}
static GIOError
@ -653,16 +643,11 @@ fd_reader (int fd,
return read (fd, buf, len);
}
static guint
g_io_win32_fd_add_watch (GIOChannel *channel,
gint priority,
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify)
static GSource *
g_io_win32_fd_create_watch (GIOChannel *channel,
GIOCondition condition)
{
return g_io_win32_add_watch (channel, priority, condition,
func, user_data, notify, fd_reader);
return g_io_win32_create_watch (channel, condition, fd_reader);
}
static GIOError
@ -752,16 +737,11 @@ sock_reader (int fd,
return recv (fd, buf, len, 0);
}
static guint
g_io_win32_sock_add_watch (GIOChannel *channel,
gint priority,
GIOCondition condition,
GIOFunc func,
gpointer user_data,
GDestroyNotify notify)
static GSource *
g_io_win32_sock_create_watch (GIOChannel *channel,
GIOCondition condition)
{
return g_io_win32_add_watch (channel, priority, condition,
func, user_data, notify, sock_reader);
return g_io_win32_add_watch (channel, condition, sock_reader);
}
static GIOFuncs win32_channel_msg_funcs = {
@ -769,7 +749,7 @@ static GIOFuncs win32_channel_msg_funcs = {
g_io_win32_msg_write,
g_io_win32_no_seek,
g_io_win32_msg_close,
g_io_win32_msg_add_watch,
g_io_win32_msg_create_watch,
g_io_win32_free
};
@ -778,7 +758,7 @@ static GIOFuncs win32_channel_fd_funcs = {
g_io_win32_fd_write,
g_io_win32_fd_seek,
g_io_win32_fd_close,
g_io_win32_fd_add_watch,
g_io_win32_fd_create_watch,
g_io_win32_free
};
@ -787,7 +767,7 @@ static GIOFuncs win32_channel_sock_funcs = {
g_io_win32_sock_write,
g_io_win32_no_seek,
g_io_win32_sock_close,
g_io_win32_sock_add_watch,
g_io_win32_sock_create_watch,
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
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
/* gmain.h - the GLib Main loop
* Copyright (C) 1998-2000 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
* modify it under the terms of the GNU Library 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.
* 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
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* 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__
#define __G_MAIN_H__
#include <gtypes.h>
#include <gslist.h>
#include <gthread.h>
G_BEGIN_DECLS
/* Main loop
*/
typedef struct _GTimeVal GTimeVal;
typedef struct _GSourceFuncs GSourceFuncs;
typedef struct _GMainLoop GMainLoop; /* Opaque */
typedef struct _GMainContext GMainContext; /* Opaque */
typedef struct _GMainLoop GMainLoop; /* Opaque */
typedef struct _GSource GSource;
typedef struct _GSourceCallbackFuncs GSourceCallbackFuncs;
typedef struct _GSourceFuncs GSourceFuncs;
struct _GTimeVal
typedef gboolean (*GSourceFunc) (gpointer data);
struct _GSource
{
glong tv_sec;
glong tv_usec;
/*< private >*/
gpointer callback_data;
GSourceCallbackFuncs *callback_funcs;
GSourceFuncs *source_funcs;
guint ref_count;
GMainContext *context;
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) (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;
gboolean (*prepare) (GSource *source,
gint *timeout);
gboolean (*check) (GSource *source);
gboolean (*dispatch) (GSource *source,
GSourceFunc callback,
gpointer user_data);
void (*destroy) (GSource *source);
};
/* 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);
/* Hooks for adding to the main loop */
guint g_source_add (gint priority,
gboolean can_recurse,
GSourceFuncs *funcs,
gpointer source_data,
gpointer user_data,
GDestroyNotify notify);
gboolean g_source_remove (guint tag);
gboolean g_source_remove_by_user_data (gpointer user_data);
gboolean g_source_remove_by_source_data (gpointer source_data);
gboolean g_source_remove_by_funcs_user_data (GSourceFuncs *funcs,
gpointer user_data);
void g_get_current_time (GTimeVal *result);
/* Running the main loop */
GMainLoop* g_main_new (gboolean is_running);
void g_main_run (GMainLoop *loop);
void g_main_quit (GMainLoop *loop);
void g_main_destroy (GMainLoop *loop);
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
/* Any definitions using GPollFD or GPollFunc are primarily
* for Unix and not guaranteed to be the compatible on all
* operating systems on which GLib runs. Right now, the
* GLib does use these functions on Win32 as well, but interprets
* them in a fairly different way than on Unix. If you use
* these definitions, you are should be prepared to recode
* for different operating systems.
*
* System-specific IO and main loop calls
*
* 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
@ -137,32 +102,185 @@ gboolean g_idle_remove_by_data (gpointer data);
* Win32. It's really only written for the GIMP's needs so
* far.
*/
typedef struct _GPollFD GPollFD;
typedef gint (*GPollFunc) (GPollFD *ufds,
guint nfsd,
gint timeout);
typedef gint (*GPollFunc) (GPollFD *ufds,
guint nfsd,
gint timeout);
struct _GPollFD
{
gint fd;
gushort events;
gushort revents;
gint fd;
gushort events;
gushort revents;
};
void g_main_add_poll (GPollFD *fd,
gint priority);
void g_main_remove_poll (GPollFD *fd);
void g_main_set_poll_func (GPollFunc func);
/* 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);
void g_main_context_remove_poll (GMainContext *context,
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
/* Useful on other platforms, too? */
GPollFunc g_main_win32_get_poll_func (void);
#endif
/* This is used to add polling for Windows messages. GDK (GTK+) programs
* should *not* use this.
*/
void g_main_poll_win32_msg_add (gint priority,
GPollFD *fd,
guint hwnd);
#endif G_OS_WIN32
G_END_DECLS
#endif /* __G_MAIN_H__ */

View File

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

View File

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

2746
gmain.c

File diff suppressed because it is too large Load Diff

334
gmain.h
View File

@ -1,122 +1,87 @@
/* GLIB - Library of useful routines for C programming
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
/* gmain.h - the GLib Main loop
* Copyright (C) 1998-2000 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
* modify it under the terms of the GNU Library 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.
* 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
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* 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__
#define __G_MAIN_H__
#include <gtypes.h>
#include <gslist.h>
#include <gthread.h>
G_BEGIN_DECLS
/* Main loop
*/
typedef struct _GTimeVal GTimeVal;
typedef struct _GSourceFuncs GSourceFuncs;
typedef struct _GMainLoop GMainLoop; /* Opaque */
typedef struct _GMainContext GMainContext; /* Opaque */
typedef struct _GMainLoop GMainLoop; /* Opaque */
typedef struct _GSource GSource;
typedef struct _GSourceCallbackFuncs GSourceCallbackFuncs;
typedef struct _GSourceFuncs GSourceFuncs;
struct _GTimeVal
typedef gboolean (*GSourceFunc) (gpointer data);
struct _GSource
{
glong tv_sec;
glong tv_usec;
/*< private >*/
gpointer callback_data;
GSourceCallbackFuncs *callback_funcs;
GSourceFuncs *source_funcs;
guint ref_count;
GMainContext *context;
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) (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;
gboolean (*prepare) (GSource *source,
gint *timeout);
gboolean (*check) (GSource *source);
gboolean (*dispatch) (GSource *source,
GSourceFunc callback,
gpointer user_data);
void (*destroy) (GSource *source);
};
/* 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);
/* Hooks for adding to the main loop */
guint g_source_add (gint priority,
gboolean can_recurse,
GSourceFuncs *funcs,
gpointer source_data,
gpointer user_data,
GDestroyNotify notify);
gboolean g_source_remove (guint tag);
gboolean g_source_remove_by_user_data (gpointer user_data);
gboolean g_source_remove_by_source_data (gpointer source_data);
gboolean g_source_remove_by_funcs_user_data (GSourceFuncs *funcs,
gpointer user_data);
void g_get_current_time (GTimeVal *result);
/* Running the main loop */
GMainLoop* g_main_new (gboolean is_running);
void g_main_run (GMainLoop *loop);
void g_main_quit (GMainLoop *loop);
void g_main_destroy (GMainLoop *loop);
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
/* Any definitions using GPollFD or GPollFunc are primarily
* for Unix and not guaranteed to be the compatible on all
* operating systems on which GLib runs. Right now, the
* GLib does use these functions on Win32 as well, but interprets
* them in a fairly different way than on Unix. If you use
* these definitions, you are should be prepared to recode
* for different operating systems.
*
* System-specific IO and main loop calls
*
* 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
@ -137,32 +102,185 @@ gboolean g_idle_remove_by_data (gpointer data);
* Win32. It's really only written for the GIMP's needs so
* far.
*/
typedef struct _GPollFD GPollFD;
typedef gint (*GPollFunc) (GPollFD *ufds,
guint nfsd,
gint timeout);
typedef gint (*GPollFunc) (GPollFD *ufds,
guint nfsd,
gint timeout);
struct _GPollFD
{
gint fd;
gushort events;
gushort revents;
gint fd;
gushort events;
gushort revents;
};
void g_main_add_poll (GPollFD *fd,
gint priority);
void g_main_remove_poll (GPollFD *fd);
void g_main_set_poll_func (GPollFunc func);
/* 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);
void g_main_context_remove_poll (GMainContext *context,
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
/* Useful on other platforms, too? */
GPollFunc g_main_win32_get_poll_func (void);
#endif
/* This is used to add polling for Windows messages. GDK (GTK+) programs
* should *not* use this.
*/
void g_main_poll_win32_msg_add (gint priority,
GPollFD *fd,
guint hwnd);
#endif G_OS_WIN32
G_END_DECLS
#endif /* __G_MAIN_H__ */

View File

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

View File

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

View File

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

View File

@ -19,6 +19,7 @@ TESTS = \
gio-test \
hash-test \
list-test \
mainloop-test \
markup-test \
node-test \
queue-test \
@ -45,6 +46,7 @@ dirname_test_LDADD = $(progs_LDADD)
gio_test_LDADD = $(progs_LDADD)
hash_test_LDADD = $(progs_LDADD)
list_test_LDADD = $(progs_LDADD)
mainloop_test_LDADD = $(thread_LDADD)
markup_test_LDADD = $(progs_LDADD)
node_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;
}