X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fpbd%2Fsystem_exec.cc;h=351e4ee066ae118f2f69e0e64de6cf2b90715f42;hb=63ac1e7224406bb51a26494f66aa98d4c2899449;hp=82398af0c84c7854fbd640901dab2a441ce89d73;hpb=5399425f534e2d96d07cf29f427bfa0f39d904b7;p=ardour.git diff --git a/libs/pbd/system_exec.cc b/libs/pbd/system_exec.cc index 82398af0c8..351e4ee066 100644 --- a/libs/pbd/system_exec.cc +++ b/libs/pbd/system_exec.cc @@ -43,16 +43,22 @@ #include #endif +#include #define USE_VFORK +#include "pbd/file_utils.h" +#include "pbd/search_path.h" #include "pbd/system_exec.h" using namespace std; using namespace PBD; static void * interposer_thread (void *arg); + +#ifndef PLATFORM_WINDOWS /* POSIX Process only */ static void close_fd (int& fd) { if (fd >= 0) ::close (fd); fd = -1; } +#endif #if (!defined PLATFORM_WINDOWS && defined NO_VFORK) /* @@ -164,6 +170,7 @@ SystemExec::init () stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE; stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE; stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE; + w_args = NULL; #endif } @@ -192,8 +199,40 @@ SystemExec::SystemExec (std::string command, const std::map s { init (); make_argp_escaped(command, subs); - cmd = argp[0]; - // cmd = strdup(argp[0]); + +#ifdef PLATFORM_WINDOWS + if (argp[0] && strlen (argp[0]) > 0) { + std::string wa = argp[0]; + // only add quotes to command if required.. + if (argp[0][0] != '"' + && argp[0][strlen(argp[0])-1] != '"' + && strchr(argp[0], ' ')) { + wa = "\""; + wa += argp[0]; + wa += "\""; + } + // ...but always quote all args + for (int i = 1; argp[i]; ++i) { + std::string tmp (argp[i]); + while (tmp.find("\"") != std::string::npos) + tmp.replace(tmp.find("\""), 1, "\\\""); + wa += " \""; + wa += tmp; + wa += '"'; + } + w_args = strdup(wa.c_str()); + } +#else + if (find_file (Searchpath (Glib::getenv ("PATH")), argp[0], cmd)) { + // argp[0] exists in $PATH` - set it to the actual path where it was found + free (argp[0]); + argp[0] = strdup(cmd.c_str ()); + } + // else argp[0] not found in path - leave it as-is, it might be an absolute path + + // Glib::find_program_in_path () is only available in Glib >= 2.28 + // cmd = Glib::find_program_in_path (argp[0]); +#endif make_envp(); } @@ -241,7 +280,7 @@ SystemExec::make_argp_escaped(std::string command, const std::map "\" - case '\0': + case '\0': case '\\': arg += '\\'; break; default : arg += '\\'; arg += c; break; } @@ -265,14 +304,6 @@ SystemExec::make_argp_escaped(std::string command, const std::map 0 && (*tmp)[strlen(*tmp) - 1] == '\\') { + wa.append("\\"); } - wa.append(arg); wa.append("\""); tmp++; } @@ -409,8 +453,7 @@ int SystemExec::wait (int options) { while (is_running()) { - WaitForSingleObject(pid->hProcess, INFINITE); - Sleep(20); + WaitForSingleObject(pid->hProcess, 40); } return 0; } @@ -418,7 +461,12 @@ SystemExec::wait (int options) bool SystemExec::is_running () { - return pid?true:false; + if (!pid) return false; + DWORD exit_code; + if (GetExitCodeProcess(pid->hProcess, &exit_code)) { + if (exit_code == STILL_ACTIVE) return true; + } + return false; } int @@ -522,6 +570,7 @@ SystemExec::output_interposer() ReadStdout(data, bytesRead);/* EMIT SIGNAL */ } Terminated();/* EMIT SIGNAL */ + pthread_exit(0); } void @@ -632,7 +681,7 @@ SystemExec::terminate () close_stdin(); if (pid) { - ::usleep(50000); + ::usleep(200000); sched_yield(); wait(WNOHANG); } @@ -640,10 +689,10 @@ SystemExec::terminate () /* if pid is non-zero, the child task is still executing (i.e. it did * not exit in response to stdin being closed). try to kill it. */ - + if (pid) { ::kill(pid, SIGTERM); - usleep(50000); + ::usleep(250000); sched_yield(); wait(WNOHANG); } @@ -660,6 +709,7 @@ SystemExec::terminate () wait(); if (thread_active) pthread_join(thread_id_tt, NULL); thread_active = false; + assert(pid == 0); ::pthread_mutex_unlock(&write_lock); } @@ -801,6 +851,10 @@ SystemExec::start (int stderr_mode, const char *vfork_exec_wrapper) #else signal(SIGPIPE, SIG_DFL); #endif + if (!vfork_exec_wrapper) { + error << _("Cannot start external process, no vfork wrapper") << endmsg; + return -1; + } int good_fds[2] = { pok[1], -1 }; close_allv(good_fds); @@ -863,7 +917,16 @@ SystemExec::output_interposer() for (;fcntl(rfd, F_GETFL)!=-1;) { r = read(rfd, buf, sizeof(buf)); if (r < 0 && (errno == EINTR || errno == EAGAIN)) { - ::usleep(1000); + fd_set rfds; + struct timeval tv; + FD_ZERO(&rfds); + FD_SET(rfd, &rfds); + tv.tv_sec = 0; + tv.tv_usec = 10000; + int rv = select(1, &rfds, NULL, NULL, &tv); + if (rv == -1) { + break; + } continue; } if (r <= 0) { @@ -874,6 +937,7 @@ SystemExec::output_interposer() ReadStdout(rv, r);/* EMIT SIGNAL */ } Terminated();/* EMIT SIGNAL */ + pthread_exit(0); } void