[kdbus] KDBUS_ITEM_PAYLOAD_OFF items are (once again) relative to msg header
[platform/upstream/glib.git] / gio / gsubprocess.c
index 2e517f9..999d777 100644 (file)
@@ -1,7 +1,7 @@
 /* GIO - GLib Input, Output and Streaming Library
  *
- * Copyright © 2012 Red Hat, Inc.
- * Copyright © 2012-2013 Canonical Limited
+ * Copyright © 2012, 2013 Red Hat, Inc.
+ * Copyright © 20122013 Canonical Limited
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as published
@@ -18,6 +18,7 @@
  * SECTION:gsubprocess
  * @title: GSubprocess
  * @short_description: Child processes
+ * @include: gio/gio.h
  * @see_also: #GSubprocessLauncher
  *
  * #GSubprocess allows the creation of and interaction with child
  * comprehensive API for asynchronous I/O, such
  * g_output_stream_splice_async().  This makes GSubprocess
  * significantly more powerful and flexible than equivalent APIs in
- * some other languages such as the <literal>subprocess.py</literal>
+ * some other languages such as the `subprocess.py`
  * included with Python.  For example, using #GSubprocess one could
  * create two child processes, reading standard output from the first,
  * processing it, and writing to the input stream of the second, all
  * without blocking the main loop.
  *
  * A powerful g_subprocess_communicate() API is provided similar to the
- * <literal>communicate()</literal> method of
- * <literal>subprocess.py</literal>.  This enables very easy interaction
- * with a subprocess that has been opened with pipes.
+ * `communicate()` method of `subprocess.py`. This enables very easy
+ * interaction with a subprocess that has been opened with pipes.
  *
  * #GSubprocess defaults to tight control over the file descriptors open
  * in the child process, avoiding dangling-fd issues that are caused by
  * change of working directory, child setup functions, etc).
  *
  * A typical use of #GSubprocess will involve calling
- * g_subprocess_new(), followed by g_subprocess_wait() or
- * g_subprocess_wait_sync().  After the process exits, the status can be
+ * g_subprocess_new(), followed by g_subprocess_wait_async() or
+ * g_subprocess_wait().  After the process exits, the status can be
  * checked using functions such as g_subprocess_get_if_exited() (which
  * are similar to the familiar WIFEXITED-style POSIX macros).
  *
- * Since: 2.36
+ * Since: 2.40
  **/
 
 #include "config.h"
@@ -99,8 +99,8 @@
 #include <fcntl.h>
 #endif
 #ifdef G_OS_WIN32
-#define _WIN32_WINNT 0x0500
 #include <windows.h>
+#include <io.h>
 #include "giowin32-priv.h"
 #endif
 
 #define O_BINARY 0
 #endif
 
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#else
+#define HAVE_O_CLOEXEC 1
+#endif
+
 #define COMMUNICATE_READ_SIZE 4096
 
 /* A GSubprocess can have two possible states: running and not.
@@ -173,6 +179,7 @@ enum
   N_PROPS
 };
 
+#ifdef G_OS_UNIX
 typedef struct
 {
   gint                 fds[3];
@@ -199,6 +206,34 @@ unset_cloexec (int fd)
     }
 }
 
+static int
+dupfd_cloexec (int parent_fd)
+{
+  int fd;
+#ifdef F_DUPFD_CLOEXEC
+  do
+    fd = fcntl (parent_fd, F_DUPFD_CLOEXEC, 3);
+  while (fd == -1 && errno == EINTR);
+#else
+  /* OS X Snow Lion and earlier don't have F_DUPFD_CLOEXEC:
+   * https://bugzilla.gnome.org/show_bug.cgi?id=710962
+   */
+  int result, flags;
+  do
+    fd = fcntl (parent_fd, F_DUPFD, 3);
+  while (fd == -1 && errno == EINTR);
+  flags = fcntl (fd, F_GETFD, 0);
+  if (flags != -1)
+    {
+      flags |= FD_CLOEXEC;
+      do
+        result = fcntl (fd, F_SETFD, flags);
+      while (result == -1 && errno == EINTR);
+    }
+#endif
+  return fd;
+}
+
 /**
  * Based on code derived from
  * gnome-terminal:src/terminal-screen.c:terminal_screen_child_setup(),
@@ -250,9 +285,7 @@ child_setup (gpointer user_data)
           gint parent_fd = g_array_index (child_data->needdup_fd_assignments, int, i);
           gint new_parent_fd;
 
-          do
-            new_parent_fd = fcntl (parent_fd, F_DUPFD_CLOEXEC, 3);
-          while (parent_fd == -1 && errno == EINTR);
+          new_parent_fd = dupfd_cloexec (parent_fd);
 
           g_array_index (child_data->needdup_fd_assignments, int, i) = new_parent_fd;
         }
@@ -278,6 +311,7 @@ child_setup (gpointer user_data)
   if (child_data->child_setup_func)
     child_data->child_setup_func (child_data->child_setup_data);
 }
+#endif
 
 static GInputStream *
 platform_input_stream_from_spawn_fd (gint fd)
@@ -328,6 +362,10 @@ unix_open_file (const char  *filename,
       g_free (display_name);
       /* fall through... */
     }
