[Spice-devel] [spice-xpi 08/12] Use glib functions to spawn/watch client
Christophe Fergeau
cfergeau at redhat.com
Tue Mar 12 04:23:03 PDT 2013
This removes quite a lot of OS-specific code.
---
SpiceXPI/src/plugin/controller-unix.cpp | 143 +++++++++++++++++---------------
SpiceXPI/src/plugin/controller.h | 7 +-
configure.ac | 2 +-
3 files changed, 85 insertions(+), 67 deletions(-)
diff --git a/SpiceXPI/src/plugin/controller-unix.cpp b/SpiceXPI/src/plugin/controller-unix.cpp
index 0435c24..7b4bc1c 100644
--- a/SpiceXPI/src/plugin/controller-unix.cpp
+++ b/SpiceXPI/src/plugin/controller-unix.cpp
@@ -163,94 +163,107 @@ uint32_t SpiceController::Write(const void *lpBuffer, uint32_t nBytesToWrite)
return len;
}
-bool SpiceController::StartClient()
+void SpiceController::ChildExited(GPid pid, gint status, gpointer user_data)
{
- std::string socket_file(m_tmp_dir);
- socket_file += "/spice-xpi";
+ SpiceController *fake_this = (SpiceController *)user_data;
- /* use a pipe for the children to wait until it gets tracked */
- int pipe_fds[2] = { -1, -1 };
- if (pipe(pipe_fds) < 0) {
- perror("spice-xpi system error");
- return false;
- }
-
- m_pid_controller = fork();
- if (m_pid_controller == 0)
- {
- setpgrp();
+ g_message("Client with pid %p exited", pid);
- close(pipe_fds[1]);
- pipe_fds[1] = -1;
+ g_main_loop_quit(fake_this->m_child_watch_mainloop);
+ /* FIXME: we are not in the main thread!! */
+ fake_this->m_plugin->OnSpiceClientExit(status);
+}
- char c;
- if (read(pipe_fds[0], &c, 1) != 0)
- g_critical("Error while reading on pipe: %s", g_strerror(errno));
+void SpiceController::WaitForPid(GPid pid)
+{
+ GMainContext *context;
+ GSource *source;
- close(pipe_fds[0]);
- pipe_fds[0] = -1;
+ context = g_main_context_new();
- gchar **env = g_get_environ();
- env = g_environ_setenv(env, "SPICE_XPI_SOCKET", socket_file.c_str(), TRUE);
- if (!m_proxy.empty())
- env = g_environ_setenv(env, "SPICE_PROXY", m_proxy.c_str(), TRUE);
+ m_child_watch_mainloop = g_main_loop_new(context, FALSE);
+ source = g_child_watch_source_new(pid);
+ g_source_set_callback(source, (GSourceFunc)ChildExited, this, NULL);
+ g_source_attach(source, context);
- execle("/usr/libexec/spice-xpi-client",
- "/usr/libexec/spice-xpi-client", NULL,
- env);
- g_message("failed to run spice-xpi-client, running spicec instead");
+ g_main_loop_run(m_child_watch_mainloop);
- // TODO: temporary fallback for backward compatibility
- execle("/usr/bin/spicec",
- "/usr/bin/spicec", "--controller", NULL,
- env);
+ g_main_loop_unref(m_child_watch_mainloop);
+ g_main_context_unref(context);
- g_critical("ERROR failed to run spicec fallback");
- g_strfreev(env);
- exit(EXIT_FAILURE);
- }
- else
- {
- g_debug("child pid: %"G_GUINT64_FORMAT, (guint64)m_pid_controller);
+ g_spawn_close_pid(pid);
+ if (pid == m_pid_controller)
+ m_pid_controller = 0;
+}
- close(pipe_fds[0]);
- pipe_fds[0] = -1;
- pthread_t controller_thread_id;
- pthread_create(&controller_thread_id, NULL, ControllerWaitHelper,
- reinterpret_cast<void*>(this));
+gpointer SpiceController::ClientThread(gpointer data)
+{
+ char *spice_xpi_argv[] = { "/usr/libexec/spice-xpi-client", NULL };
+ SpiceController *fake_this = (SpiceController *)data;
+ gchar **env = g_get_environ();
+ GPid pid;
+ gboolean spawned;
+ GError *error = NULL;
+
+ std::string socket_file(fake_this->m_tmp_dir);
+ socket_file += "/spice-xpi";
- close(pipe_fds[1]);
- pipe_fds[1] = -1;
+ fake_this->SetFilename(socket_file);
- this->SetFilename(socket_file);
+ env = g_environ_setenv(env, "SPICE_XPI_SOCKET", socket_file.c_str(), TRUE);
+ if (!fake_this->m_proxy.empty())
+ env = g_environ_setenv(env, "SPICE_PROXY", fake_this->m_proxy.c_str(), TRUE);
- return true;
+ spawned = g_spawn_async(NULL,
+ spice_xpi_argv, env,
+ G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL, NULL, /* child_func, child_arg */
+ &pid, &error);
+ if (error != NULL) {
+ g_warning("failed to start spice-xpi-client: %s", error->message);
+ g_clear_error(&error);
+ }
+ if (!spawned) {
+ // TODO: temporary fallback for backward compatibility
+ char *spicec_argv[] = { "/usr/bin/spicec", "--controller", NULL };
+ g_message("failed to run spice-xpi-client, running spicec instead");
+ spawned = g_spawn_async(NULL, spicec_argv, env,
+ G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL, NULL, /* child_func, child_arg */
+ &pid, &error);
+ }
+ if (error != NULL) {
+ g_warning("failed to start spice-xpi-client: %s", error->message);
+ g_clear_error(&error);
+ }
+ g_strfreev(env);
+ if (!spawned) {
+ g_critical("ERROR failed to run spicec fallback");
+ return NULL;
}
- g_return_val_if_reached(false);
-}
+#ifdef XP_UNIX
+ fake_this->m_pid_controller = pid;
+#endif
+ fake_this->WaitForPid(pid);
-void SpiceController::StopClient()
-{
- if (m_pid_controller > 0)
- kill(-m_pid_controller, SIGTERM);
+ return NULL;
}
-void *SpiceController::ControllerWaitHelper(void *opaque)
+bool SpiceController::StartClient()
{
- SpiceController *fake_this = reinterpret_cast<SpiceController *>(opaque);
- if (!fake_this)
- return NULL;
+ GThread *thread;
- int exit_code;
- waitpid(fake_this->m_pid_controller, &exit_code, 0);
- g_debug("child finished, pid: %"G_GUINT64_FORMAT, (guint64)exit_code);
+ thread = g_thread_create(ClientThread, this, FALSE, NULL);
- fake_this->m_plugin->OnSpiceClientExit(exit_code);
- fake_this->m_pid_controller = -1;
+ return (thread != NULL);
+}
- return NULL;
+void SpiceController::StopClient()
+{
+ if (m_pid_controller > 0)
+ kill(-m_pid_controller, SIGTERM);
}
int SpiceController::TranslateRC(int nRC)
diff --git a/SpiceXPI/src/plugin/controller.h b/SpiceXPI/src/plugin/controller.h
index 54d1d46..268994b 100644
--- a/SpiceXPI/src/plugin/controller.h
+++ b/SpiceXPI/src/plugin/controller.h
@@ -58,6 +58,7 @@
(rather than anonymous pipe which is local only and one way)
*/
+#include <glib.h>
#include <string>
extern "C" {
# include <stdint.h>
@@ -86,7 +87,9 @@ public:
private:
int Connect();
- static void *ControllerWaitHelper(void *opaque);
+ void WaitForPid(GPid pid);
+ static void ChildExited(GPid pid, gint status, gpointer user_data);
+ static gpointer ClientThread(gpointer data);
nsPluginInstance *m_plugin;
int m_client_socket;
@@ -94,6 +97,8 @@ private:
std::string m_tmp_dir;
pid_t m_pid_controller;
std::string m_proxy;
+
+ GMainLoop *m_child_watch_mainloop;
};
#endif // SPICE_CONTROLLER_H
diff --git a/configure.ac b/configure.ac
index 48d3a6b..3ed0cfc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -24,7 +24,7 @@ AC_CONFIG_SUBDIRS([spice-protocol])
SPICE_PROTOCOL_CFLAGS='-I ${top_srcdir}/spice-protocol'
AC_SUBST(SPICE_PROTOCOL_CFLAGS)
-PKG_CHECK_MODULES(GLIB, glib-2.0 gio-2.0)
+PKG_CHECK_MODULES(GLIB, glib-2.0 gio-2.0 gthread-2.0)
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
--
1.8.1.4
More information about the Spice-devel
mailing list