gmain: unify win/unix implementations for child watcher

Let's move the difference between the win/unix implementations closer to
where the difference is. Thereby, we easier see the two implementations
side by side. Splitting it at a higher layer makes the code harder to
read.

This is just a preparation for what comes next.
This commit is contained in:
Thomas Haller 2023-03-28 14:38:08 +02:00
parent d1e558f492
commit 9315a211fa

View File

@ -488,6 +488,11 @@ static gboolean g_child_watch_dispatch (GSource *source,
GSourceFunc callback,
gpointer user_data);
static void g_child_watch_finalize (GSource *source);
#ifndef G_OS_WIN32
static void unref_unix_signal_handler_unlocked (int signum);
#endif
#ifdef G_OS_UNIX
static void g_unix_signal_handler (int signum);
static gboolean g_unix_signal_watch_prepare (GSource *source,
@ -5479,17 +5484,49 @@ g_timeout_add_seconds_once (guint interval,
/* Child watch functions */
#ifdef G_OS_WIN32
#ifdef HAVE_PIDFD
static int
siginfo_t_to_wait_status (const siginfo_t *info)
{
/* Each of these returns is essentially the inverse of WIFEXITED(),
* WIFSIGNALED(), etc. */
switch (info->si_code)
{
case CLD_EXITED:
return W_EXITCODE (info->si_status, 0);
case CLD_KILLED:
return W_EXITCODE (0, info->si_status);
case CLD_DUMPED:
return W_EXITCODE (0, info->si_status | WCOREFLAG);
case CLD_CONTINUED:
return __W_CONTINUED;
case CLD_STOPPED:
case CLD_TRAPPED:
default:
return W_STOPCODE (info->si_status);
}
}
#endif /* HAVE_PIDFD */
static gboolean
g_child_watch_prepare (GSource *source,
gint *timeout)
{
#ifdef G_OS_WIN32
*timeout = -1;
return FALSE;
#else /* G_OS_WIN32 */
{
GChildWatchSource *child_watch_source;
child_watch_source = (GChildWatchSource *) source;
return g_atomic_int_get (&child_watch_source->child_exited);
}
#endif /* G_OS_WIN32 */
}
static gboolean
static gboolean
g_child_watch_check (GSource *source)
{
GChildWatchSource *child_watch_source;
@ -5497,6 +5534,7 @@ g_child_watch_check (GSource *source)
child_watch_source = (GChildWatchSource *) source;
#ifdef G_OS_WIN32
child_exited = child_watch_source->poll.revents & G_IO_IN;
if (child_exited)
@ -5511,15 +5549,45 @@ g_child_watch_check (GSource *source)
*/
if (!GetExitCodeProcess (child_watch_source->pid, &child_status))
{
gchar *emsg = g_win32_error_message (GetLastError ());
g_warning (G_STRLOC ": GetExitCodeProcess() failed: %s", emsg);
g_free (emsg);
gchar *emsg = g_win32_error_message (GetLastError ());
g_warning (G_STRLOC ": GetExitCodeProcess() failed: %s", emsg);
g_free (emsg);
child_watch_source->child_status = -1;
}
child_watch_source->child_status = -1;
}
else
child_watch_source->child_status = child_status;
child_watch_source->child_status = child_status;
}
#else /* G_OS_WIN32 */
#ifdef HAVE_PIDFD
if (child_watch_source->using_pidfd)
{
child_exited = child_watch_source->poll.revents & G_IO_IN;
if (child_exited)
{
siginfo_t child_info = { 0, };
/* Get the exit status */
if (waitid (P_PIDFD, child_watch_source->poll.fd, &child_info, WEXITED | WNOHANG) >= 0 &&
child_info.si_pid != 0)
{
/* waitid() helpfully provides the wait status in a decomposed
* form which is quite useful. Unfortunately we have to report it
* to the #GChildWatchFunc as a waitpid()-style platform-specific
* wait status, so that the user code in #GChildWatchFunc can then
* call WIFEXITED() (etc.) on it. That means re-composing the
* status information. */
child_watch_source->child_status = siginfo_t_to_wait_status (&child_info);
child_watch_source->child_exited = TRUE;
}
}
return child_exited;
}
#endif /* HAVE_PIDFD */
child_exited = g_atomic_int_get (&child_watch_source->child_exited);
#endif /* G_OS_WIN32 */
return child_exited;
}
@ -5527,9 +5595,24 @@ g_child_watch_check (GSource *source)
static void
g_child_watch_finalize (GSource *source)
{
#ifndef G_OS_WIN32
GChildWatchSource *child_watch_source = (GChildWatchSource *) source;
if (child_watch_source->using_pidfd)
{
if (child_watch_source->poll.fd >= 0)
close (child_watch_source->poll.fd);
return;
}
G_LOCK (unix_signal_lock);
unix_child_watches = g_slist_remove (unix_child_watches, source);
unref_unix_signal_handler_unlocked (SIGCHLD);
G_UNLOCK (unix_signal_lock);
#endif /* G_OS_WIN32 */
}
#else /* G_OS_WIN32 */
#ifndef G_OS_WIN32
static void
wake_source (GSource *source)
@ -5662,79 +5745,6 @@ dispatch_unix_signals (void)
G_UNLOCK(unix_signal_lock);
}
static gboolean
g_child_watch_prepare (GSource *source,
gint *timeout)
{
GChildWatchSource *child_watch_source;
child_watch_source = (GChildWatchSource *) source;
return g_atomic_int_get (&child_watch_source->child_exited);
}
#ifdef HAVE_PIDFD
static int
siginfo_t_to_wait_status (const siginfo_t *info)
{
/* Each of these returns is essentially the inverse of WIFEXITED(),
* WIFSIGNALED(), etc. */
switch (info->si_code)
{
case CLD_EXITED:
return W_EXITCODE (info->si_status, 0);
case CLD_KILLED:
return W_EXITCODE (0, info->si_status);
case CLD_DUMPED:
return W_EXITCODE (0, info->si_status | WCOREFLAG);
case CLD_CONTINUED:
return __W_CONTINUED;
case CLD_STOPPED:
case CLD_TRAPPED:
default:
return W_STOPCODE (info->si_status);
}
}
#endif /* HAVE_PIDFD */
static gboolean
g_child_watch_check (GSource *source)
{
GChildWatchSource *child_watch_source;
child_watch_source = (GChildWatchSource *) source;
#ifdef HAVE_PIDFD
if (child_watch_source->using_pidfd)
{
gboolean child_exited = child_watch_source->poll.revents & G_IO_IN;
if (child_exited)
{
siginfo_t child_info = { 0, };
/* Get the exit status */
if (waitid (P_PIDFD, child_watch_source->poll.fd, &child_info, WEXITED | WNOHANG) >= 0 &&
child_info.si_pid != 0)
{
/* waitid() helpfully provides the wait status in a decomposed
* form which is quite useful. Unfortunately we have to report it
* to the #GChildWatchFunc as a waitpid()-style platform-specific
* wait status, so that the user code in #GChildWatchFunc can then
* call WIFEXITED() (etc.) on it. That means re-composing the
* status information. */
child_watch_source->child_status = siginfo_t_to_wait_status (&child_info);
child_watch_source->child_exited = TRUE;
}
}
return child_exited;
}
#endif /* HAVE_PIDFD */
return g_atomic_int_get (&child_watch_source->child_exited);
}
static gboolean
g_unix_signal_watch_prepare (GSource *source,
gint *timeout)
@ -5913,24 +5923,6 @@ g_unix_signal_watch_finalize (GSource *source)
G_UNLOCK (unix_signal_lock);
}
static void
g_child_watch_finalize (GSource *source)
{
GChildWatchSource *child_watch_source = (GChildWatchSource *) source;
if (child_watch_source->using_pidfd)
{
if (child_watch_source->poll.fd >= 0)
close (child_watch_source->poll.fd);
return;
}
G_LOCK (unix_signal_lock);
unix_child_watches = g_slist_remove (unix_child_watches, source);
unref_unix_signal_handler_unlocked (SIGCHLD);
G_UNLOCK (unix_signal_lock);
}
#endif /* G_OS_WIN32 */
static gboolean