+#ifndef HAVE_O_CLOEXEC
+  else
+    fcntl (my_fd, F_SETFD, FD_CLOEXEC);
+#endif
 
   return my_fd;
 }
@@ -377,6 +415,7 @@ g_subprocess_exited (GPid     pid,
   while (tasks)
     {
       g_task_return_boolean (tasks->data, TRUE);
+      g_object_unref (tasks->data);
       tasks = g_slist_delete_link (tasks, tasks);
     }
 
@@ -391,7 +430,9 @@ initable_init (GInitable     *initable,
                GError       **error)
 {
   GSubprocess *self = G_SUBPROCESS (initable);
+#ifdef G_OS_UNIX
   ChildData child_data = { { -1, -1, -1 }, 0 };
+#endif
   gint *pipe_ptrs[3] = { NULL, NULL, NULL };
   gint pipe_fds[3] = { -1, -1, -1 };
   gint close_fds[3] = { -1, -1, -1 };
@@ -453,10 +494,10 @@ initable_init (GInitable     *initable,
     spawn_flags |= G_SPAWN_STDERR_TO_DEV_NULL;
   else if (self->flags & G_SUBPROCESS_FLAGS_STDERR_PIPE)
     pipe_ptrs[2] = &pipe_fds[2];
+#ifdef G_OS_UNIX
   else if (self->flags & G_SUBPROCESS_FLAGS_STDERR_MERGE)
     /* This will work because stderr gets setup after stdout. */
     child_data.fds[2] = 1;
-#ifdef G_OS_UNIX
   else if (self->launcher)
     {
       if (self->launcher->stderr_fd != -1)
@@ -493,13 +534,20 @@ initable_init (GInitable     *initable,
   spawn_flags |= G_SPAWN_DO_NOT_REAP_CHILD;
   spawn_flags |= G_SPAWN_CLOEXEC_PIPES;
 
+#ifdef G_OS_UNIX
   child_data.child_setup_func = self->launcher ? self->launcher->child_setup_func : NULL;
   child_data.child_setup_data = self->launcher ? self->launcher->child_setup_user_data : NULL;
+#endif
+
   success = g_spawn_async_with_pipes (self->launcher ? self->launcher->cwd : NULL,
                                       self->argv,
                                       self->launcher ? self->launcher->envp : NULL,
                                       spawn_flags,
+#ifdef G_OS_UNIX
                                       child_setup, &child_data,
+#else
+                                      NULL, NULL,
+#endif
                                       &self->pid,
                                       pipe_ptrs[0], pipe_ptrs[1], pipe_ptrs[2],
                                       error);
@@ -515,7 +563,7 @@ initable_init (GInitable     *initable,
     identifier = (guint64) self->pid;
 #endif
 
-    s = snprintf (self->identifier, sizeof self->identifier, "%"G_GUINT64_FORMAT, identifier);
+    s = g_snprintf (self->identifier, sizeof self->identifier, "%"G_GUINT64_FORMAT, identifier);
     g_assert (0 < s && s < sizeof self->identifier);
   }
 
@@ -532,7 +580,9 @@ initable_init (GInitable     *initable,
       g_source_unref (source);
     }
 
+#ifdef G_OS_UNIX
 out:
+#endif
   /* we don't need this past init... */
   self->launcher = NULL;
 
@@ -558,7 +608,9 @@ g_subprocess_finalize (GObject *object)
   g_clear_object (&self->stdin_pipe);
   g_clear_object (&self->stdout_pipe);
   g_clear_object (&self->stderr_pipe);
-  g_free (self->argv);
+  g_strfreev (self->argv);
+
+  g_mutex_clear (&self->pending_waits_lock);
 
   G_OBJECT_CLASS (g_subprocess_parent_class)->finalize (object);
 }
@@ -566,6 +618,7 @@ g_subprocess_finalize (GObject *object)
 static void
 g_subprocess_init (GSubprocess  *self)
 {
+  g_mutex_init (&self->pending_waits_lock);
 }
 
 static void
@@ -594,15 +647,23 @@ g_subprocess_class_init (GSubprocessClass *class)
 
 /**
  * g_subprocess_new: (skip)
+ * @flags: flags that define the behaviour of the subprocess
+ * @error: (allow-none): return location for an error, or %NULL
+ * @argv0: first commandline argument to pass to the subprocess
+ * @...:   more commandline arguments, followed by %NULL
  *
- * Create a new process with the given flags and varargs argument list.
+ * Create a new process with the given flags and varargs argument
+ * list.  By default, matching the g_spawn_async() defaults, the
+ * child's stdin will be set to the system null device, and
+ * stdout/stderr will be inherited from the parent.  You can use
+ * @flags to control this behavior.
  *
  * The argument list must be terminated with %NULL.
  *
  * Returns: A newly created #GSubprocess, or %NULL on error (and @error
  *   will be set)
  *
- * Since: 2.36
+ * Since: 2.40
  */
 GSubprocess *
 g_subprocess_new (GSubprocessFlags   flags,
@@ -625,6 +686,7 @@ g_subprocess_new (GSubprocessFlags   flags,
   while ((arg = va_arg (ap, const gchar *)))
     g_ptr_array_add (args, (gchar *) arg);
   g_ptr_array_add (args, NULL);
+  va_end (ap);
 
   result = g_subprocess_newv ((const gchar * const *) args->pdata, flags, error);
 
@@ -635,6 +697,9 @@ g_subprocess_new (GSubprocessFlags   flags,
 
 /**
  * g_subprocess_newv:
+ * @argv: (array zero-terminated=1) (element-type utf8): commandline arguments for the subprocess
+ * @flags: flags that define the behaviour of the subprocess
+ * @error: (allow-none): return location for an error, or %NULL
  *
  * Create a new process with the given flags and argument list.
  *
@@ -643,7 +708,7 @@ g_subprocess_new (GSubprocessFlags   flags,
  * Returns: A newly created #GSubprocess, or %NULL on error (and @error
  *   will be set)
  *
- * Since: 2.36
+ * Since: 2.40
  * Rename to: g_subprocess_new
  */
 GSubprocess *
@@ -659,42 +724,91 @@ g_subprocess_newv (const gchar * const  *argv,
                          NULL);
 }
 
+/**
+ * g_subprocess_get_identifier:
+ * @subprocess: a #GSubprocess
+ *
+ * On UNIX, returns the process ID as a decimal string.
+ * On Windows, returns the result of GetProcessId() also as a string.
+ */
 const gchar *
-g_subprocess_get_identifier (GSubprocess *self)
+g_subprocess_get_identifier (GSubprocess *subprocess)
 {
-  g_return_val_if_fail (G_IS_SUBPROCESS (self), NULL);
+  g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), NULL);
 
-  if (self->pid)
-    return self->identifier;
+  if (subprocess->pid)
+    return subprocess->identifier;
   else
     return NULL;
 }
 
+/**
+ * g_subprocess_get_stdin_pipe:
+ * @subprocess: a #GSubprocess
+ *
+ * Gets the #GOutputStream that you can write to in order to give data
+ * to the stdin of @subprocess.
+ *
+ * The process must have been created with
+ * %G_SUBPROCESS_FLAGS_STDIN_PIPE.
+ *
+ * Returns: (transfer none): the stdout pipe
+ *
+ * Since: 2.40
+ **/
 GOutputStream *
-g_subprocess_get_stdin_pipe (GSubprocess       *self)
+g_subprocess_get_stdin_pipe (GSubprocess *subprocess)
 {
-  g_return_val_if_fail (G_IS_SUBPROCESS (self), NULL);
-  g_return_val_if_fail (self->stdin_pipe, NULL);
+  g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), NULL);
+  g_return_val_if_fail (subprocess->stdin_pipe, NULL);
 
-  return self->stdin_pipe;
+  return subprocess->stdin_pipe;
 }
 
+/**
+ * g_subprocess_get_stdout_pipe:
+ * @subprocess: a #GSubprocess
+ *
+ * Gets the #GInputStream from which to read the stdout output of
+ * @subprocess.
+ *
+ * The process must have been created with
+ * %G_SUBPROCESS_FLAGS_STDOUT_PIPE.
+ *
+ * Returns: (transfer none): the stdout pipe
+ *
+ * Since: 2.40
+ **/
 GInputStream *
-g_subprocess_get_stdout_pipe (GSubprocess      *self)
+g_subprocess_get_stdout_pipe (GSubprocess *subprocess)
 {
-  g_return_val_if_fail (G_IS_SUBPROCESS (self), NULL);
-  g_return_val_if_fail (self->stdout_pipe, NULL);
+  g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), NULL);
+  g_return_val_if_fail (subprocess->stdout_pipe, NULL);
 
-  return self->stdout_pipe;
+  return subprocess->stdout_pipe;
 }
 
