mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-06-01 10:20:07 +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:
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>
|
||||
|
||||
* 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>
|
||||
|
||||
* 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>
|
||||
|
||||
* 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>
|
||||
|
||||
* 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>
|
||||
|
||||
* 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>
|
||||
|
||||
* tests/type-test.c: Fix broken test for gsize formats.
|
||||
|
@ -131,6 +131,7 @@ case "$host" in
|
||||
GOBJECT_DEF=gobject.def
|
||||
GTHREAD_DEF=gthread.def
|
||||
TESTGMODULE_EXP=testgmodule.exp
|
||||
glib_pid_type=HANDLE
|
||||
;;
|
||||
*)
|
||||
glib_native_win32=no
|
||||
@ -143,6 +144,7 @@ case "$host" in
|
||||
GOBJECT_DEF=
|
||||
GTHREAD_DEF=
|
||||
TESTGMODULE_EXP=
|
||||
glib_pid_type=int
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT([$glib_native_win32])
|
||||
@ -2265,6 +2267,8 @@ _______EOF
|
||||
|
||||
#define G_MODULE_SUFFIX "$g_module_suffix"
|
||||
|
||||
typedef $g_pid_type GPid;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* GLIBCONFIG_H */
|
||||
@ -2536,6 +2540,7 @@ g_mutex_contents="$glib_cv_byte_contents_gmutex"
|
||||
|
||||
g_module_suffix="$glib_gmodule_suffix"
|
||||
|
||||
g_pid_type="$glib_pid_type"
|
||||
case $host in
|
||||
*-*-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>
|
||||
|
||||
* glib/tmpl/macros_misc.sgml: Fix a typo.
|
||||
|
@ -426,6 +426,12 @@ g_idle_add
|
||||
g_idle_add_full
|
||||
g_idle_remove_by_data
|
||||
|
||||
<SUBSECTION>
|
||||
GPid
|
||||
GChildWatchFunc
|
||||
g_child_watch_source_new
|
||||
g_child_watch_add
|
||||
g_child_watch_add_full
|
||||
<SUBSECTION>
|
||||
GPollFD
|
||||
|
||||
@ -468,6 +474,7 @@ GLIB_SYSDEF_POLLPRI
|
||||
G_WIN32_MSG_HANDLE
|
||||
g_idle_funcs
|
||||
g_timeout_funcs
|
||||
g_child_watch_funcs
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
|
432
glib/gmain.c
432
glib/gmain.c
@ -62,9 +62,14 @@
|
||||
#include <net/socket.h>
|
||||
#endif /* G_OS_BEOS */
|
||||
|
||||
#ifdef G_OS_UNIX
|
||||
#include <fcntl.h>
|
||||
#include <sys/wait.h>
|
||||
#endif
|
||||
/* Types */
|
||||
|
||||
typedef struct _GTimeoutSource GTimeoutSource;
|
||||
typedef struct _GChildWatchSource GChildWatchSource;
|
||||
typedef struct _GPollRec GPollRec;
|
||||
typedef struct _GSourceCallback GSourceCallback;
|
||||
|
||||
@ -157,6 +162,15 @@ struct _GTimeoutSource
|
||||
guint interval;
|
||||
};
|
||||
|
||||
struct _GChildWatchSource
|
||||
{
|
||||
GSource source;
|
||||
GPid pid;
|
||||
gint child_status;
|
||||
gint count;
|
||||
gboolean child_exited;
|
||||
};
|
||||
|
||||
struct _GPollRec
|
||||
{
|
||||
gint priority;
|
||||
@ -175,8 +189,6 @@ struct _GPollRec
|
||||
#endif
|
||||
|
||||
#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) \
|
||||
G_STMT_START { \
|
||||
@ -213,6 +225,12 @@ static gboolean g_timeout_check (GSource *source);
|
||||
static gboolean g_timeout_dispatch (GSource *source,
|
||||
GSourceFunc callback,
|
||||
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,
|
||||
gint *timeout);
|
||||
static gboolean g_idle_check (GSource *source);
|
||||
@ -224,6 +242,18 @@ G_LOCK_DEFINE_STATIC (main_loop);
|
||||
static GMainContext *default_main_context;
|
||||
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__)
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
@ -235,6 +265,14 @@ GSourceFuncs g_timeout_funcs =
|
||||
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__)
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
@ -586,6 +624,10 @@ g_main_context_unref_and_unlock (GMainContext *context)
|
||||
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;
|
||||
while (source)
|
||||
{
|
||||
@ -649,6 +691,8 @@ g_main_context_unref (GMainContext *context)
|
||||
static void
|
||||
g_main_context_init_pipe (GMainContext *context)
|
||||
{
|
||||
if (context->wake_up_pipe[0] != -1)
|
||||
return;
|
||||
# ifndef G_OS_WIN32
|
||||
if (pipe (context->wake_up_pipe) < 0)
|
||||
g_error ("Cannot create pipe main loop wake-up: %s\n",
|
||||
@ -702,7 +746,10 @@ g_main_context_new ()
|
||||
context->owner = NULL;
|
||||
context->waiters = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
context->wake_up_pipe[0] = -1;
|
||||
context->wake_up_pipe[1] = -1;
|
||||
|
||||
context->ref_count = 1;
|
||||
|
||||
context->next_id = 1;
|
||||
@ -730,6 +777,10 @@ g_main_context_new ()
|
||||
context);
|
||||
#endif
|
||||
|
||||
G_LOCK (main_context_list);
|
||||
main_context_list = g_slist_append (main_context_list, context);
|
||||
G_UNLOCK (main_context_list);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
@ -920,17 +971,14 @@ g_source_destroy_internal (GSource *source,
|
||||
old_cb_funcs->unref (old_cb_data);
|
||||
LOCK_CONTEXT (context);
|
||||
}
|
||||
|
||||
if (!SOURCE_BLOCKED (source))
|
||||
|
||||
tmp_list = source->poll_fds;
|
||||
while (tmp_list)
|
||||
{
|
||||
tmp_list = source->poll_fds;
|
||||
while (tmp_list)
|
||||
{
|
||||
g_main_context_remove_poll_unlocked (context, tmp_list->data);
|
||||
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);
|
||||
}
|
||||
|
||||
@ -1036,8 +1084,7 @@ g_source_add_poll (GSource *source,
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -1069,8 +1116,7 @@ g_source_remove_poll (GSource *source,
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -1224,22 +1270,16 @@ g_source_set_priority (GSource *source,
|
||||
|
||||
if (context)
|
||||
{
|
||||
/* Remove the source from the context's source and then
|
||||
* add it back so it is sorted in the correct plcae
|
||||
*/
|
||||
g_source_list_remove (source, source->context);
|
||||
g_source_list_add (source, source->context);
|
||||
|
||||
if (!SOURCE_BLOCKED (source))
|
||||
source->next = NULL;
|
||||
source->prev = NULL;
|
||||
|
||||
tmp_list = source->poll_fds;
|
||||
while (tmp_list)
|
||||
{
|
||||
tmp_list = source->poll_fds;
|
||||
while (tmp_list)
|
||||
{
|
||||
g_main_context_remove_poll_unlocked (context, tmp_list->data);
|
||||
g_main_context_add_poll_unlocked (context, priority, tmp_list->data);
|
||||
|
||||
tmp_list = tmp_list->next;
|
||||
}
|
||||
g_main_context_remove_poll_unlocked (context, tmp_list->data);
|
||||
g_main_context_add_poll_unlocked (context, priority, tmp_list->data);
|
||||
|
||||
tmp_list = tmp_list->next;
|
||||
}
|
||||
|
||||
UNLOCK_CONTEXT (source->context);
|
||||
@ -1543,11 +1583,11 @@ g_main_context_find_source_by_user_data (GMainContext *context,
|
||||
* g_source_remove:
|
||||
* @tag: the id of the source to remove.
|
||||
*
|
||||
* Removes the source with the given id from the default main
|
||||
* context. The id of a #GSource is given by g_source_get_id(),
|
||||
* or will be returned by the functions g_source_attach(),
|
||||
* g_idle_add(), g_idle_add_full(), g_timeout_add(),
|
||||
* g_timeout_add_full(), g_io_add_watch, and g_io_add_watch_full().
|
||||
* Removes the source with the given id from the default main context. The id of
|
||||
* a #GSource is given by g_source_get_id(), or will be returned by the
|
||||
* functions g_source_attach(), g_idle_add(), g_idle_add_full(),
|
||||
* g_timeout_add(), g_timeout_add_full(), g_child_watch_add(),
|
||||
* g_child_watch_add_full(), g_io_add_watch(), and g_io_add_watch_full().
|
||||
*
|
||||
* See also g_source_destroy().
|
||||
*
|
||||
@ -1666,43 +1706,6 @@ g_get_current_time (GTimeVal *result)
|
||||
|
||||
/* 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 */
|
||||
static void
|
||||
g_main_dispatch (GMainContext *context)
|
||||
@ -1738,9 +1741,6 @@ g_main_dispatch (GMainContext *context)
|
||||
if (cb_funcs)
|
||||
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;
|
||||
source->flags |= G_HOOK_FLAG_IN_CALL;
|
||||
|
||||
@ -1760,10 +1760,6 @@ g_main_dispatch (GMainContext *context)
|
||||
if (!was_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
|
||||
* sources from one main context to another
|
||||
*/
|
||||
@ -2052,7 +2048,7 @@ g_main_context_prepare (GMainContext *context,
|
||||
SOURCE_UNREF (source, context);
|
||||
break;
|
||||
}
|
||||
if (SOURCE_BLOCKED (source))
|
||||
if ((source->flags & G_HOOK_FLAG_IN_CALL) && !(source->flags & G_SOURCE_CAN_RECURSE))
|
||||
goto next;
|
||||
|
||||
if (!(source->flags & G_SOURCE_READY))
|
||||
@ -2203,8 +2199,8 @@ g_main_context_check (GMainContext *context,
|
||||
if (!context->poll_waiting)
|
||||
{
|
||||
#ifndef G_OS_WIN32
|
||||
gchar c;
|
||||
read (context->wake_up_pipe[0], &c, 1);
|
||||
gchar a;
|
||||
read (context->wake_up_pipe[0], &a, 1);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@ -2240,7 +2236,7 @@ g_main_context_check (GMainContext *context,
|
||||
SOURCE_UNREF (source, context);
|
||||
break;
|
||||
}
|
||||
if (SOURCE_BLOCKED (source))
|
||||
if ((source->flags & G_HOOK_FLAG_IN_CALL) && !(source->flags & G_SOURCE_CAN_RECURSE))
|
||||
goto next;
|
||||
|
||||
if (!(source->flags & G_SOURCE_READY))
|
||||
@ -3241,6 +3237,274 @@ g_timeout_add (guint32 interval,
|
||||
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 */
|
||||
|
||||
static gboolean
|
||||
|
50
glib/gmain.h
50
glib/gmain.h
@ -32,7 +32,9 @@ typedef struct _GSourceCallbackFuncs GSourceCallbackFuncs;
|
||||
typedef struct _GSourceFuncs GSourceFuncs;
|
||||
|
||||
typedef gboolean (*GSourceFunc) (gpointer data);
|
||||
|
||||
typedef void (*GChildWatchFunc) (GPid pid,
|
||||
gint status,
|
||||
gpointer data);
|
||||
struct _GSource
|
||||
{
|
||||
/*< private >*/
|
||||
@ -243,8 +245,9 @@ void g_source_get_current_time (GSource *source,
|
||||
|
||||
/* Specific source types
|
||||
*/
|
||||
GSource *g_idle_source_new (void);
|
||||
GSource *g_timeout_source_new (guint interval);
|
||||
GSource *g_idle_source_new (void);
|
||||
GSource *g_child_watch_source_new (GPid pid);
|
||||
GSource *g_timeout_source_new (guint interval);
|
||||
|
||||
/* 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,
|
||||
gpointer user_data);
|
||||
|
||||
/* 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);
|
||||
/* Idles, child watchers 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_child_watch_add_full (gint priority,
|
||||
GPid pid,
|
||||
GChildWatchFunc function,
|
||||
gpointer data,
|
||||
GDestroyNotify notify);
|
||||
guint g_child_watch_add (GPid pid,
|
||||
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 */
|
||||
GLIB_VAR GSourceFuncs g_timeout_funcs;
|
||||
GLIB_VAR GSourceFuncs g_child_watch_funcs;
|
||||
GLIB_VAR GSourceFuncs g_idle_funcs;
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -66,6 +66,7 @@ endif
|
||||
test_programs = \
|
||||
array-test \
|
||||
$(CXX_TEST) \
|
||||
child-test \
|
||||
completion-test \
|
||||
date-test \
|
||||
dirname-test \
|
||||
@ -115,6 +116,7 @@ thread_ldadd = $(libgthread) $(G_THREAD_LIBS) $(progs_ldadd)
|
||||
module_ldadd = $(libgmodule) $(G_MODULE_LIBS) $(progs_ldadd)
|
||||
|
||||
array_test_LDADD = $(progs_ldadd)
|
||||
child_test_LDADD = $(thread_ldadd)
|
||||
completion_test_LDADD = $(progs_ldadd)
|
||||
date_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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user