X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Fsystem_exec.cc;h=55dbc60bb4c2cf80c367ca1484e453692c07a2dd;hb=5dca8270eb589cc60c756e09bd02ce323805b741;hp=00b212710e63392a610d702523b9eac09c0fc83f;hpb=810e59d61a46a9a7c3fdde8fac6f7ba63cdcf1b7;p=ardour.git diff --git a/gtk2_ardour/system_exec.cc b/gtk2_ardour/system_exec.cc index 00b212710e..55dbc60bb4 100644 --- a/gtk2_ardour/system_exec.cc +++ b/gtk2_ardour/system_exec.cc @@ -1,5 +1,6 @@ /* Copyright (C) 2010 Paul Davis + Copyright 2005-2008 Lennart Poettering Author: Robin Gareus This program is free software; you can redistribute it and/or modify @@ -17,14 +18,15 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifdef WITH_VIDEOTIMELINE - #include #include #include #include #include +#include +#include + #ifdef __WIN32__ #include #else @@ -32,13 +34,117 @@ #include #include #include +#include +#include +#include #endif + #include "system_exec.h" using namespace std; void * interposer_thread (void *arg); +static void close_fd (int& fd) { if (fd >= 0) ::close (fd); fd = -1; } + +#ifndef __WIN32__ +/* + * This function was part of libasyncns. + * LGPL v2.1 + * Copyright 2005-2008 Lennart Poettering + */ +static int close_allv(const int except_fds[]) { + struct rlimit rl; + int fd; + +#ifdef __linux__ + + DIR *d; + + assert(except_fds); + + if ((d = opendir("/proc/self/fd"))) { + struct dirent *de; + + while ((de = readdir(d))) { + int found; + long l; + char *e = NULL; + int i; + + if (de->d_name[0] == '.') + continue; + + errno = 0; + l = strtol(de->d_name, &e, 10); + if (errno != 0 || !e || *e) { + closedir(d); + errno = EINVAL; + return -1; + } + + fd = (int) l; + + if ((long) fd != l) { + closedir(d); + errno = EINVAL; + return -1; + } + + if (fd < 3) + continue; + + if (fd == dirfd(d)) + continue; + + found = 0; + for (i = 0; except_fds[i] >= 0; i++) + if (except_fds[i] == fd) { + found = 1; + break; + } + + if (found) continue; + + if (close(fd) < 0) { + int saved_errno; + + saved_errno = errno; + closedir(d); + errno = saved_errno; + + return -1; + } + } + + closedir(d); + return 0; + } + +#endif + + if (getrlimit(RLIMIT_NOFILE, &rl) < 0) + return -1; + + for (fd = 0; fd < (int) rl.rlim_max; fd++) { + int i; + + if (fd <= 3) + continue; + + for (i = 0; except_fds[i] >= 0; i++) + if (except_fds[i] == fd) + continue; + + if (close(fd) < 0 && errno != EBADF) + return -1; + } + + return 0; +} +#endif /* not on windows */ + + SystemExec::SystemExec (std::string c, std::string a) : cmd(c) { @@ -293,6 +399,10 @@ SystemExec::output_interposer() { DWORD bytesRead = 0; char data[BUFSIZ]; +#if 0 // untested code to set up nonblocking + unsigned long l = 1; + ioctlsocket(stdoutP[0], FIONBIO, &l); +#endif while(1) { #if 0 // for non-blocking pipes.. DWORD bytesAvail = 0; @@ -409,18 +519,33 @@ void SystemExec::terminate () { ::pthread_mutex_lock(&write_lock); + + /* close stdin in an attempt to get the child to exit cleanly. + */ + close_stdin(); + if (pid) { - ::usleep(100000); + ::usleep(50000); + sched_yield(); wait(WNOHANG); } + /* 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) { - ::fprintf(stderr, "Child process is running. trying SIGTERM\n"); ::kill(pid, SIGTERM); - ::usleep(10000); + ::usleep(50000); + sched_yield(); wait(WNOHANG); } + + /* if pid is non-zero, the child task is STILL executing after being + * sent SIGTERM. Act tough ... send SIGKILL + */ + if (pid) { ::fprintf(stderr, "Process is still running! trying SIGKILL\n"); ::kill(pid, SIGKILL); @@ -436,12 +561,23 @@ int SystemExec::wait (int options) { int status=0; + int ret; + if (pid==0) return -1; - if (pid==::waitpid(pid, &status, options)) { - pid=0; - } - if (errno == ECHILD) { - pid=0; + + ret = waitpid (pid, &status, options); + + if (ret == pid) { + if (WEXITSTATUS(status) || WIFSIGNALED(status)) { + pid=0; + } + } else { + if (ret != 0) { + if (errno == ECHILD) { + /* no currently running children, reset pid */ + pid=0; + } + } /* else the process is still running */ } return status; } @@ -479,18 +615,18 @@ SystemExec::start (int stderr_mode) pid=r; /* check if execve was successful. */ - ::close(pok[1]); + close_fd(pok[1]); char buf; for ( ;; ) { - int n = ::read(pok[0], &buf, 1 ); + ssize_t n = ::read(pok[0], &buf, 1 ); if ( n==1 ) { /* child process returned from execve */ pid=0; - ::close(pok[0]); - ::close(pin[1]); - ::close(pin[0]); - ::close(pout[1]); - ::close(pout[0]); + close_fd(pok[0]); + close_fd(pin[1]); + close_fd(pin[0]); + close_fd(pout[1]); + close_fd(pout[0]); pin[1] = -1; return -3; } else if ( n==-1 ) { @@ -499,7 +635,7 @@ SystemExec::start (int stderr_mode) } break; } - ::close(pok[0]); + close_fd(pok[0]); /* child started successfully */ #if 0 @@ -515,17 +651,17 @@ SystemExec::start (int stderr_mode) } if (r == 0) { /* 2nd child process - catch stdout */ - ::close(pin[1]); - ::close(pout[1]); + close_fd(pin[1]); + close_fd(pout[1]); output_interposer(); exit(0); } - ::close(pout[1]); - ::close(pin[0]); - ::close(pout[0]); + close_fd(pout[1]); + close_fd(pin[0]); + close_fd(pout[0]); #else /* use pthread */ - ::close(pout[1]); - ::close(pin[0]); + close_fd(pout[1]); + close_fd(pin[0]); int rv = pthread_create(&thread_id_tt, NULL, interposer_thread, this); thread_active=true; @@ -539,15 +675,15 @@ SystemExec::start (int stderr_mode) } /* child process - exec external process */ - ::close(pok[0]); + close_fd(pok[0]); ::fcntl(pok[1], F_SETFD, FD_CLOEXEC); - ::close(pin[1]); + close_fd(pin[1]); if (pin[0] != STDIN_FILENO) { ::dup2(pin[0], STDIN_FILENO); } - ::close(pin[0]); - ::close(pout[0]); + close_fd(pin[0]); + close_fd(pout[0]); if (pout[1] != STDOUT_FILENO) { ::dup2(pout[1], STDOUT_FILENO); } @@ -565,7 +701,7 @@ SystemExec::start (int stderr_mode) } if (pout[1] != STDOUT_FILENO && pout[1] != STDERR_FILENO) { - ::close(pout[1]); + close_fd(pout[1]); } if (nicelevel !=0) { @@ -588,11 +724,16 @@ SystemExec::start (int stderr_mode) signal(SIGPIPE, SIG_DFL); #endif +#ifndef __WIN32__ + int good_fds[1] = { 0 }; + close_allv(good_fds); +#endif + ::execve(argp[0], argp, envp); /* if we reach here something went wrong.. */ char buf = 0; (void) ::write(pok[1], &buf, 1 ); - (void) ::close(pok[1]); + close_fd(pok[1]); exit(-1); return -1; } @@ -602,7 +743,11 @@ SystemExec::output_interposer() { int rfd=pout[0]; char buf[BUFSIZ]; - size_t r; + ssize_t r; + unsigned long l = 1; + + ioctl(rfd, FIONBIO, &l); // set non-blocking I/O + for (;fcntl(rfd, F_GETFL)!=-1;) { r = read(rfd, buf, sizeof(buf)); if (r < 0 && (errno == EINTR || errno == EAGAIN)) { @@ -623,18 +768,18 @@ void SystemExec::close_stdin() { if (pin[1]<0) return; - ::close(pin[0]); - ::close(pin[1]); - ::close(pout[0]); - ::close(pout[1]); - pin[1] = - 1; // mark as closed + close_fd(pin[0]); + close_fd(pin[1]); + close_fd(pout[0]); + close_fd(pout[1]); } int SystemExec::write_to_stdin(std::string d, size_t len) { const char *data; - size_t r,c; + ssize_t r; + size_t c; ::pthread_mutex_lock(&write_lock); data=d.c_str(); @@ -649,7 +794,7 @@ SystemExec::write_to_stdin(std::string d, size_t len) sleep(1); continue; } - if (r != (len-c)) { + if ((size_t) r != (len-c)) { ::pthread_mutex_unlock(&write_lock); return c; } @@ -663,5 +808,3 @@ SystemExec::write_to_stdin(std::string d, size_t len) } #endif // end UNIX process - -#endif /* WITH_VIDEOTIMELINE */