+/**
+ * g_subprocess_get_stderr_pipe:
+ * @subprocess: a #GSubprocess
+ *
+ * Gets the #GInputStream from which to read the stderr output of
+ * @subprocess.
+ *
+ * The process must have been created with
+ * %G_SUBPROCESS_FLAGS_STDERR_PIPE.
+ *
+ * Returns: (transfer none): the stderr pipe
+ *
+ * Since: 2.40
+ **/
 GInputStream *
-g_subprocess_get_stderr_pipe (GSubprocess      *self)
+g_subprocess_get_stderr_pipe (GSubprocess *subprocess)
 {
-  g_return_val_if_fail (G_IS_SUBPROCESS (self), NULL);
-  g_return_val_if_fail (self->stderr_pipe, NULL);
+  g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), NULL);
+  g_return_val_if_fail (subprocess->stderr_pipe, NULL);
 
-  return self->stderr_pipe;
+  return subprocess->stderr_pipe;
 }
 
 static void
@@ -714,18 +828,31 @@ g_subprocess_wait_cancelled (GCancellable *cancellable,
   g_object_unref (task);
 }
 
+/**
+ * g_subprocess_wait_async:
+ * @subprocess: a #GSubprocess
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the operation is complete
+ * @user_data: user_data for @callback
+ *
+ * Wait for the subprocess to terminate.
+ *
+ * This is the asynchronous version of g_subprocess_wait().
+ *
+ * Since: 2.40
+ */
 void
