diff --git a/direct/src/plugin/p3dX11SplashWindow.cxx b/direct/src/plugin/p3dX11SplashWindow.cxx index fcc7324653..57e960c813 100755 --- a/direct/src/plugin/p3dX11SplashWindow.cxx +++ b/direct/src/plugin/p3dX11SplashWindow.cxx @@ -24,12 +24,6 @@ #include #include -// Sleeps for a short time. -#define MILLISLEEP() \ - timespec ts; \ - ts.tv_sec = 0; ts.tv_nsec = 100000; \ - nanosleep(&ts, NULL); - // Clamps a value to two boundaries. #define clamp(x, lb, hb) (x < lb ? lb : (x > hb ? hb : x)) @@ -45,6 +39,10 @@ P3DX11SplashWindow(P3DInstance *inst) : // Init for parent process _subprocess_pid = -1; + // Init for read thread + _started_read_thread = false; + INIT_THREAD(_read_thread); + // Init for subprocess _display = None; _window = None; @@ -185,6 +183,11 @@ button_click_detected() { // This method is called in the child process, and must relay // the information to the parent process. cerr << "click detected\n"; + + TiXmlDocument doc; + TiXmlElement *xcommand = new TiXmlElement("click"); + doc.LinkEndChild(xcommand); + write_xml(_pipe_write, &doc, nout); } //////////////////////////////////////////////////////////////////// @@ -198,18 +201,23 @@ void P3DX11SplashWindow:: start_subprocess() { assert(_subprocess_pid == -1); - // Create a directional pipe to send messages to the sub-process. - // (We don't need a receive pipe.) + // Create a bi-directional pipe to communicate with the sub-process. int to_fd[2]; if (pipe(to_fd) < 0) { perror("failed to create pipe"); } + int from_fd[2]; + if (pipe(from_fd) < 0) { + perror("failed to create pipe"); + } // Fork and exec. pid_t child = fork(); if (child < 0) { close(to_fd[0]); close(to_fd[1]); + close(from_fd[0]); + close(from_fd[1]); perror("fork"); return; } @@ -220,6 +228,8 @@ start_subprocess() { // Open the read end of the pipe, and close the write end. _pipe_read.open_read(to_fd[0]); close(to_fd[1]); + _pipe_write.open_write(from_fd[1]); + close(from_fd[0]); subprocess_run(); _exit(0); @@ -229,6 +239,10 @@ start_subprocess() { _subprocess_pid = child; _pipe_write.open_write(to_fd[1]); close(to_fd[0]); + _pipe_read.open_read(from_fd[0]); + close(from_fd[1]); + + spawn_read_thread(); } //////////////////////////////////////////////////////////////////// @@ -300,6 +314,8 @@ stop_subprocess() { } else if (WIFSTOPPED(status)) { nout << " stopped by " << WSTOPSIG(status) << "\n"; } + + join_read_thread(); } //////////////////////////////////////////////////////////////////// @@ -343,9 +359,76 @@ check_stopped() { } _subprocess_pid = -1; + join_read_thread(); + _inst->request_stop(); } +//////////////////////////////////////////////////////////////////// +// Function: P3DX11SplashWindow::spawn_read_thread +// Access: Private +// Description: Starts the read thread. We need this thread to +// listen for feedback from the subprocess. (At the +// moment, the only kind of feedback we might receive is +// whether the button has been clicked.) +//////////////////////////////////////////////////////////////////// +void P3DX11SplashWindow:: +spawn_read_thread() { + SPAWN_THREAD(_read_thread, rt_thread_run, this); + _started_read_thread = true; +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DX11SplashWindow::join_read_thread +// Access: Private +// Description: Waits for the read thread to stop. +//////////////////////////////////////////////////////////////////// +void P3DX11SplashWindow:: +join_read_thread() { + if (!_started_read_thread) { + return; + } + + JOIN_THREAD(_read_thread); + _started_read_thread = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DX11SplashWindow::rt_thread_run +// Access: Private +// Description: The main function for the read thread. +//////////////////////////////////////////////////////////////////// +void P3DX11SplashWindow:: +rt_thread_run() { + while (true) { + TiXmlDocument *doc = read_xml(_pipe_read, nout); + if (doc == NULL) { + // Some error on reading. + return; + } + + // Successfully read an XML document. + rt_handle_request(doc); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: P3DX11SplashWindow::rt_handle_request +// Access: Private +// Description: Processes a single request or notification received +// from an instance. +//////////////////////////////////////////////////////////////////// +void P3DX11SplashWindow:: +rt_handle_request(TiXmlDocument *doc) { + // Eh, don't even bother decoding the XML. We know it can only be a + // click notification. + delete doc; + + ACQUIRE_LOCK(_api_lock); + P3DSplashWindow::button_click_detected(); + RELEASE_LOCK(_api_lock); +} + //////////////////////////////////////////////////////////////////// // Function: P3DX11SplashWindow::subprocess_run // Access: Private diff --git a/direct/src/plugin/p3dX11SplashWindow.h b/direct/src/plugin/p3dX11SplashWindow.h index 5134a1be49..f237909786 100755 --- a/direct/src/plugin/p3dX11SplashWindow.h +++ b/direct/src/plugin/p3dX11SplashWindow.h @@ -51,11 +51,26 @@ private: void stop_subprocess(); void check_stopped(); + void spawn_read_thread(); + void join_read_thread(); + +private: + // These methods run only within the read thread. + THREAD_CALLBACK_DECLARATION(P3DX11SplashWindow, rt_thread_run); + void rt_thread_run(); + void rt_terminate(); + void rt_handle_request(TiXmlDocument *doc); + private: // Data members that are stored in the parent process. pid_t _subprocess_pid; + HandleStream _pipe_read; HandleStream _pipe_write; + // The remaining members are manipulated by or for the read thread. + bool _started_read_thread; + THREAD _read_thread; + private: // These methods run only within the subprocess. class X11ImageData; @@ -93,7 +108,6 @@ private: X11ImageData _button_click_image; bool _subprocess_continue; - HandleStream _pipe_read; bool _own_display; string _install_label;