|
From: Braden M. <br...@us...> - 2006-01-28 18:58:36
|
Update of /cvsroot/openvrml/openvrml/mozilla-plugin/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19996/mozilla-plugin/src Modified Files: openvrml.cpp Log Message: Launch the child openvrml-player process using g_spawn_async_with_pipes instead of fork/exec. Use the child process' stdin and stdout for the command and request channels, respectively, instead of specifying file descriptors for these on the command line. Index: openvrml.cpp =================================================================== RCS file: /cvsroot/openvrml/openvrml/mozilla-plugin/src/openvrml.cpp,v retrieving revision 1.27 retrieving revision 1.28 diff -C2 -d -r1.27 -r1.28 *** openvrml.cpp 25 Jan 2006 04:24:24 -0000 1.27 --- openvrml.cpp 28 Jan 2006 18:58:25 -0000 1.28 *************** *** 64,69 **** int x, y; int width, height; ! pid_t player_pid; ! int out_pipe[2], in_pipe[2]; GIOChannel * request_channel; std::stringstream request_line; --- 64,68 ---- int x, y; int width, height; ! GIOChannel * command_channel; GIOChannel * request_channel; std::stringstream request_line; *************** *** 77,82 **** void SetWindow(NPWindow & window) throw (std::bad_alloc); void HandleEvent(void * event) throw (); ! int in() const throw (); ! int out() const throw (); }; --- 76,80 ---- void SetWindow(NPWindow & window) throw (std::bad_alloc); void HandleEvent(void * event) throw (); ! ssize_t WriteCommand(const std::string & command); }; *************** *** 412,423 **** command << "new-stream " << ptrdiff_t(stream) << ' ' << type << ' ' << stream->url << '\n'; ! ssize_t bytes_written = write(pluginInstance.out(), ! command.str().data(), ! command.str().length()); ! if (bytes_written < 0) { ! printerr(strerror(errno)); ! return NPERR_GENERIC_ERROR; ! } ! return NPERR_NO_ERROR; } --- 410,417 ---- command << "new-stream " << ptrdiff_t(stream) << ' ' << type << ' ' << stream->url << '\n'; ! const ssize_t bytes_written = pluginInstance.WriteCommand(command.str()); ! return (bytes_written < 0) ! ? NPERR_GENERIC_ERROR ! : NPERR_NO_ERROR; } *************** *** 428,445 **** if (!instance || !instance->pdata) { return NPERR_INVALID_INSTANCE_ERROR; } ! PluginInstance * const pluginInstance = ! static_cast<PluginInstance *>(instance->pdata); std::ostringstream command; command << "destroy-stream " << ptrdiff_t(stream) << '\n'; ! ssize_t bytes_written = write(pluginInstance->out(), ! command.str().data(), ! command.str().length()); ! if (bytes_written < 0) { ! printerr(strerror(errno)); ! return NPERR_GENERIC_ERROR; ! } ! ! return NPERR_NO_ERROR; } --- 422,434 ---- if (!instance || !instance->pdata) { return NPERR_INVALID_INSTANCE_ERROR; } ! PluginInstance & pluginInstance = ! *static_cast<PluginInstance *>(instance->pdata); std::ostringstream command; command << "destroy-stream " << ptrdiff_t(stream) << '\n'; ! const ssize_t bytes_written = pluginInstance.WriteCommand(command.str()); ! return (bytes_written < 0) ! ? NPERR_GENERIC_ERROR ! : NPERR_NO_ERROR; } *************** *** 476,481 **** if (!instance || !instance->pdata) { return 0; } ! PluginInstance * const pluginInstance = ! static_cast<PluginInstance *>(instance->pdata); std::ostringstream command; --- 465,470 ---- if (!instance || !instance->pdata) { return 0; } ! PluginInstance & pluginInstance = ! *static_cast<PluginInstance *>(instance->pdata); std::ostringstream command; *************** *** 485,497 **** command.put(static_cast<char *>(buffer)[i]); } ! ssize_t bytes_written = write(pluginInstance->out(), ! command.str().data(), ! command.str().length()); ! if (bytes_written < 0) { ! printerr(strerror(errno)); ! return NPERR_GENERIC_ERROR; ! } ! return len; /* The number of bytes accepted */ } --- 474,480 ---- command.put(static_cast<char *>(buffer)[i]); } ! const ssize_t bytes_written = pluginInstance.WriteCommand(command.str()); ! return bytes_written; // The number of bytes accepted. } *************** *** 1004,1008 **** ! PluginInstance::PluginInstance(NPP npp) throw (std::bad_alloc): npp(npp), window(0), --- 987,991 ---- ! PluginInstance::PluginInstance(const NPP npp) throw (std::bad_alloc): npp(npp), window(0), *************** *** 1011,1063 **** width(0), height(0), ! player_pid(0), request_channel(0), scriptablePeer(new ScriptablePeer(*this)) ! { ! int result = pipe(this->out_pipe); ! if (result != 0) { ! printerr(strerror(errno)); ! } ! result = pipe(this->in_pipe); ! if (result != 0) { ! printerr(strerror(errno)); ! } ! } PluginInstance::~PluginInstance() throw () { ! if (this->player_pid) { ! if (this->request_channel) { ! GError * error = 0; ! const gboolean flush = false; ! GIOStatus status = g_io_channel_shutdown(this->request_channel, ! flush, ! &error); ! if (status != G_IO_STATUS_NORMAL) { ! if (error) { ! g_critical(error->message); ! g_error_free(error); ! } } } g_io_channel_unref(this->request_channel); ! // ! // The openvrml-player process should detect that this file ! // descriptor has been closed and terminate in response. ! // ! int result = close(this->out_pipe[1]); ! if (result != 0) { ! printerr(strerror(errno)); ! g_error("Failed to close write descriptor for " ! "OpenVRML plug-in's output pipe"); } ! int status; ! int options = 0; ! pid_t pid = waitpid(this->player_pid, &status, options); ! if (pid == -1) { ! printerr(strerror(errno)); ! } } } --- 994,1034 ---- width(0), height(0), ! command_channel(0), request_channel(0), scriptablePeer(new ScriptablePeer(*this)) ! {} PluginInstance::~PluginInstance() throw () { ! if (this->request_channel) { ! GError * error = 0; ! const gboolean flush = false; ! GIOStatus status = g_io_channel_shutdown(this->request_channel, ! flush, ! &error); ! if (status != G_IO_STATUS_NORMAL) { ! if (error) { ! printerr(error->message); ! g_error_free(error); } } + g_io_channel_unref(this->request_channel); + } ! if (this->command_channel) { ! GError * error = 0; ! const gboolean flush = false; ! GIOStatus status = g_io_channel_shutdown(this->command_channel, ! flush, ! &error); ! if (status != G_IO_STATUS_NORMAL) { ! if (error) { ! printerr(error->message); ! g_error_free(error); ! } } ! g_io_channel_unref(this->command_channel); } } *************** *** 1077,1196 **** // } else { ! this->window = GdkNativeWindow(ptrdiff_t(window.window)); ! ! fcntl(this->out_pipe[0], F_SETFD, 0); ! fcntl(this->in_pipe[1], F_SETFD, 0); ! ! this->player_pid = fork(); ! if (this->player_pid == 0) { ! using std::vector; ! using std::string; ! using boost::lexical_cast; ! int result = close(this->out_pipe[1]); ! if (result != 0) { ! g_error("Failed to close write descriptor for " ! "openvrml-player's input pipe"); ! } ! result = close(this->in_pipe[0]); ! if (result != 0) { ! g_error("Failed to close read descriptor for " ! "openvrml-player's output pipe"); ! } ! // ! // The OPENVRML_PLAYER environment variable overrides the ! // default path to the child process executable. To allow ! // OPENVRML_PLAYER to include arguments (rather than just be a ! // path to an executable), it is parsed wit ! // g_shell_parse_argv. This is particularly useful in case we ! // want to run the child process in a harness like valgrind. ! // ! gint openvrml_player_cmd_argc = 0; ! gchar ** openvrml_player_cmd_argv = 0; ! const gchar * const openvrml_player_cmd = ! g_getenv("OPENVRML_PLAYER"); ! if (!openvrml_player_cmd) { ! openvrml_player_cmd_argc = 1; ! openvrml_player_cmd_argv = ! static_cast<gchar **>(g_malloc(sizeof (gchar *))); ! if (!openvrml_player_cmd_argv) { throw std::bad_alloc(); } ! openvrml_player_cmd_argv[0] = ! OPENVRML_LIBEXECDIR_ "/openvrml-player"; ! } else { ! GError * error = 0; ! gboolean succeeded = ! g_shell_parse_argv(openvrml_player_cmd, ! &openvrml_player_cmd_argc, ! &openvrml_player_cmd_argv, ! &error); ! if (!succeeded) { ! if (error) { ! g_critical(error->message); ! g_error_free(error); ! } } } ! string socket_id_arg = ! "--gtk-socket-id=" + lexical_cast<string>(this->window); ! const char * socket_id_arg_c_str = socket_id_arg.c_str(); ! vector<char> socket_id_arg_vec( ! socket_id_arg_c_str, ! socket_id_arg_c_str + socket_id_arg.length() + 1); ! ! string read_fd_arg = ! "--read-fd=" + lexical_cast<string>(this->out_pipe[0]); ! const char * read_fd_arg_c_str = read_fd_arg.c_str(); ! vector<char> read_fd_arg_vec( ! read_fd_arg_c_str, ! read_fd_arg_c_str + read_fd_arg.length() + 1); ! string write_fd_arg = ! "--write-fd=" + lexical_cast<string>(this->in_pipe[1]); ! const char * write_fd_arg_c_str = write_fd_arg.c_str(); ! vector<char> write_fd_arg_vec( ! write_fd_arg_c_str, ! write_fd_arg_c_str + write_fd_arg.length() + 1); ! const gint argv_size = openvrml_player_cmd_argc + 4; ! gchar ** const argv = ! static_cast<gchar **>( ! g_malloc(sizeof (gchar *) * argv_size)); ! if (!argv) { throw std::bad_alloc(); } ! gint i; ! for (i = 0; i < openvrml_player_cmd_argc; ++i) { ! argv[i] = openvrml_player_cmd_argv[i]; } ! argv[i++] = &socket_id_arg_vec.front(); ! argv[i++] = &read_fd_arg_vec.front(); ! argv[i++] = &write_fd_arg_vec.front(); ! argv[i] = 0; ! result = execv(argv[0], argv); ! if (result < 0) { ! g_error("Failed to start openvrml-player"); ! } - g_free(argv); - g_strfreev(openvrml_player_cmd_argv); - } else if (this->player_pid > 0) { - int result = close(this->out_pipe[0]); - if (result != 0) { - printerr(strerror(errno)); - } - result = close(this->in_pipe[1]); - if (result != 0) { - printerr(strerror(errno)); - } - this->request_channel = - g_io_channel_unix_new(this->in_pipe[0]); - g_io_add_watch(this->request_channel, - G_IO_IN, - request_data_available, - this); - } else if (this->player_pid < 0) { - printerr(strerror(errno)); - } } } --- 1048,1148 ---- // } else { ! using std::string; ! using std::vector; ! using boost::lexical_cast; ! this->window = GdkNativeWindow(ptrdiff_t(window.window)); ! // ! // The OPENVRML_PLAYER environment variable overrides the default ! // path to the child process executable. To allow OPENVRML_PLAYER ! // to include arguments (rather than just be a path to an ! // executable), it is parsed wit g_shell_parse_argv. This is ! // particularly useful in case we want to run the child process in ! // a harness like valgrind. ! // ! gint openvrml_player_cmd_argc = 0; ! gchar ** openvrml_player_cmd_argv = 0; ! const gchar * const openvrml_player_cmd = ! g_getenv("OPENVRML_PLAYER"); ! if (!openvrml_player_cmd) { ! openvrml_player_cmd_argc = 1; ! openvrml_player_cmd_argv = ! static_cast<gchar **>(g_malloc(sizeof (gchar *))); ! if (!openvrml_player_cmd_argv) { throw std::bad_alloc(); } ! openvrml_player_cmd_argv[0] = ! OPENVRML_LIBEXECDIR_ "/openvrml-player"; ! } else { ! GError * error = 0; ! gboolean succeeded = ! g_shell_parse_argv(openvrml_player_cmd, ! &openvrml_player_cmd_argc, ! &openvrml_player_cmd_argv, ! &error); ! if (!succeeded) { ! if (error) { ! g_critical(error->message); ! g_error_free(error); } } + } ! string socket_id_arg = ! "--gtk-socket-id=" + lexical_cast<string>(this->window); ! const char * socket_id_arg_c_str = socket_id_arg.c_str(); ! vector<char> socket_id_arg_vec( ! socket_id_arg_c_str, ! socket_id_arg_c_str + socket_id_arg.length() + 1); ! const gint argv_size = openvrml_player_cmd_argc + 2; ! gchar ** const argv = ! static_cast<gchar **>(g_malloc(sizeof (gchar *) * argv_size)); ! if (!argv) { throw std::bad_alloc(); } ! gint i; ! for (i = 0; i < openvrml_player_cmd_argc; ++i) { ! argv[i] = openvrml_player_cmd_argv[i]; ! } ! argv[i++] = &socket_id_arg_vec.front(); ! argv[i] = 0; ! gchar * const working_directory = g_get_current_dir(); ! if (!working_directory) { throw std::bad_alloc(); }; ! gchar ** envp = 0; ! GPid * const child_pid = 0; ! gint standard_input, standard_output; ! gint * const standard_error = 0; ! GError * error = 0; ! gboolean succeeded = g_spawn_async_with_pipes(working_directory, ! argv, ! envp, ! GSpawnFlags(0), ! 0, ! 0, ! child_pid, ! &standard_input, ! &standard_output, ! standard_error, ! &error); ! if (!succeeded) { ! if (error) { ! g_critical(error->message); ! g_error_free(error); } ! } ! g_free(working_directory); ! g_free(argv); ! g_strfreev(openvrml_player_cmd_argv); ! ! this->command_channel = g_io_channel_unix_new(standard_input); ! if (!this->command_channel) { throw std::bad_alloc(); } ! ! this->request_channel = g_io_channel_unix_new(standard_output); ! if (!this->command_channel) { throw std::bad_alloc(); } ! g_io_add_watch(this->request_channel, ! G_IO_IN, ! request_data_available, ! this); } } *************** *** 1199,1210 **** {} ! int PluginInstance::in() const throw () { ! return this->in_pipe[0]; ! } ! int PluginInstance::out() const throw () ! { ! return this->out_pipe[1]; } --- 1151,1184 ---- {} ! ssize_t PluginInstance::WriteCommand(const std::string & command) { ! gsize bytes_written; ! GError * error = 0; ! GIOStatus status = g_io_channel_write_chars(this->command_channel, ! command.data(), ! command.length(), ! &bytes_written, ! &error); ! if (status != G_IO_STATUS_NORMAL) { ! if (error) { ! printerr(error->message); ! g_error_free(error); ! } ! return -1; ! } ! do { ! status = g_io_channel_flush(this->command_channel, &error); ! } while (status == G_IO_STATUS_AGAIN); ! ! if (status != G_IO_STATUS_NORMAL) { ! if (error) { ! printerr(error->message); ! g_error_free(error); ! } ! return -1; ! } ! ! return bytes_written; } |