-g_subprocess_wait_async (GSubprocess         *self,
+g_subprocess_wait_async (GSubprocess         *subprocess,
                          GCancellable        *cancellable,
                          GAsyncReadyCallback  callback,
                          gpointer             user_data)
 {
   GTask *task;
 
-  task = g_task_new (self, cancellable, callback, user_data);
+  task = g_task_new (subprocess, cancellable, callback, user_data);
 
-  g_mutex_lock (&self->pending_waits_lock);
-  if (self->pid)
+  g_mutex_lock (&subprocess->pending_waits_lock);
+  if (subprocess->pid)
     {
       /* Only bother with cancellable if we're putting it in the list.
        * If not, it's going to dispatch immediately anyway and we will
@@ -734,10 +861,10 @@ g_subprocess_wait_async (GSubprocess         *self,
       if (cancellable)
         g_signal_connect_object (cancellable, "cancelled", G_CALLBACK (g_subprocess_wait_cancelled), task, 0);
 
-      self->pending_waits = g_slist_prepend (self->pending_waits, task);
+      subprocess->pending_waits = g_slist_prepend (subprocess->pending_waits, task);
       task = NULL;
     }
-  g_mutex_unlock (&self->pending_waits_lock);
+  g_mutex_unlock (&subprocess->pending_waits_lock);
 
   /* If we still have task then it's because did_exit is already TRUE */
   if (task != NULL)
@@ -747,8 +874,21 @@ g_subprocess_wait_async (GSubprocess         *self,
     }
 }
 
+/**
+ * g_subprocess_wait_finish:
+ * @subprocess: a #GSubprocess
+ * @result: the #GAsyncResult passed to your #GAsyncReadyCallback
+ * @error: a pointer to a %NULL #GError, or %NULL
+ *
+ * Collects the result of a previous call to
+ * g_subprocess_wait_async().
+ *
+ * Returns: %TRUE if successful, or %FALSE with @error set
+ *
+ * Since: 2.40
+ */
 gboolean
-g_subprocess_wait_finish (GSubprocess   *self,
+g_subprocess_wait_finish (GSubprocess   *subprocess,
                           GAsyncResult  *result,
                           GError       **error)
 {
@@ -788,28 +928,35 @@ g_subprocess_sync_complete (GAsyncResult **result)
 
 /**
  * g_subprocess_wait:
- * @self: a #GSubprocess
+ * @subprocess: a #GSubprocess
  * @cancellable: a #GCancellable
  * @error: a #GError
  *
- * Synchronously wait for the subprocess to terminate, returning the
- * status code in @out_exit_status.  See the documentation of
- * g_spawn_check_exit_status() for how to interpret it.  Note that if
- * @error is set, then @out_exit_status will be left uninitialized.
+ * Synchronously wait for the subprocess to terminate.
+ *
+ * After the process terminates you can query its exit status with
+ * functions such as g_subprocess_get_if_exited() and
+ * g_subprocess_get_exit_status().
+ *
+ * This function does not fail in the case of the subprocess having
+ * abnormal termination.  See g_subprocess_wait_check() for that.
+ *
+ * Cancelling @cancellable doesn't kill the subprocess.  Call
+ * g_subprocess_force_exit() if it is desirable.
  *
  * Returns: %TRUE on success, %FALSE if @cancellable was cancelled
  *
- * Since: 2.36
+ * Since: 2.40
  */
 gboolean
-g_subprocess_wait (GSubprocess   *self,
+g_subprocess_wait (GSubprocess   *subprocess,
                    GCancellable  *cancellable,
                    GError       **error)
 {
   GAsyncResult *result = NULL;
   gboolean success;
 
-  g_return_val_if_fail (G_IS_SUBPROCESS (self), FALSE);
+  g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), FALSE);
 
   /* Synchronous waits are actually the 'more difficult' case because we
    * need to deal with the possibility of cancellation.  That more or
@@ -825,56 +972,83 @@ g_subprocess_wait (GSubprocess   *self,
   /* We can shortcut in the case that the process already quit (but only
    * after we checked the cancellable).
    */
-  if (self->pid == 0)
+  if (subprocess->pid == 0)
     return TRUE;
 
   /* Otherwise, we need to do this the long way... */
   g_subprocess_sync_setup ();
-  g_subprocess_wait_async (self, cancellable, g_subprocess_sync_done, &result);
+  g_subprocess_wait_async (subprocess, cancellable, g_subprocess_sync_done, &result);
   g_subprocess_sync_complete (&result);
-  success = g_subprocess_wait_finish (self, result, error);
+  success = g_subprocess_wait_finish (subprocess, result, error);
   g_object_unref (result);
 
   return success;
 }
 
 /**
- * g_subprocess_wait_sync_check:
- * @self: a #GSubprocess
+ * g_subprocess_wait_check:
+ * @subprocess: a #GSubprocess
  * @cancellable: a #GCancellable
  * @error: a #GError
  *
- * Combines g_subprocess_wait_sync() with g_spawn_check_exit_status().
+ * Combines g_subprocess_wait() with g_spawn_check_exit_status().
  *
- * Returns: %TRUE on success, %FALSE if process exited abnormally, or @cancellable was cancelled
+ * Returns: %TRUE on success, %FALSE if process exited abnormally, or
+ * @cancellable was cancelled
  *
- * Since: 2.36
+ * Since: 2.40
  */
 gboolean
-g_subprocess_wait_check (GSubprocess   *self,
+g_subprocess_wait_check (GSubprocess   *subprocess,
                          GCancellable  *cancellable,
                          GError       **error)
 {
-  return g_subprocess_wait (self, cancellable, error) &&
-         g_spawn_check_exit_status (self->status, error);
+  return g_subprocess_wait (subprocess, cancellable, error) &&
+         g_spawn_check_exit_status (subprocess->status, error);
 }
 
+/**
+ * g_subprocess_wait_check_async:
+ * @subprocess: a #GSubprocess
+ * @cancellable: a #GCancellable, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the operation is complete
+ * @user_data: user_data for @callback
+ *
+ * Combines g_subprocess_wait_async() with g_spawn_check_exit_status().
+ *
+ * This is the asynchronous version of g_subprocess_wait_check().
+ *
+ * Since: 2.40
+ */
 void
-g_subprocess_wait_check_async (GSubprocess         *self,
+g_subprocess_wait_check_async (GSubprocess         *subprocess,
                                GCancellable        *cancellable,
                                GAsyncReadyCallback  callback,
                                gpointer             user_data)
 {
-  g_subprocess_wait_async (self, cancellable, callback, user_data);
+  g_subprocess_wait_async (subprocess, cancellable, callback, user_data);
 }
 
+/**
+ * g_subprocess_wait_check_finish:
+ * @subprocess: a #GSubprocess
+ * @result: the #GAsyncResult passed to your #GAsyncReadyCallback
+ * @error: a pointer to a %NULL #GError, or %NULL
+ *
+ * Collects the result of a previous call to
+ * g_subprocess_wait_check_async().
+ *
+ * Returns: %TRUE if successful, or %FALSE with @error set
+ *
+ * Since: 2.40
+ */
 gboolean
-g_subprocess_wait_check_finish (GSubprocess   *self,
+g_subprocess_wait_check_finish (GSubprocess   *subprocess,
                                 GAsyncResult  *result,
                                 GError       **error)
 {
-  return g_subprocess_wait_finish (self, result, error) &&
-         g_spawn_check_exit_status (self->status, error);
+  return g_subprocess_wait_finish (subprocess, result, error) &&
+         g_spawn_check_exit_status (subprocess->status, error);
 }
 
 #ifdef G_OS_UNIX
@@ -903,12 +1077,12 @@ g_subprocess_actually_send_signal (gpointer user_data)
 }
 
 static void
-g_subprocess_dispatch_signal (GSubprocess *self,
+g_subprocess_dispatch_signal (GSubprocess *subprocess,
                               gint         signalnum)
 {
-  SignalRecord signal_record = { g_object_ref (self), signalnum };
+  SignalRecord signal_record = { g_object_ref (subprocess), signalnum };
 
-  g_return_if_fail (G_IS_SUBPROCESS (self));
+  g_return_if_fail (G_IS_SUBPROCESS (subprocess));
 
   /* This MUST be a lower priority than the priority that the child
    * watch source uses in initable_init().
@@ -930,7 +1104,7 @@ g_subprocess_dispatch_signal (GSubprocess *self,
 
 /**
  * g_subprocess_send_signal:
- * @self: a #GSubprocess
+ * @subprocess: a #GSubprocess
  * @signal_num: the signal number to send
  *
  * Sends the UNIX signal @signal_num to the subprocess, if it is still
@@ -941,21 +1115,21 @@ g_subprocess_dispatch_signal (GSubprocess *self,
  *
  * This API is not available on Windows.
  *
- * Since: 2.36
+ * Since: 2.40
  **/
 void
-g_subprocess_send_signal (GSubprocess *self,
+g_subprocess_send_signal (GSubprocess *subprocess,
                           gint         signal_num)
 {
-  g_return_if_fail (G_IS_SUBPROCESS (self));
+  g_return_if_fail (G_IS_SUBPROCESS (subprocess));
 
-  g_subprocess_dispatch_signal (self, signal_num);
+  g_subprocess_dispatch_signal (subprocess, signal_num);
 }
 #endif
 
 /**
  * g_subprocess_force_exit:
- * @self: a #GSubprocess
+ * @subprocess: a #GSubprocess
  *
  * Use an operating-system specific method to attempt an immediate,
  * forceful termination of the process.  There is no mechanism to
@@ -965,23 +1139,23 @@ g_subprocess_send_signal (GSubprocess *self,
  *
  * On Unix, this function sends %SIGKILL.
  *
- * Since: 2.36
+ * Since: 2.40
  **/
 void
-g_subprocess_force_exit (GSubprocess *self)
+g_subprocess_force_exit (GSubprocess *subprocess)
 {
-  g_return_if_fail (G_IS_SUBPROCESS (self));
+  g_return_if_fail (G_IS_SUBPROCESS (subprocess));
 
 #ifdef G_OS_UNIX
-  g_subprocess_dispatch_signal (self, SIGKILL);
+  g_subprocess_dispatch_signal (subprocess, SIGKILL);
 #else
-  TerminateProcess (self->pid, 1);
+  TerminateProcess (subprocess->pid, 1);
 #endif
 }
 
 /**
  * g_subprocess_get_status:
- * @self: a #GSubprocess
+ * @subprocess: a #GSubprocess
  *
  * Gets the raw status code of the process, as from waitpid().
  *
@@ -997,20 +1171,20 @@ g_subprocess_force_exit (GSubprocess *self)
  *
  * Returns: the (meaningless) waitpid() exit status from the kernel
  *
- * Since: 2.36
+ * Since: 2.40
  **/
 gint
-g_subprocess_get_status (GSubprocess *self)
+g_subprocess_get_status (GSubprocess *subprocess)
 {
-  g_return_val_if_fail (G_IS_SUBPROCESS (self), FALSE);
-  g_return_val_if_fail (self->pid == 0, FALSE);
+  g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), FALSE);
+  g_return_val_if_fail (subprocess->pid == 0, FALSE);
 
-  return self->status;
+  return subprocess->status;
 }
 
 /**
  * g_subprocess_get_successful:
- * @self: a #GSubprocess
+ * @subprocess: a #GSubprocess
  *
  * Checks if the process was "successful".  A process is considered
  * successful if it exited cleanly with an exit status of 0, either by
@@ -1021,20 +1195,24 @@ g_subprocess_get_status (GSubprocess *self)
  *
  * Returns: %TRUE if the process exited cleanly with a exit status of 0
  *
- * Since: 2.36
+ * Since: 2.40
  **/
 gboolean
-g_subprocess_get_successful (GSubprocess *self)
+g_subprocess_get_successful (GSubprocess *subprocess)
 {
-  g_return_val_if_fail (G_IS_SUBPROCESS (self), FALSE);
-  g_return_val_if_fail (self->pid == 0, FALSE);
+  g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), FALSE);
+  g_return_val_if_fail (subprocess->pid == 0, FALSE);
 
-  return WIFEXITED (self->status) && WEXITSTATUS (self->status) == 0;
+#ifdef G_OS_UNIX
+  return WIFEXITED (subprocess->status) && WEXITSTATUS (subprocess->status) == 0;
+#else
+  return subprocess->status == 0;
+#endif
 }
 
 /**
  * g_subprocess_get_if_exited:
- * @self: a #GSubprocess
+ * @subprocess: a #GSubprocess
  *
  * Check if the given subprocess exited normally (ie: by way of exit()
  * or return from main()).
@@ -1046,20 +1224,24 @@ g_subprocess_get_successful (GSubprocess *self)
  *
  * Returns: %TRUE if the case of a normal exit
  *
- * Since: 2.36
+ * Since: 2.40
  **/
 gboolean
-g_subprocess_get_if_exited (GSubprocess *self)
+g_subprocess_get_if_exited (GSubprocess *subprocess)
 {
-  g_return_val_if_fail (G_IS_SUBPROCESS (self), FALSE);
-  g_return_val_if_fail (self->pid == 0, FALSE);
+  g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), FALSE);
+  g_return_val_if_fail (subprocess->pid == 0, FALSE);
 
-  return WIFEXITED (self->status);
+#ifdef G_OS_UNIX
+  return WIFEXITED (subprocess->status);
+#else
+  return TRUE;
+#endif
 }
 
 /**
  * g_subprocess_get_exit_status:
- * @self: a #GSubprocess
+ * @subprocess: a #GSubprocess
  *
  * Check the exit status of the subprocess, given that it exited
  * normally.  This is the value passed to the exit() system call or the
@@ -1072,21 +1254,26 @@ g_subprocess_get_if_exited (GSubprocess *self)
  *
  * Returns: the exit status
  *
- * Since: 2.36
+ * Since: 2.40
  **/
 gint
-g_subprocess_get_exit_status (GSubprocess *self)
+g_subprocess_get_exit_status (GSubprocess *subprocess)
 {
-  g_return_val_if_fail (G_IS_SUBPROCESS (self), 1);
-  g_return_val_if_fail (self->pid == 0, 1);
-  g_return_val_if_fail (WIFEXITED (self->status), 1);
+  g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), 1);
+  g_return_val_if_fail (subprocess->pid == 0, 1);
+
+#ifdef G_OS_UNIX
+  g_return_val_if_fail (WIFEXITED (subprocess->status), 1);
 
-  return WEXITSTATUS (self->status);
+  return WEXITSTATUS (subprocess->status);
+#else
+  return subprocess->status;
+#endif
 }
 
 /**
  * g_subprocess_get_if_signaled:
- * @self: a #GSubprocess
+ * @subprocess: a #GSubprocess
  *
  * Check if the given subprocess terminated in response to a signal.
  *
@@ -1097,20 +1284,24 @@ g_subprocess_get_exit_status (GSubprocess *self)
  *
  * Returns: %TRUE if the case of termination due to a signal
  *
- * Since: 2.36
+ * Since: 2.40
  **/
 gboolean
