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 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel