mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-19 23:28:54 +02:00
Wrap waitpid() as a GSource. This is a partial implementation of the "Unix
Sat Feb 14 01:21:34 2004 Matthias Clasen <maclas@gmx.de> * glib/gmain.h: * glib/gmain.c (g_child_watch_source_new): * glib/gmain.c (g_child_watch_add): * glib/gmain.c (g_child_watch_add_full): Wrap waitpid() as a GSource. This is a partial implementation of the "Unix signal source". (#50296, Jonathan R. Blandford) * configure.in: Add the necessary configury to typedef GPid appropriately. * tests/Makefile.am: * tests/child-test.c: Test child_watch sources.
This commit is contained in:
committed by
Matthias Clasen
parent
fff62fd3df
commit
540d02ba8b
15
ChangeLog
15
ChangeLog
@@ -1,3 +1,18 @@
|
|||||||
|
Sat Feb 14 01:21:34 2004 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
|
* glib/gmain.h:
|
||||||
|
* glib/gmain.c (g_child_watch_source_new):
|
||||||
|
* glib/gmain.c (g_child_watch_add):
|
||||||
|
* glib/gmain.c (g_child_watch_add_full): Wrap waitpid() as a
|
||||||
|
GSource. This is a partial implementation of the "Unix signal
|
||||||
|
source". (#50296, Jonathan R. Blandford)
|
||||||
|
|
||||||
|
* configure.in: Add the necessary configury to typedef GPid
|
||||||
|
appropriately.
|
||||||
|
|
||||||
|
* tests/Makefile.am:
|
||||||
|
* tests/child-test.c: Test child_watch sources.
|
||||||
|
|
||||||
Sat Feb 7 15:02:01 2004 Manish Singh <yosh@gimp.org>
|
Sat Feb 7 15:02:01 2004 Manish Singh <yosh@gimp.org>
|
||||||
|
|
||||||
* tests/type-test.c: Fix broken test for gsize formats.
|
* tests/type-test.c: Fix broken test for gsize formats.
|
||||||
|
@@ -1,3 +1,18 @@
|
|||||||
|
Sat Feb 14 01:21:34 2004 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
|
* glib/gmain.h:
|
||||||
|
* glib/gmain.c (g_child_watch_source_new):
|
||||||
|
* glib/gmain.c (g_child_watch_add):
|
||||||
|
* glib/gmain.c (g_child_watch_add_full): Wrap waitpid() as a
|
||||||
|
GSource. This is a partial implementation of the "Unix signal
|
||||||
|
source". (#50296, Jonathan R. Blandford)
|
||||||
|
|
||||||
|
* configure.in: Add the necessary configury to typedef GPid
|
||||||
|
appropriately.
|
||||||
|
|
||||||
|
* tests/Makefile.am:
|
||||||
|
* tests/child-test.c: Test child_watch sources.
|
||||||
|
|
||||||
Sat Feb 7 15:02:01 2004 Manish Singh <yosh@gimp.org>
|
Sat Feb 7 15:02:01 2004 Manish Singh <yosh@gimp.org>
|
||||||
|
|
||||||
* tests/type-test.c: Fix broken test for gsize formats.
|
* tests/type-test.c: Fix broken test for gsize formats.
|
||||||
|
@@ -1,3 +1,18 @@
|
|||||||
|
Sat Feb 14 01:21:34 2004 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
|
* glib/gmain.h:
|
||||||
|
* glib/gmain.c (g_child_watch_source_new):
|
||||||
|
* glib/gmain.c (g_child_watch_add):
|
||||||
|
* glib/gmain.c (g_child_watch_add_full): Wrap waitpid() as a
|
||||||
|
GSource. This is a partial implementation of the "Unix signal
|
||||||
|
source". (#50296, Jonathan R. Blandford)
|
||||||
|
|
||||||
|
* configure.in: Add the necessary configury to typedef GPid
|
||||||
|
appropriately.
|
||||||
|
|
||||||
|
* tests/Makefile.am:
|
||||||
|
* tests/child-test.c: Test child_watch sources.
|
||||||
|
|
||||||
Sat Feb 7 15:02:01 2004 Manish Singh <yosh@gimp.org>
|
Sat Feb 7 15:02:01 2004 Manish Singh <yosh@gimp.org>
|
||||||
|
|
||||||
* tests/type-test.c: Fix broken test for gsize formats.
|
* tests/type-test.c: Fix broken test for gsize formats.
|
||||||
|
@@ -1,3 +1,18 @@
|
|||||||
|
Sat Feb 14 01:21:34 2004 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
|
* glib/gmain.h:
|
||||||
|
* glib/gmain.c (g_child_watch_source_new):
|
||||||
|
* glib/gmain.c (g_child_watch_add):
|
||||||
|
* glib/gmain.c (g_child_watch_add_full): Wrap waitpid() as a
|
||||||
|
GSource. This is a partial implementation of the "Unix signal
|
||||||
|
source". (#50296, Jonathan R. Blandford)
|
||||||
|
|
||||||
|
* configure.in: Add the necessary configury to typedef GPid
|
||||||
|
appropriately.
|
||||||
|
|
||||||
|
* tests/Makefile.am:
|
||||||
|
* tests/child-test.c: Test child_watch sources.
|
||||||
|
|
||||||
Sat Feb 7 15:02:01 2004 Manish Singh <yosh@gimp.org>
|
Sat Feb 7 15:02:01 2004 Manish Singh <yosh@gimp.org>
|
||||||
|
|
||||||
* tests/type-test.c: Fix broken test for gsize formats.
|
* tests/type-test.c: Fix broken test for gsize formats.
|
||||||
|
@@ -1,3 +1,18 @@
|
|||||||
|
Sat Feb 14 01:21:34 2004 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
|
* glib/gmain.h:
|
||||||
|
* glib/gmain.c (g_child_watch_source_new):
|
||||||
|
* glib/gmain.c (g_child_watch_add):
|
||||||
|
* glib/gmain.c (g_child_watch_add_full): Wrap waitpid() as a
|
||||||
|
GSource. This is a partial implementation of the "Unix signal
|
||||||
|
source". (#50296, Jonathan R. Blandford)
|
||||||
|
|
||||||
|
* configure.in: Add the necessary configury to typedef GPid
|
||||||
|
appropriately.
|
||||||
|
|
||||||
|
* tests/Makefile.am:
|
||||||
|
* tests/child-test.c: Test child_watch sources.
|
||||||
|
|
||||||
Sat Feb 7 15:02:01 2004 Manish Singh <yosh@gimp.org>
|
Sat Feb 7 15:02:01 2004 Manish Singh <yosh@gimp.org>
|
||||||
|
|
||||||
* tests/type-test.c: Fix broken test for gsize formats.
|
* tests/type-test.c: Fix broken test for gsize formats.
|
||||||
|
@@ -1,3 +1,18 @@
|
|||||||
|
Sat Feb 14 01:21:34 2004 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
|
* glib/gmain.h:
|
||||||
|
* glib/gmain.c (g_child_watch_source_new):
|
||||||
|
* glib/gmain.c (g_child_watch_add):
|
||||||
|
* glib/gmain.c (g_child_watch_add_full): Wrap waitpid() as a
|
||||||
|
GSource. This is a partial implementation of the "Unix signal
|
||||||
|
source". (#50296, Jonathan R. Blandford)
|
||||||
|
|
||||||
|
* configure.in: Add the necessary configury to typedef GPid
|
||||||
|
appropriately.
|
||||||
|
|
||||||
|
* tests/Makefile.am:
|
||||||
|
* tests/child-test.c: Test child_watch sources.
|
||||||
|
|
||||||
Sat Feb 7 15:02:01 2004 Manish Singh <yosh@gimp.org>
|
Sat Feb 7 15:02:01 2004 Manish Singh <yosh@gimp.org>
|
||||||
|
|
||||||
* tests/type-test.c: Fix broken test for gsize formats.
|
* tests/type-test.c: Fix broken test for gsize formats.
|
||||||
|
@@ -131,6 +131,7 @@ case "$host" in
|
|||||||
GOBJECT_DEF=gobject.def
|
GOBJECT_DEF=gobject.def
|
||||||
GTHREAD_DEF=gthread.def
|
GTHREAD_DEF=gthread.def
|
||||||
TESTGMODULE_EXP=testgmodule.exp
|
TESTGMODULE_EXP=testgmodule.exp
|
||||||
|
glib_pid_type=HANDLE
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
glib_native_win32=no
|
glib_native_win32=no
|
||||||
@@ -143,6 +144,7 @@ case "$host" in
|
|||||||
GOBJECT_DEF=
|
GOBJECT_DEF=
|
||||||
GTHREAD_DEF=
|
GTHREAD_DEF=
|
||||||
TESTGMODULE_EXP=
|
TESTGMODULE_EXP=
|
||||||
|
glib_pid_type=int
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
AC_MSG_RESULT([$glib_native_win32])
|
AC_MSG_RESULT([$glib_native_win32])
|
||||||
@@ -2265,6 +2267,8 @@ _______EOF
|
|||||||
|
|
||||||
#define G_MODULE_SUFFIX "$g_module_suffix"
|
#define G_MODULE_SUFFIX "$g_module_suffix"
|
||||||
|
|
||||||
|
typedef $g_pid_type GPid;
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* GLIBCONFIG_H */
|
#endif /* GLIBCONFIG_H */
|
||||||
@@ -2536,6 +2540,7 @@ g_mutex_contents="$glib_cv_byte_contents_gmutex"
|
|||||||
|
|
||||||
g_module_suffix="$glib_gmodule_suffix"
|
g_module_suffix="$glib_gmodule_suffix"
|
||||||
|
|
||||||
|
g_pid_type="$glib_pid_type"
|
||||||
case $host in
|
case $host in
|
||||||
*-*-beos*)
|
*-*-beos*)
|
||||||
glib_os="#define G_OS_BEOS"
|
glib_os="#define G_OS_BEOS"
|
||||||
|
@@ -1,3 +1,9 @@
|
|||||||
|
Sat Feb 14 01:25:23 2004 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
|
* glib/glib-sections.txt: Add GPid, GChildWatchFunc,
|
||||||
|
g_child_watch_source_new, g_child_watch_add,
|
||||||
|
g_child_watch_add_full.
|
||||||
|
|
||||||
Fri Feb 13 23:16:25 2004 Matthias Clasen <maclas@gmx.de>
|
Fri Feb 13 23:16:25 2004 Matthias Clasen <maclas@gmx.de>
|
||||||
|
|
||||||
* glib/tmpl/macros_misc.sgml: Fix a typo.
|
* glib/tmpl/macros_misc.sgml: Fix a typo.
|
||||||
|
@@ -426,6 +426,12 @@ g_idle_add
|
|||||||
g_idle_add_full
|
g_idle_add_full
|
||||||
g_idle_remove_by_data
|
g_idle_remove_by_data
|
||||||
|
|
||||||
|
<SUBSECTION>
|
||||||
|
GPid
|
||||||
|
GChildWatchFunc
|
||||||
|
g_child_watch_source_new
|
||||||
|
g_child_watch_add
|
||||||
|
g_child_watch_add_full
|
||||||
<SUBSECTION>
|
<SUBSECTION>
|
||||||
GPollFD
|
GPollFD
|
||||||
|
|
||||||
@@ -468,6 +474,7 @@ GLIB_SYSDEF_POLLPRI
|
|||||||
G_WIN32_MSG_HANDLE
|
G_WIN32_MSG_HANDLE
|
||||||
g_idle_funcs
|
g_idle_funcs
|
||||||
g_timeout_funcs
|
g_timeout_funcs
|
||||||
|
g_child_watch_funcs
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
|
432
glib/gmain.c
432
glib/gmain.c
@@ -62,9 +62,14 @@
|
|||||||
#include <net/socket.h>
|
#include <net/socket.h>
|
||||||
#endif /* G_OS_BEOS */
|
#endif /* G_OS_BEOS */
|
||||||
|
|
||||||
|
#ifdef G_OS_UNIX
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#endif
|
||||||
/* Types */
|
/* Types */
|
||||||
|
|
||||||
typedef struct _GTimeoutSource GTimeoutSource;
|
typedef struct _GTimeoutSource GTimeoutSource;
|
||||||
|
typedef struct _GChildWatchSource GChildWatchSource;
|
||||||
typedef struct _GPollRec GPollRec;
|
typedef struct _GPollRec GPollRec;
|
||||||
typedef struct _GSourceCallback GSourceCallback;
|
typedef struct _GSourceCallback GSourceCallback;
|
||||||
|
|
||||||
@@ -157,6 +162,15 @@ struct _GTimeoutSource
|
|||||||
guint interval;
|
guint interval;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct _GChildWatchSource
|
||||||
|
{
|
||||||
|
GSource source;
|
||||||
|
GPid pid;
|
||||||
|
gint child_status;
|
||||||
|
gint count;
|
||||||
|
gboolean child_exited;
|
||||||
|
};
|
||||||
|
|
||||||
struct _GPollRec
|
struct _GPollRec
|
||||||
{
|
{
|
||||||
gint priority;
|
gint priority;
|
||||||
@@ -175,8 +189,6 @@ struct _GPollRec
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SOURCE_DESTROYED(source) (((source)->flags & G_HOOK_FLAG_ACTIVE) == 0)
|
#define SOURCE_DESTROYED(source) (((source)->flags & G_HOOK_FLAG_ACTIVE) == 0)
|
||||||
#define SOURCE_BLOCKED(source) (((source)->flags & G_HOOK_FLAG_IN_CALL) != 0 && \
|
|
||||||
((source)->flags & G_SOURCE_CAN_RECURSE) == 0)
|
|
||||||
|
|
||||||
#define SOURCE_UNREF(source, context) \
|
#define SOURCE_UNREF(source, context) \
|
||||||
G_STMT_START { \
|
G_STMT_START { \
|
||||||
@@ -213,6 +225,12 @@ static gboolean g_timeout_check (GSource *source);
|
|||||||
static gboolean g_timeout_dispatch (GSource *source,
|
static gboolean g_timeout_dispatch (GSource *source,
|
||||||
GSourceFunc callback,
|
GSourceFunc callback,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
static gboolean g_child_watch_prepare (GSource *source,
|
||||||
|
gint *timeout);
|
||||||
|
static gboolean g_child_watch_check (GSource *source);
|
||||||
|
static gboolean g_child_watch_dispatch (GSource *source,
|
||||||
|
GSourceFunc callback,
|
||||||
|
gpointer user_data);
|
||||||
static gboolean g_idle_prepare (GSource *source,
|
static gboolean g_idle_prepare (GSource *source,
|
||||||
gint *timeout);
|
gint *timeout);
|
||||||
static gboolean g_idle_check (GSource *source);
|
static gboolean g_idle_check (GSource *source);
|
||||||
@@ -224,6 +242,18 @@ G_LOCK_DEFINE_STATIC (main_loop);
|
|||||||
static GMainContext *default_main_context;
|
static GMainContext *default_main_context;
|
||||||
static GSList *main_contexts_without_pipe = NULL;
|
static GSList *main_contexts_without_pipe = NULL;
|
||||||
|
|
||||||
|
/* Child status monitoring code */
|
||||||
|
enum {
|
||||||
|
CHILD_WATCH_UNINITIALIZED,
|
||||||
|
CHILD_WATCH_INITIALIZED_SINGLE,
|
||||||
|
CHILD_WATCH_INITIALIZED_THREADED
|
||||||
|
};
|
||||||
|
static gint child_watch_init_state = CHILD_WATCH_UNINITIALIZED;
|
||||||
|
static gint child_watch_count = 0;
|
||||||
|
static gint child_watch_wake_up_pipe[2] = {0, 0};
|
||||||
|
G_LOCK_DEFINE_STATIC (main_context_list);
|
||||||
|
static GSList *main_context_list = NULL;
|
||||||
|
|
||||||
#if defined(G_PLATFORM_WIN32) && defined(__GNUC__)
|
#if defined(G_PLATFORM_WIN32) && defined(__GNUC__)
|
||||||
__declspec(dllexport)
|
__declspec(dllexport)
|
||||||
#endif
|
#endif
|
||||||
@@ -235,6 +265,14 @@ GSourceFuncs g_timeout_funcs =
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
GSourceFuncs g_child_watch_funcs =
|
||||||
|
{
|
||||||
|
g_child_watch_prepare,
|
||||||
|
g_child_watch_check,
|
||||||
|
g_child_watch_dispatch,
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
#if defined(G_PLATFORM_WIN32) && defined(__GNUC__)
|
#if defined(G_PLATFORM_WIN32) && defined(__GNUC__)
|
||||||
__declspec(dllexport)
|
__declspec(dllexport)
|
||||||
#endif
|
#endif
|
||||||
@@ -586,6 +624,10 @@ g_main_context_unref_and_unlock (GMainContext *context)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
G_LOCK (main_context_list);
|
||||||
|
main_context_list = g_slist_remove (main_context_list, context);
|
||||||
|
G_UNLOCK (main_context_list);
|
||||||
|
|
||||||
source = context->source_list;
|
source = context->source_list;
|
||||||
while (source)
|
while (source)
|
||||||
{
|
{
|
||||||
@@ -649,6 +691,8 @@ g_main_context_unref (GMainContext *context)
|
|||||||
static void
|
static void
|
||||||
g_main_context_init_pipe (GMainContext *context)
|
g_main_context_init_pipe (GMainContext *context)
|
||||||
{
|
{
|
||||||
|
if (context->wake_up_pipe[0] != -1)
|
||||||
|
return;
|
||||||
# ifndef G_OS_WIN32
|
# ifndef G_OS_WIN32
|
||||||
if (pipe (context->wake_up_pipe) < 0)
|
if (pipe (context->wake_up_pipe) < 0)
|
||||||
g_error ("Cannot create pipe main loop wake-up: %s\n",
|
g_error ("Cannot create pipe main loop wake-up: %s\n",
|
||||||
@@ -702,7 +746,10 @@ g_main_context_new ()
|
|||||||
context->owner = NULL;
|
context->owner = NULL;
|
||||||
context->waiters = NULL;
|
context->waiters = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
context->wake_up_pipe[0] = -1;
|
||||||
|
context->wake_up_pipe[1] = -1;
|
||||||
|
|
||||||
context->ref_count = 1;
|
context->ref_count = 1;
|
||||||
|
|
||||||
context->next_id = 1;
|
context->next_id = 1;
|
||||||
@@ -730,6 +777,10 @@ g_main_context_new ()
|
|||||||
context);
|
context);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
G_LOCK (main_context_list);
|
||||||
|
main_context_list = g_slist_append (main_context_list, context);
|
||||||
|
G_UNLOCK (main_context_list);
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -920,17 +971,14 @@ g_source_destroy_internal (GSource *source,
|
|||||||
old_cb_funcs->unref (old_cb_data);
|
old_cb_funcs->unref (old_cb_data);
|
||||||
LOCK_CONTEXT (context);
|
LOCK_CONTEXT (context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SOURCE_BLOCKED (source))
|
tmp_list = source->poll_fds;
|
||||||
|
while (tmp_list)
|
||||||
{
|
{
|
||||||
tmp_list = source->poll_fds;
|
g_main_context_remove_poll_unlocked (context, tmp_list->data);
|
||||||
while (tmp_list)
|
tmp_list = tmp_list->next;
|
||||||
{
|
|
||||||
g_main_context_remove_poll_unlocked (context, tmp_list->data);
|
|
||||||
tmp_list = tmp_list->next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_source_unref_internal (source, context, TRUE);
|
g_source_unref_internal (source, context, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1036,8 +1084,7 @@ g_source_add_poll (GSource *source,
|
|||||||
|
|
||||||
if (context)
|
if (context)
|
||||||
{
|
{
|
||||||
if (!SOURCE_BLOCKED (source))
|
g_main_context_add_poll_unlocked (context, source->priority, fd);
|
||||||
g_main_context_add_poll_unlocked (context, source->priority, fd);
|
|
||||||
UNLOCK_CONTEXT (context);
|
UNLOCK_CONTEXT (context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1069,8 +1116,7 @@ g_source_remove_poll (GSource *source,
|
|||||||
|
|
||||||
if (context)
|
if (context)
|
||||||
{
|
{
|
||||||
if (!SOURCE_BLOCKED (source))
|
g_main_context_remove_poll_unlocked (context, fd);
|
||||||
g_main_context_remove_poll_unlocked (context, fd);
|
|
||||||
UNLOCK_CONTEXT (context);
|
UNLOCK_CONTEXT (context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1224,22 +1270,16 @@ g_source_set_priority (GSource *source,
|
|||||||
|
|
||||||
if (context)
|
if (context)
|
||||||
{
|
{
|
||||||
/* Remove the source from the context's source and then
|
source->next = NULL;
|
||||||
* add it back so it is sorted in the correct plcae
|
source->prev = NULL;
|
||||||
*/
|
|
||||||
g_source_list_remove (source, source->context);
|
tmp_list = source->poll_fds;
|
||||||
g_source_list_add (source, source->context);
|
while (tmp_list)
|
||||||
|
|
||||||
if (!SOURCE_BLOCKED (source))
|
|
||||||
{
|
{
|
||||||
tmp_list = source->poll_fds;
|
g_main_context_remove_poll_unlocked (context, tmp_list->data);
|
||||||
while (tmp_list)
|
g_main_context_add_poll_unlocked (context, priority, tmp_list->data);
|
||||||
{
|
|
||||||
g_main_context_remove_poll_unlocked (context, tmp_list->data);
|
tmp_list = tmp_list->next;
|
||||||
g_main_context_add_poll_unlocked (context, priority, tmp_list->data);
|
|
||||||
|
|
||||||
tmp_list = tmp_list->next;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UNLOCK_CONTEXT (source->context);
|
UNLOCK_CONTEXT (source->context);
|
||||||
@@ -1543,11 +1583,11 @@ g_main_context_find_source_by_user_data (GMainContext *context,
|
|||||||
* g_source_remove:
|
* g_source_remove:
|
||||||
* @tag: the id of the source to remove.
|
* @tag: the id of the source to remove.
|
||||||
*
|
*
|
||||||
* Removes the source with the given id from the default main
|
* Removes the source with the given id from the default main context. The id of
|
||||||
* context. The id of a #GSource is given by g_source_get_id(),
|
* a #GSource is given by g_source_get_id(), or will be returned by the
|
||||||
* or will be returned by the functions g_source_attach(),
|
* functions g_source_attach(), g_idle_add(), g_idle_add_full(),
|
||||||
* g_idle_add(), g_idle_add_full(), g_timeout_add(),
|
* g_timeout_add(), g_timeout_add_full(), g_child_watch_add(),
|
||||||
* g_timeout_add_full(), g_io_add_watch, and g_io_add_watch_full().
|
* g_child_watch_add_full(), g_io_add_watch(), and g_io_add_watch_full().
|
||||||
*
|
*
|
||||||
* See also g_source_destroy().
|
* See also g_source_destroy().
|
||||||
*
|
*
|
||||||
@@ -1666,43 +1706,6 @@ g_get_current_time (GTimeVal *result)
|
|||||||
|
|
||||||
/* Running the main loop */
|
/* Running the main loop */
|
||||||
|
|
||||||
/* Temporarily remove all this source's file descriptors from the
|
|
||||||
* poll(), so that if data comes available for one of the file descriptors
|
|
||||||
* we don't continually spin in the poll()
|
|
||||||
*/
|
|
||||||
/* HOLDS: source->context's lock */
|
|
||||||
void
|
|
||||||
block_source (GSource *source)
|
|
||||||
{
|
|
||||||
GSList *tmp_list;
|
|
||||||
|
|
||||||
g_return_if_fail (!SOURCE_BLOCKED (source));
|
|
||||||
|
|
||||||
tmp_list = source->poll_fds;
|
|
||||||
while (tmp_list)
|
|
||||||
{
|
|
||||||
g_main_context_remove_poll_unlocked (source->context, tmp_list->data);
|
|
||||||
tmp_list = tmp_list->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HOLDS: source->context's lock */
|
|
||||||
void
|
|
||||||
unblock_source (GSource *source)
|
|
||||||
{
|
|
||||||
GSList *tmp_list;
|
|
||||||
|
|
||||||
g_return_if_fail (!SOURCE_BLOCKED (source)); /* Source already unblocked */
|
|
||||||
g_return_if_fail (!SOURCE_DESTROYED (source));
|
|
||||||
|
|
||||||
tmp_list = source->poll_fds;
|
|
||||||
while (tmp_list)
|
|
||||||
{
|
|
||||||
g_main_context_add_poll_unlocked (source->context, source->priority, tmp_list->data);
|
|
||||||
tmp_list = tmp_list->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* HOLDS: context's lock */
|
/* HOLDS: context's lock */
|
||||||
static void
|
static void
|
||||||
g_main_dispatch (GMainContext *context)
|
g_main_dispatch (GMainContext *context)
|
||||||
@@ -1738,9 +1741,6 @@ g_main_dispatch (GMainContext *context)
|
|||||||
if (cb_funcs)
|
if (cb_funcs)
|
||||||
cb_funcs->ref (cb_data);
|
cb_funcs->ref (cb_data);
|
||||||
|
|
||||||
if ((source->flags & G_SOURCE_CAN_RECURSE) == 0)
|
|
||||||
block_source (source);
|
|
||||||
|
|
||||||
was_in_call = source->flags & G_HOOK_FLAG_IN_CALL;
|
was_in_call = source->flags & G_HOOK_FLAG_IN_CALL;
|
||||||
source->flags |= G_HOOK_FLAG_IN_CALL;
|
source->flags |= G_HOOK_FLAG_IN_CALL;
|
||||||
|
|
||||||
@@ -1760,10 +1760,6 @@ g_main_dispatch (GMainContext *context)
|
|||||||
if (!was_in_call)
|
if (!was_in_call)
|
||||||
source->flags &= ~G_HOOK_FLAG_IN_CALL;
|
source->flags &= ~G_HOOK_FLAG_IN_CALL;
|
||||||
|
|
||||||
if ((source->flags & G_SOURCE_CAN_RECURSE) == 0 &&
|
|
||||||
!SOURCE_DESTROYED (source))
|
|
||||||
unblock_source (source);
|
|
||||||
|
|
||||||
/* Note: this depends on the fact that we can't switch
|
/* Note: this depends on the fact that we can't switch
|
||||||
* sources from one main context to another
|
* sources from one main context to another
|
||||||
*/
|
*/
|
||||||
@@ -2052,7 +2048,7 @@ g_main_context_prepare (GMainContext *context,
|
|||||||
SOURCE_UNREF (source, context);
|
SOURCE_UNREF (source, context);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (SOURCE_BLOCKED (source))
|
if ((source->flags & G_HOOK_FLAG_IN_CALL) && !(source->flags & G_SOURCE_CAN_RECURSE))
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
if (!(source->flags & G_SOURCE_READY))
|
if (!(source->flags & G_SOURCE_READY))
|
||||||
@@ -2203,8 +2199,8 @@ g_main_context_check (GMainContext *context,
|
|||||||
if (!context->poll_waiting)
|
if (!context->poll_waiting)
|
||||||
{
|
{
|
||||||
#ifndef G_OS_WIN32
|
#ifndef G_OS_WIN32
|
||||||
gchar c;
|
gchar a;
|
||||||
read (context->wake_up_pipe[0], &c, 1);
|
read (context->wake_up_pipe[0], &a, 1);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2240,7 +2236,7 @@ g_main_context_check (GMainContext *context,
|
|||||||
SOURCE_UNREF (source, context);
|
SOURCE_UNREF (source, context);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (SOURCE_BLOCKED (source))
|
if ((source->flags & G_HOOK_FLAG_IN_CALL) && !(source->flags & G_SOURCE_CAN_RECURSE))
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
if (!(source->flags & G_SOURCE_READY))
|
if (!(source->flags & G_SOURCE_READY))
|
||||||
@@ -3241,6 +3237,274 @@ g_timeout_add (guint32 interval,
|
|||||||
interval, function, data, NULL);
|
interval, function, data, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Child watch functions */
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_for_child_exited (GSource *source)
|
||||||
|
{
|
||||||
|
GChildWatchSource *child_watch_source;
|
||||||
|
gint count;
|
||||||
|
|
||||||
|
/* protect against another SIGCHLD in the middle of this call */
|
||||||
|
count = child_watch_count;
|
||||||
|
|
||||||
|
child_watch_source = (GChildWatchSource *) source;
|
||||||
|
|
||||||
|
if (child_watch_source->count < count)
|
||||||
|
{
|
||||||
|
gint child_status;
|
||||||
|
|
||||||
|
if (waitpid (child_watch_source->pid, &child_status, WNOHANG) > 0)
|
||||||
|
{
|
||||||
|
child_watch_source->child_status = child_status;
|
||||||
|
child_watch_source->child_exited = TRUE;
|
||||||
|
}
|
||||||
|
child_watch_source->count = count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
g_child_watch_prepare (GSource *source,
|
||||||
|
gint *timeout)
|
||||||
|
{
|
||||||
|
GChildWatchSource *child_watch_source;
|
||||||
|
*timeout = -1;
|
||||||
|
|
||||||
|
child_watch_source = (GChildWatchSource *) source;
|
||||||
|
|
||||||
|
check_for_child_exited (source);
|
||||||
|
|
||||||
|
return child_watch_source->child_exited;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
g_child_watch_check (GSource *source)
|
||||||
|
{
|
||||||
|
GChildWatchSource *child_watch_source;
|
||||||
|
|
||||||
|
child_watch_source = (GChildWatchSource *) source;
|
||||||
|
|
||||||
|
return (child_watch_source->count < child_watch_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
g_child_watch_dispatch (GSource *source,
|
||||||
|
GSourceFunc callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GChildWatchSource *child_watch_source;
|
||||||
|
GChildWatchFunc child_watch_callback = (GChildWatchFunc) callback;
|
||||||
|
|
||||||
|
child_watch_source = (GChildWatchSource *) source;
|
||||||
|
|
||||||
|
if (!callback)
|
||||||
|
{
|
||||||
|
g_warning ("Child watch source dispatched without callback\n"
|
||||||
|
"You must call g_source_set_callback().");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
(child_watch_callback) (child_watch_source->pid, child_watch_source->child_status, user_data);
|
||||||
|
|
||||||
|
/* We never keep a child watch source around as the child is gone */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_child_watch_signal_handler (int signum)
|
||||||
|
{
|
||||||
|
child_watch_count ++;
|
||||||
|
|
||||||
|
if (child_watch_init_state == CHILD_WATCH_INITIALIZED_THREADED)
|
||||||
|
{
|
||||||
|
write (child_watch_wake_up_pipe[1], "B", 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We count on the signal interrupting the poll in the same thread.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_child_watch_source_init_single (void)
|
||||||
|
{
|
||||||
|
g_assert (! g_thread_supported());
|
||||||
|
g_assert (child_watch_init_state == CHILD_WATCH_UNINITIALIZED);
|
||||||
|
|
||||||
|
child_watch_init_state = CHILD_WATCH_INITIALIZED_SINGLE;
|
||||||
|
|
||||||
|
signal (SIGCHLD, g_child_watch_signal_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpointer
|
||||||
|
child_watch_helper_thread (gpointer data)
|
||||||
|
{
|
||||||
|
GPollFD fds;
|
||||||
|
GPollFunc poll_func;
|
||||||
|
|
||||||
|
#ifdef HAVE_POLL
|
||||||
|
poll_func = (GPollFunc)poll;
|
||||||
|
#else
|
||||||
|
poll_func = g_poll;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fds.fd = child_watch_wake_up_pipe[0];
|
||||||
|
fds.events = G_IO_IN;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
gchar b[20];
|
||||||
|
GSList *list;
|
||||||
|
|
||||||
|
read (child_watch_wake_up_pipe[0], b, 20);
|
||||||
|
|
||||||
|
/* We were woken up. Wake up all other contexts in all other threads */
|
||||||
|
G_UNLOCK (main_context_list);
|
||||||
|
for (list = main_context_list; list; list = list->next)
|
||||||
|
{
|
||||||
|
GMainContext *context;
|
||||||
|
|
||||||
|
context = list->data;
|
||||||
|
g_main_context_wakeup (context);
|
||||||
|
}
|
||||||
|
G_LOCK (main_context_list);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_child_watch_source_init_multi_threaded (void)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
g_assert (g_thread_supported());
|
||||||
|
|
||||||
|
if (pipe (child_watch_wake_up_pipe) < 0)
|
||||||
|
g_error ("Cannot create wake up pipe: %s\n", g_strerror (errno));
|
||||||
|
fcntl (child_watch_wake_up_pipe[1], F_SETFL, O_NONBLOCK | fcntl (child_watch_wake_up_pipe[1], F_GETFL));
|
||||||
|
|
||||||
|
/* We create a helper thread that polls on the wakeup pipe indefinitely */
|
||||||
|
/* FIXME: Think this through for races */
|
||||||
|
if (g_thread_create (child_watch_helper_thread, NULL, FALSE, &error) == NULL)
|
||||||
|
g_error ("Cannot create a thread to monitor child exit status: %s\n", error->message);
|
||||||
|
child_watch_init_state = CHILD_WATCH_INITIALIZED_THREADED;
|
||||||
|
signal (SIGCHLD, g_child_watch_signal_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_child_watch_source_init_promote_single_to_threaded (void)
|
||||||
|
{
|
||||||
|
g_child_watch_source_init_multi_threaded ();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_child_watch_source_init (void)
|
||||||
|
{
|
||||||
|
if (g_thread_supported())
|
||||||
|
{
|
||||||
|
if (child_watch_init_state == CHILD_WATCH_UNINITIALIZED)
|
||||||
|
g_child_watch_source_init_multi_threaded ();
|
||||||
|
else if (child_watch_init_state == CHILD_WATCH_INITIALIZED_SINGLE)
|
||||||
|
g_child_watch_source_init_promote_single_to_threaded ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (child_watch_init_state == CHILD_WATCH_UNINITIALIZED)
|
||||||
|
g_child_watch_source_init_single ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_child_watch_source_new:
|
||||||
|
* @pid: process id of a child process to watch
|
||||||
|
*
|
||||||
|
* Creates a new child_watch source.
|
||||||
|
*
|
||||||
|
* The source will not initially be associated with any #GMainContext
|
||||||
|
* and must be added to one with g_source_attach() before it will be
|
||||||
|
* executed.
|
||||||
|
*
|
||||||
|
* Return value: the newly-created child watch source
|
||||||
|
*
|
||||||
|
* Since: 2.4
|
||||||
|
**/
|
||||||
|
GSource *
|
||||||
|
g_child_watch_source_new (GPid pid)
|
||||||
|
{
|
||||||
|
GSource *source = g_source_new (&g_child_watch_funcs, sizeof (GChildWatchSource));
|
||||||
|
GChildWatchSource *child_watch_source = (GChildWatchSource *)source;
|
||||||
|
|
||||||
|
g_child_watch_source_init ();
|
||||||
|
|
||||||
|
child_watch_source->pid = pid;
|
||||||
|
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_child_watch_add_full:
|
||||||
|
* @priority: the priority of the idle source. Typically this will be in the
|
||||||
|
* range between #G_PRIORITY_DEFAULT_IDLE and #G_PRIORITY_HIGH_IDLE.
|
||||||
|
* @pid: process id of a child process to watch
|
||||||
|
* @function: function to call
|
||||||
|
* @data: data to pass to @function
|
||||||
|
* @notify: function to call when the idle is removed, or %NULL
|
||||||
|
*
|
||||||
|
* Sets a function to be called when the child indicated by @pid exits, at a
|
||||||
|
* default priority, #G_PRIORITY_DEFAULT.
|
||||||
|
*
|
||||||
|
* Return value: the id of event source.
|
||||||
|
*
|
||||||
|
* Since: 2.4
|
||||||
|
**/
|
||||||
|
guint
|
||||||
|
g_child_watch_add_full (gint priority,
|
||||||
|
GPid pid,
|
||||||
|
GChildWatchFunc function,
|
||||||
|
gpointer data,
|
||||||
|
GDestroyNotify notify)
|
||||||
|
{
|
||||||
|
GSource *source;
|
||||||
|
guint id;
|
||||||
|
|
||||||
|
g_return_val_if_fail (function != NULL, 0);
|
||||||
|
|
||||||
|
source = g_child_watch_source_new (pid);
|
||||||
|
|
||||||
|
if (priority != G_PRIORITY_DEFAULT)
|
||||||
|
g_source_set_priority (source, priority);
|
||||||
|
|
||||||
|
g_source_set_callback (source, (GSourceFunc) function, data, notify);
|
||||||
|
id = g_source_attach (source, NULL);
|
||||||
|
g_source_unref (source);
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* g_child_watch_add:
|
||||||
|
* @pid: process id of a child process to watch
|
||||||
|
* @function: function to call
|
||||||
|
* @data: data to pass to @function
|
||||||
|
*
|
||||||
|
* Sets a function to be called when the child indicated by @pid exits, at a
|
||||||
|
* default priority, #G_PRIORITY_DEFAULT.
|
||||||
|
*
|
||||||
|
* Return value: the id of event source.
|
||||||
|
*
|
||||||
|
* Since: 2.4
|
||||||
|
**/
|
||||||
|
guint
|
||||||
|
g_child_watch_add (GPid pid,
|
||||||
|
GChildWatchFunc function,
|
||||||
|
gpointer data)
|
||||||
|
{
|
||||||
|
return g_child_watch_add_full (G_PRIORITY_DEFAULT, pid, function, data, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Idle functions */
|
/* Idle functions */
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
50
glib/gmain.h
50
glib/gmain.h
@@ -32,7 +32,9 @@ typedef struct _GSourceCallbackFuncs GSourceCallbackFuncs;
|
|||||||
typedef struct _GSourceFuncs GSourceFuncs;
|
typedef struct _GSourceFuncs GSourceFuncs;
|
||||||
|
|
||||||
typedef gboolean (*GSourceFunc) (gpointer data);
|
typedef gboolean (*GSourceFunc) (gpointer data);
|
||||||
|
typedef void (*GChildWatchFunc) (GPid pid,
|
||||||
|
gint status,
|
||||||
|
gpointer data);
|
||||||
struct _GSource
|
struct _GSource
|
||||||
{
|
{
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
@@ -243,8 +245,9 @@ void g_source_get_current_time (GSource *source,
|
|||||||
|
|
||||||
/* Specific source types
|
/* Specific source types
|
||||||
*/
|
*/
|
||||||
GSource *g_idle_source_new (void);
|
GSource *g_idle_source_new (void);
|
||||||
GSource *g_timeout_source_new (guint interval);
|
GSource *g_child_watch_source_new (GPid pid);
|
||||||
|
GSource *g_timeout_source_new (guint interval);
|
||||||
|
|
||||||
/* Miscellaneous functions
|
/* Miscellaneous functions
|
||||||
*/
|
*/
|
||||||
@@ -278,25 +281,34 @@ gboolean g_source_remove_by_user_data (gpointer user_data);
|
|||||||
gboolean g_source_remove_by_funcs_user_data (GSourceFuncs *funcs,
|
gboolean g_source_remove_by_funcs_user_data (GSourceFuncs *funcs,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
|
|
||||||
/* Idles and timeouts */
|
/* Idles, child watchers and timeouts */
|
||||||
guint g_timeout_add_full (gint priority,
|
guint g_timeout_add_full (gint priority,
|
||||||
guint interval,
|
guint interval,
|
||||||
GSourceFunc function,
|
GSourceFunc function,
|
||||||
gpointer data,
|
gpointer data,
|
||||||
GDestroyNotify notify);
|
GDestroyNotify notify);
|
||||||
guint g_timeout_add (guint interval,
|
guint g_timeout_add (guint interval,
|
||||||
GSourceFunc function,
|
GSourceFunc function,
|
||||||
gpointer data);
|
gpointer data);
|
||||||
guint g_idle_add (GSourceFunc function,
|
guint g_child_watch_add_full (gint priority,
|
||||||
gpointer data);
|
GPid pid,
|
||||||
guint g_idle_add_full (gint priority,
|
GChildWatchFunc function,
|
||||||
GSourceFunc function,
|
gpointer data,
|
||||||
gpointer data,
|
GDestroyNotify notify);
|
||||||
GDestroyNotify notify);
|
guint g_child_watch_add (GPid pid,
|
||||||
gboolean g_idle_remove_by_data (gpointer data);
|
GChildWatchFunc 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);
|
||||||
|
|
||||||
/* Hook for GClosure / GSource integration. Don't touch */
|
/* Hook for GClosure / GSource integration. Don't touch */
|
||||||
GLIB_VAR GSourceFuncs g_timeout_funcs;
|
GLIB_VAR GSourceFuncs g_timeout_funcs;
|
||||||
|
GLIB_VAR GSourceFuncs g_child_watch_funcs;
|
||||||
GLIB_VAR GSourceFuncs g_idle_funcs;
|
GLIB_VAR GSourceFuncs g_idle_funcs;
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
@@ -66,6 +66,7 @@ endif
|
|||||||
test_programs = \
|
test_programs = \
|
||||||
array-test \
|
array-test \
|
||||||
$(CXX_TEST) \
|
$(CXX_TEST) \
|
||||||
|
child-test \
|
||||||
completion-test \
|
completion-test \
|
||||||
date-test \
|
date-test \
|
||||||
dirname-test \
|
dirname-test \
|
||||||
@@ -115,6 +116,7 @@ thread_ldadd = $(libgthread) $(G_THREAD_LIBS) $(progs_ldadd)
|
|||||||
module_ldadd = $(libgmodule) $(G_MODULE_LIBS) $(progs_ldadd)
|
module_ldadd = $(libgmodule) $(G_MODULE_LIBS) $(progs_ldadd)
|
||||||
|
|
||||||
array_test_LDADD = $(progs_ldadd)
|
array_test_LDADD = $(progs_ldadd)
|
||||||
|
child_test_LDADD = $(thread_ldadd)
|
||||||
completion_test_LDADD = $(progs_ldadd)
|
completion_test_LDADD = $(progs_ldadd)
|
||||||
date_test_LDADD = $(progs_ldadd)
|
date_test_LDADD = $(progs_ldadd)
|
||||||
dirname_test_LDADD = $(progs_ldadd)
|
dirname_test_LDADD = $(progs_ldadd)
|
||||||
|
101
tests/child-test.c
Normal file
101
tests/child-test.c
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
/* GLIB - Library of useful routines for C programming
|
||||||
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this library; if not, write to the
|
||||||
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
|
* Boston, MA 02111-1307, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
|
GMainLoop *main_loop;
|
||||||
|
gint alive;
|
||||||
|
|
||||||
|
gint
|
||||||
|
get_a_child (gint ttl)
|
||||||
|
{
|
||||||
|
GPid pid;
|
||||||
|
|
||||||
|
pid = fork ();
|
||||||
|
if (pid < 0)
|
||||||
|
exit (1);
|
||||||
|
|
||||||
|
if (pid > 0)
|
||||||
|
return pid;
|
||||||
|
|
||||||
|
sleep (ttl);
|
||||||
|
_exit (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
child_watch_callback (GPid pid, gint status, gpointer data)
|
||||||
|
{
|
||||||
|
g_print ("child %d exited, status %d\n", pid, status);
|
||||||
|
|
||||||
|
if (--alive == 0)
|
||||||
|
g_main_loop_quit (main_loop);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gpointer
|
||||||
|
test_thread (gpointer data)
|
||||||
|
{
|
||||||
|
GMainLoop *new_main_loop;
|
||||||
|
GSource *source;
|
||||||
|
GPid pid;
|
||||||
|
gint ttl = GPOINTER_TO_INT (data);
|
||||||
|
|
||||||
|
new_main_loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
|
||||||
|
pid = get_a_child (ttl);
|
||||||
|
source = g_child_watch_source_new (pid);
|
||||||
|
g_source_set_callback (source, (GSourceFunc) child_watch_callback, NULL, NULL);
|
||||||
|
g_source_attach (source, g_main_loop_get_context (new_main_loop));
|
||||||
|
g_source_unref (source);
|
||||||
|
|
||||||
|
g_print ("whee! created pid: %d\n", pid);
|
||||||
|
g_main_loop_run (new_main_loop);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (int argc, char *argv[])
|
||||||
|
{
|
||||||
|
g_thread_init (NULL);
|
||||||
|
main_loop = g_main_loop_new (NULL, FALSE);
|
||||||
|
|
||||||
|
system ("/bin/true");
|
||||||
|
|
||||||
|
alive = 2;
|
||||||
|
g_thread_create (test_thread, GINT_TO_POINTER (10), FALSE, NULL);
|
||||||
|
g_thread_create (test_thread, GINT_TO_POINTER (20), FALSE, NULL);
|
||||||
|
|
||||||
|
g_main_loop_run (main_loop);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Reference in New Issue
Block a user