-g_subprocess_get_if_signaled (GSubprocess *self)
+g_subprocess_get_if_signaled (GSubprocess *subprocess)
 {
-  g_return_val_if_fail (G_IS_SUBPROCESS (self), FALSE);
-  g_return_val_if_fail (self->pid == 0, FALSE);
+  g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), FALSE);
+  g_return_val_if_fail (subprocess->pid == 0, FALSE);
 
-  return WIFSIGNALED (self->status);
+#ifdef G_OS_UNIX
+  return WIFSIGNALED (subprocess->status);
+#else
+  return FALSE;
+#endif
 }
 
 /**
  * g_subprocess_get_term_sig:
- * @self: a #GSubprocess
+ * @subprocess: a #GSubprocess
  *
  * Get the signal number that caused the subprocess to terminate, given
  * that it terminated due to a signal.
@@ -1122,16 +1313,23 @@ g_subprocess_get_if_signaled (GSubprocess *self)
  *
  * Returns: the signal causing termination
  *
- * Since: 2.36
+ * Since: 2.40
  **/
 gint
-g_subprocess_get_term_sig (GSubprocess *self)
+g_subprocess_get_term_sig (GSubprocess *subprocess)
 {
-  g_return_val_if_fail (G_IS_SUBPROCESS (self), 0);
-  g_return_val_if_fail (self->pid == 0, 0);
-  g_return_val_if_fail (WIFSIGNALED (self->status), 0);
+  g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), 0);
+  g_return_val_if_fail (subprocess->pid == 0, 0);
+
+#ifdef G_OS_UNIX
+  g_return_val_if_fail (WIFSIGNALED (subprocess->status), 0);
 
