mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-13 12:56:15 +01:00
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:
parent
5791ec5b85
commit
e2fd4e2bd0
@ -28,6 +28,8 @@ stamp-h.in
|
|||||||
testgdate
|
testgdate
|
||||||
testgdateparser
|
testgdateparser
|
||||||
testglib
|
testglib
|
||||||
|
timeloop
|
||||||
|
timeloop-basic
|
||||||
annotations
|
annotations
|
||||||
logs
|
logs
|
||||||
glib.rc
|
glib.rc
|
||||||
|
32
ChangeLog
32
ChangeLog
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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.
|
||||||
|
@ -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
24
docs/Changes-2.0.txt
Normal 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().
|
@ -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>
|
||||||
|
22
giochannel.c
22
giochannel.c
@ -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);
|
||||||
}
|
}
|
||||||
|
37
giochannel.h
37
giochannel.h
@ -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
|
||||||
@ -71,25 +72,21 @@ typedef gboolean (*GIOFunc) (GIOChannel *source,
|
|||||||
gpointer data);
|
gpointer data);
|
||||||
struct _GIOFuncs
|
struct _GIOFuncs
|
||||||
{
|
{
|
||||||
GIOError (*io_read) (GIOChannel *channel,
|
GIOError (*io_read) (GIOChannel *channel,
|
||||||
gchar *buf,
|
gchar *buf,
|
||||||
guint count,
|
guint count,
|
||||||
guint *bytes_read);
|
guint *bytes_read);
|
||||||
GIOError (*io_write) (GIOChannel *channel,
|
GIOError (*io_write) (GIOChannel *channel,
|
||||||
gchar *buf,
|
gchar *buf,
|
||||||
guint count,
|
guint count,
|
||||||
guint *bytes_written);
|
guint *bytes_written);
|
||||||
GIOError (*io_seek) (GIOChannel *channel,
|
GIOError (*io_seek) (GIOChannel *channel,
|
||||||
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,
|
void (*io_free) (GIOChannel *channel);
|
||||||
GIOFunc func,
|
|
||||||
gpointer user_data,
|
|
||||||
GDestroyNotify notify);
|
|
||||||
void (*io_free) (GIOChannel *channel);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void g_io_channel_init (GIOChannel *channel);
|
void g_io_channel_init (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,
|
||||||
|
131
giounix.c
131
giounix.c
@ -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;
|
||||||
@ -56,37 +59,29 @@ struct _GIOUnixWatch {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static GIOError g_io_unix_read (GIOChannel *channel,
|
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,
|
guint *bytes_written);
|
||||||
guint *bytes_written);
|
static GIOError g_io_unix_seek (GIOChannel *channel,
|
||||||
static GIOError g_io_unix_seek (GIOChannel *channel,
|
gint offset,
|
||||||
gint offset,
|
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 GSource *g_io_unix_create_watch (GIOChannel *channel,
|
||||||
static guint g_io_unix_add_watch (GIOChannel *channel,
|
GIOCondition condition);
|
||||||
gint priority,
|
|
||||||
GIOCondition condition,
|
static gboolean g_io_unix_prepare (GSource *source,
|
||||||
GIOFunc func,
|
gint *timeout);
|
||||||
gpointer user_data,
|
static gboolean g_io_unix_check (GSource *source);
|
||||||
GDestroyNotify notify);
|
static gboolean g_io_unix_dispatch (GSource *source,
|
||||||
static gboolean g_io_unix_prepare (gpointer source_data,
|
GSourceFunc callback,
|
||||||
GTimeVal *current_time,
|
gpointer user_data);
|
||||||
gint *timeout,
|
static void g_io_unix_destroy (GSource *source);
|
||||||
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);
|
|
||||||
|
|
||||||
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,
|
{
|
||||||
user_data);
|
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
|
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 *
|
||||||
|
122
giowin32.c
122
giowin32.c
@ -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,
|
int (*reader) (int, guchar *, int)))
|
||||||
GIOFunc func,
|
|
||||||
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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
@ -71,25 +72,21 @@ typedef gboolean (*GIOFunc) (GIOChannel *source,
|
|||||||
gpointer data);
|
gpointer data);
|
||||||
struct _GIOFuncs
|
struct _GIOFuncs
|
||||||
{
|
{
|
||||||
GIOError (*io_read) (GIOChannel *channel,
|
GIOError (*io_read) (GIOChannel *channel,
|
||||||
gchar *buf,
|
gchar *buf,
|
||||||
guint count,
|
guint count,
|
||||||
guint *bytes_read);
|
guint *bytes_read);
|
||||||
GIOError (*io_write) (GIOChannel *channel,
|
GIOError (*io_write) (GIOChannel *channel,
|
||||||
gchar *buf,
|
gchar *buf,
|
||||||
guint count,
|
guint count,
|
||||||
guint *bytes_written);
|
guint *bytes_written);
|
||||||
GIOError (*io_seek) (GIOChannel *channel,
|
GIOError (*io_seek) (GIOChannel *channel,
|
||||||
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,
|
void (*io_free) (GIOChannel *channel);
|
||||||
GIOFunc func,
|
|
||||||
gpointer user_data,
|
|
||||||
GDestroyNotify notify);
|
|
||||||
void (*io_free) (GIOChannel *channel);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void g_io_channel_init (GIOChannel *channel);
|
void g_io_channel_init (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,
|
||||||
|
131
glib/giounix.c
131
glib/giounix.c
@ -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;
|
||||||
@ -56,37 +59,29 @@ struct _GIOUnixWatch {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static GIOError g_io_unix_read (GIOChannel *channel,
|
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,
|
guint *bytes_written);
|
||||||
guint *bytes_written);
|
static GIOError g_io_unix_seek (GIOChannel *channel,
|
||||||
static GIOError g_io_unix_seek (GIOChannel *channel,
|
gint offset,
|
||||||
gint offset,
|
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 GSource *g_io_unix_create_watch (GIOChannel *channel,
|
||||||
static guint g_io_unix_add_watch (GIOChannel *channel,
|
GIOCondition condition);
|
||||||
gint priority,
|
|
||||||
GIOCondition condition,
|
static gboolean g_io_unix_prepare (GSource *source,
|
||||||
GIOFunc func,
|
gint *timeout);
|
||||||
gpointer user_data,
|
static gboolean g_io_unix_check (GSource *source);
|
||||||
GDestroyNotify notify);
|
static gboolean g_io_unix_dispatch (GSource *source,
|
||||||
static gboolean g_io_unix_prepare (gpointer source_data,
|
GSourceFunc callback,
|
||||||
GTimeVal *current_time,
|
gpointer user_data);
|
||||||
gint *timeout,
|
static void g_io_unix_destroy (GSource *source);
|
||||||
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);
|
|
||||||
|
|
||||||
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,
|
{
|
||||||
user_data);
|
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
|
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 *
|
||||||
|
122
glib/giowin32.c
122
glib/giowin32.c
@ -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,
|
int (*reader) (int, guchar *, int)))
|
||||||
GIOFunc func,
|
|
||||||
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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
2746
glib/gmain.c
2746
glib/gmain.c
File diff suppressed because it is too large
Load Diff
334
glib/gmain.h
334
glib/gmain.h
@ -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 _GMainLoop GMainLoop; /* Opaque */
|
||||||
typedef struct _GTimeVal GTimeVal;
|
typedef struct _GSource GSource;
|
||||||
typedef struct _GSourceFuncs GSourceFuncs;
|
typedef struct _GSourceCallbackFuncs GSourceCallbackFuncs;
|
||||||
typedef struct _GMainLoop GMainLoop; /* Opaque */
|
typedef struct _GSourceFuncs GSourceFuncs;
|
||||||
|
|
||||||
struct _GTimeVal
|
typedef gboolean (*GSourceFunc) (gpointer data);
|
||||||
|
|
||||||
|
struct _GSource
|
||||||
{
|
{
|
||||||
glong tv_sec;
|
/*< private >*/
|
||||||
glong tv_usec;
|
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
|
struct _GSourceFuncs
|
||||||
{
|
{
|
||||||
gboolean (*prepare) (gpointer source_data,
|
gboolean (*prepare) (GSource *source,
|
||||||
GTimeVal *current_time,
|
gint *timeout);
|
||||||
gint *timeout,
|
gboolean (*check) (GSource *source);
|
||||||
gpointer user_data);
|
gboolean (*dispatch) (GSource *source,
|
||||||
gboolean (*check) (gpointer source_data,
|
GSourceFunc callback,
|
||||||
GTimeVal *current_time,
|
gpointer user_data);
|
||||||
gpointer user_data);
|
void (*destroy) (GSource *source);
|
||||||
gboolean (*dispatch) (gpointer source_data,
|
|
||||||
GTimeVal *dispatch_time,
|
|
||||||
gpointer user_data);
|
|
||||||
GDestroyNotify destroy;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Standard priorities */
|
/* Any definitions using GPollFD or GPollFunc are primarily
|
||||||
|
* for Unix and not guaranteed to be the compatible on all
|
||||||
#define G_PRIORITY_HIGH -100
|
* operating systems on which GLib runs. Right now, the
|
||||||
#define G_PRIORITY_DEFAULT 0
|
* GLib does use these functions on Win32 as well, but interprets
|
||||||
#define G_PRIORITY_HIGH_IDLE 100
|
* them in a fairly different way than on Unix. If you use
|
||||||
#define G_PRIORITY_DEFAULT_IDLE 200
|
* these definitions, you are should be prepared to recode
|
||||||
#define G_PRIORITY_LOW 300
|
* for different operating systems.
|
||||||
|
|
||||||
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
|
|
||||||
*
|
*
|
||||||
* 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,32 +102,185 @@ 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;
|
||||||
gushort events;
|
gushort events;
|
||||||
gushort revents;
|
gushort revents;
|
||||||
};
|
};
|
||||||
|
|
||||||
void g_main_add_poll (GPollFD *fd,
|
/* Standard priorities */
|
||||||
gint priority);
|
|
||||||
void g_main_remove_poll (GPollFD *fd);
|
#define G_PRIORITY_HIGH -100
|
||||||
void g_main_set_poll_func (GPollFunc func);
|
#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
|
#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__ */
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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__ */
|
||||||
|
334
gmain.h
334
gmain.h
@ -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 _GMainLoop GMainLoop; /* Opaque */
|
||||||
typedef struct _GTimeVal GTimeVal;
|
typedef struct _GSource GSource;
|
||||||
typedef struct _GSourceFuncs GSourceFuncs;
|
typedef struct _GSourceCallbackFuncs GSourceCallbackFuncs;
|
||||||
typedef struct _GMainLoop GMainLoop; /* Opaque */
|
typedef struct _GSourceFuncs GSourceFuncs;
|
||||||
|
|
||||||
struct _GTimeVal
|
typedef gboolean (*GSourceFunc) (gpointer data);
|
||||||
|
|
||||||
|
struct _GSource
|
||||||
{
|
{
|
||||||
glong tv_sec;
|
/*< private >*/
|
||||||
glong tv_usec;
|
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
|
struct _GSourceFuncs
|
||||||
{
|
{
|
||||||
gboolean (*prepare) (gpointer source_data,
|
gboolean (*prepare) (GSource *source,
|
||||||
GTimeVal *current_time,
|
gint *timeout);
|
||||||
gint *timeout,
|
gboolean (*check) (GSource *source);
|
||||||
gpointer user_data);
|
gboolean (*dispatch) (GSource *source,
|
||||||
gboolean (*check) (gpointer source_data,
|
GSourceFunc callback,
|
||||||
GTimeVal *current_time,
|
gpointer user_data);
|
||||||
gpointer user_data);
|
void (*destroy) (GSource *source);
|
||||||
gboolean (*dispatch) (gpointer source_data,
|
|
||||||
GTimeVal *dispatch_time,
|
|
||||||
gpointer user_data);
|
|
||||||
GDestroyNotify destroy;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Standard priorities */
|
/* Any definitions using GPollFD or GPollFunc are primarily
|
||||||
|
* for Unix and not guaranteed to be the compatible on all
|
||||||
#define G_PRIORITY_HIGH -100
|
* operating systems on which GLib runs. Right now, the
|
||||||
#define G_PRIORITY_DEFAULT 0
|
* GLib does use these functions on Win32 as well, but interprets
|
||||||
#define G_PRIORITY_HIGH_IDLE 100
|
* them in a fairly different way than on Unix. If you use
|
||||||
#define G_PRIORITY_DEFAULT_IDLE 200
|
* these definitions, you are should be prepared to recode
|
||||||
#define G_PRIORITY_LOW 300
|
* for different operating systems.
|
||||||
|
|
||||||
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
|
|
||||||
*
|
*
|
||||||
* 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,32 +102,185 @@ 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;
|
||||||
gushort events;
|
gushort events;
|
||||||
gushort revents;
|
gushort revents;
|
||||||
};
|
};
|
||||||
|
|
||||||
void g_main_add_poll (GPollFD *fd,
|
/* Standard priorities */
|
||||||
gint priority);
|
|
||||||
void g_main_remove_poll (GPollFD *fd);
|
#define G_PRIORITY_HIGH -100
|
||||||
void g_main_set_poll_func (GPollFunc func);
|
#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
|
#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__ */
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
8
gtypes.h
8
gtypes.h
@ -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__ */
|
||||||
|
@ -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
|
||||||
|
@ -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
396
tests/mainloop-test.c
Normal 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
232
tests/timeloop-basic.c
Normal 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
213
tests/timeloop.c
Normal 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
232
timeloop-basic.c
Normal 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
213
timeloop.c
Normal 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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user