From c96969c56ef19b3efe7d8b12d3707294e36e4d39 Mon Sep 17 00:00:00 2001 From: falkTX Date: Sun, 14 Feb 2016 21:01:02 +0100 Subject: [PATCH] ExternalWindow: Add code for managing external process --- distrho/extra/ExternalWindow.hpp | 106 +++++++++++++++++++++++++++++-- 1 file changed, 101 insertions(+), 5 deletions(-) diff --git a/distrho/extra/ExternalWindow.hpp b/distrho/extra/ExternalWindow.hpp index 1fe0a06f..a0001149 100644 --- a/distrho/extra/ExternalWindow.hpp +++ b/distrho/extra/ExternalWindow.hpp @@ -19,6 +19,14 @@ #include "../DistrhoUtils.hpp" +#ifdef DISTRHO_OS_UNIX +# include +# include +# include +#else +# error Unsupported platform! +#endif + START_NAMESPACE_DISTRHO // ----------------------------------------------------------------------- @@ -29,7 +37,13 @@ class ExternalWindow public: ExternalWindow(const uint w = 1, const uint h = 1) : width(w), - height(h) {} + height(h), + pid(0) {} + + ~ExternalWindow() + { + terminateAndWaitForProcess(); + } uint getWidth() const noexcept { @@ -41,17 +55,99 @@ public: return height; } - void setSize(const uint w, const uint h) noexcept + bool isRunning() noexcept + { + if (pid <= 0) + return false; + + const pid_t p = ::waitpid(pid, nullptr, WNOHANG); + + if (p == pid || (p == -1 && errno == ECHILD)) + { + printf("NOTICE: Child process exited while idle\n"); + pid = 0; + return false; + } + + return true; + } + +protected: + bool startExternalProcess(const char* args[]) { - DISTRHO_SAFE_ASSERT_RETURN(w > 0 && h > 0,) + terminateAndWaitForProcess(); + + pid = vfork(); + + switch (pid) + { + case 0: + execvp(args[0], (char**)args); + _exit(1); + return false; - width = w; - height = h; + case -1: + printf("Could not start external ui\n"); + return false; + + default: + return true; + } } private: uint width; uint height; + pid_t pid; + + friend class UIExporter; + + void terminateAndWaitForProcess() + { + if (pid <= 0) + return; + + printf("Waiting for previous process to stop,,,\n"); + + bool sendTerm = true; + + for (pid_t p;;) + { + p = ::waitpid(pid, nullptr, WNOHANG); + + switch (p) + { + case 0: + if (sendTerm) + { + sendTerm = false; + ::kill(pid, SIGTERM); + } + break; + + case -1: + if (errno == ECHILD) + { + printf("Done! (no such process)\n"); + pid = 0; + return; + } + break; + + default: + if (p == pid) + { + printf("Done! (clean wait)\n"); + pid = 0; + return; + } + break; + } + + // 5 msec + usleep(5*1000); + } + } DISTRHO_DECLARE_NON_COPY_CLASS(ExternalWindow) };