-  return WTERMSIG (self->status);
+  return WTERMSIG (subprocess->status);
+#else
+  g_critical ("g_subprocess_get_term_sig() called on Windows, where "
+              "g_subprocess_get_if_signaled() always returns FALSE...");
+  return 0;
+#endif
 }
 
 /*< private >*/
@@ -1226,7 +1424,7 @@ g_subprocess_communicate_made_progress (GObject      *source_object,
       source == state->stdout_buf ||
       source == state->stderr_buf)
     {
-      if (!g_output_stream_splice_finish ((GOutputStream*)source, result, &error))
+      if (g_output_stream_splice_finish ((GOutputStream*) source, result, &error) == -1)
         goto out;
 
       if (source == state->stdout_buf ||
@@ -1294,13 +1492,17 @@ g_subprocess_communicate_state_free (gpointer data)
 {
   CommunicateState *state = data;
 
+  g_clear_object (&state->cancellable);
   g_clear_object (&state->stdin_buf);
   g_clear_object (&state->stdout_buf);
   g_clear_object (&state->stderr_buf);
 
-  if (!g_source_is_destroyed (state->cancellable_source))
-    g_source_destroy (state->cancellable_source);
-  g_source_unref (state->cancellable_source);
+  if (state->cancellable_source)
+    {
+      if (!g_source_is_destroyed (state->cancellable_source))
+        g_source_destroy (state->cancellable_source);
+      g_source_unref (state->cancellable_source);
+    }
 
   g_slice_free (CommunicateState, state);
 }
@@ -1366,13 +1568,14 @@ g_subprocess_communicate_internal (GSubprocess         *subprocess,
                            g_subprocess_communicate_made_progress, g_object_ref (task));
   state->outstanding_ops++;
 
+  g_object_unref (task);
   return state;
 }
 
 /**
  * g_subprocess_communicate:
- * @self: a #GSubprocess
- * @stdin_buf: data to send to the stdin of the subprocess, or %NULL
+ * @subprocess: a #GSubprocess
+ * @stdin_buf: (allow-none): data to send to the stdin of the subprocess, or %NULL
  * @cancellable: a #GCancellable
  * @stdout_buf: (out): data read from the subprocess stdout
  * @stderr_buf: (out): data read from the subprocess stderr
@@ -1381,7 +1584,7 @@ g_subprocess_communicate_internal (GSubprocess         *subprocess,
  * Communicate with the subprocess until it terminates, and all input
  * and output has been completed.
  *
- * If @stdin is given, the subprocess must have been created with
+ * If @stdin_buf is given, the subprocess must have been created with
  * %G_SUBPROCESS_FLAGS_STDIN_PIPE.  The given data is fed to the
  * stdin of the subprocess and the pipe is closed (ie: EOF).
  *
@@ -1453,8 +1656,8 @@ g_subprocess_communicate (GSubprocess   *subprocess,
 /**
  * g_subprocess_communicate_async:
  * @subprocess: Self
- * @stdin_buf: Input data
- * @cancellable: Cancellable
+ * @stdin_buf: (allow-none): Input data, or %NULL
+ * @cancellable: (allow-none): Cancellable
  * @callback: Callback
  * @user_data: User data
  *
@@ -1518,8 +1721,8 @@ g_subprocess_communicate_finish (GSubprocess   *subprocess,
 
 /**
  * g_subprocess_communicate_utf8:
- * @self: a #GSubprocess
- * @stdin_buf: data to send to the stdin of the subprocess, or %NULL
+ * @subprocess: a #GSubprocess
+ * @stdin_buf: (allow-none): data to send to the stdin of the subprocess, or %NULL
  * @cancellable: a #GCancellable
  * @stdout_buf: (out): data read from the subprocess stdout
  * @stderr_buf: (out): data read from the subprocess stderr
@@ -1529,23 +1732,26 @@ g_subprocess_communicate_finish (GSubprocess   *subprocess,
  * process as UTF-8, and returns it as a regular NUL terminated string.
  */
 gboolean
-g_subprocess_communicate_utf8 (GSubprocess          *subprocess,
-                               const char           *stdin_buf,
-                               GCancellable         *cancellable,
-                               char                **stdout_buf,
-                               char                **stderr_buf,
-                               GError              **error)
+g_subprocess_communicate_utf8 (GSubprocess   *subprocess,
+                               const char    *stdin_buf,
+                               GCancellable  *cancellable,
+                               char         **stdout_buf,
+                               char         **stderr_buf,
+                               GError       **error)
 {
   GAsyncResult *result = NULL;
   gboolean success;
   GBytes *stdin_bytes;
+  size_t stdin_buf_len = 0;
 
   g_return_val_if_fail (G_IS_SUBPROCESS (subprocess), FALSE);
   g_return_val_if_fail (stdin_buf == NULL || (subprocess->flags & G_SUBPROCESS_FLAGS_STDIN_PIPE), FALSE);
   g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-  stdin_bytes = g_bytes_new (stdin_buf, strlen (stdin_buf));
+  if (stdin_buf != NULL)
+    stdin_buf_len = strlen (stdin_buf);
+  stdin_bytes = g_bytes_new (stdin_buf, stdin_buf_len);
 
   g_subprocess_sync_setup ();
   g_subprocess_communicate_internal (subprocess, TRUE, stdin_bytes, cancellable,
@@ -1561,29 +1767,34 @@ g_subprocess_communicate_utf8 (GSubprocess          *subprocess,
 /**
  * g_subprocess_communicate_utf8_async:
  * @subprocess: Self
- * @stdin_buf: Input data
+ * @stdin_buf: (allow-none): Input data, or %NULL
  * @cancellable: Cancellable
  * @callback: Callback
  * @user_data: User data
  *
- * Asynchronous version of g_subprocess_communicate_utf().  Complete
+ * Asynchronous version of g_subprocess_communicate_utf8().  Complete
  * invocation with g_subprocess_communicate_utf8_finish().
  */
 void
-g_subprocess_communicate_utf8_async (GSubprocess          *subprocess,
-                                     const char           *stdin_buf,
-                                     GCancellable         *cancellable,
-                                     GAsyncReadyCallback   callback,
-                                     gpointer              user_data)
+g_subprocess_communicate_utf8_async (GSubprocess         *subprocess,
+                                     const char          *stdin_buf,
+                                     GCancellable        *cancellable,
+                                     GAsyncReadyCallback  callback,
+                                     gpointer             user_data)
 {
   GBytes *stdin_bytes;
+  size_t stdin_buf_len = 0;
 
   g_return_if_fail (G_IS_SUBPROCESS (subprocess));
   g_return_if_fail (stdin_buf == NULL || (subprocess->flags & G_SUBPROCESS_FLAGS_STDIN_PIPE));
   g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
 
-  stdin_bytes = g_bytes_new (stdin_buf, strlen (stdin_buf));
+  if (stdin_buf != NULL)
+    stdin_buf_len = strlen (stdin_buf);
+  stdin_bytes = g_bytes_new (stdin_buf, stdin_buf_len);
+
   g_subprocess_communicate_internal (subprocess, TRUE, stdin_bytes, cancellable, callback, user_data);
+
   g_bytes_unref (stdin_bytes);
 }
 
@@ -1627,11 +1838,11 @@ communicate_result_validate_utf8 (const char            *stream_name,
  * Complete an invocation of g_subprocess_communicate_utf8_async().
  */
 gboolean
-g_subprocess_communicate_utf8_finish (GSubprocess          *subprocess,
-                                      GAsyncResult         *result,
-                                      char                **stdout_buf,
-                                      char                **stderr_buf,
-                                      GError              **error)
+g_subprocess_communicate_utf8_finish (GSubprocess   *subprocess,
+                                      GAsyncResult  *result,
+                                      char         **stdout_buf,
+                                      char         **stderr_buf,
+                                      GError       **error)
 {
   gboolean ret = FALSE;
   CommunicateState *state;