possible fix for #5441 -- ardour hangs on shutdown (trying to stop harvid/xjadeo)
[ardour.git] / gtk2_ardour / system_exec.cc
1 /*
2     Copyright (C) 2010 Paul Davis
3     Author: Robin Gareus <robin@gareus.org>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20 #ifdef WITH_VIDEOTIMELINE
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <unistd.h>
27
28 #ifdef __WIN32__
29 #include <windows.h>
30 #else
31 #include <fcntl.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <sys/socket.h>
35 #include <sys/ioctl.h>
36 #endif
37
38 #include "system_exec.h"
39
40 using namespace std;
41 void * interposer_thread (void *arg);
42
43 SystemExec::SystemExec (std::string c, std::string a)
44         : cmd(c)
45 {
46         pthread_mutex_init(&write_lock, NULL);
47         thread_active=false;
48         pid = 0;
49         pin[1] = -1;
50         nicelevel = 0;
51         envp = NULL;
52         argp = NULL;
53 #ifdef __WIN32__
54         stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE;
55         stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE;
56         stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE;
57 #endif
58         make_envp();
59         make_argp(a);
60 }
61
62 SystemExec::SystemExec (std::string c, char **a)
63         : cmd(c) , argp(a)
64 {
65         pthread_mutex_init(&write_lock, NULL);
66         thread_active=false;
67         pid = 0;
68         pin[1] = -1;
69         nicelevel = 0;
70         envp = NULL;
71 #ifdef __WIN32__
72         stdinP[0] = stdinP[1] = INVALID_HANDLE_VALUE;
73         stdoutP[0] = stdoutP[1] = INVALID_HANDLE_VALUE;
74         stderrP[0] = stderrP[1] = INVALID_HANDLE_VALUE;
75         make_wargs(a);
76 #endif
77         make_envp();
78 }
79
80 SystemExec::~SystemExec ()
81 {
82         terminate ();
83         if (envp) {
84                 for (int i=0;envp[i];++i) {
85                   free(envp[i]);
86                 }
87                 free (envp);
88         }
89         if (argp) {
90                 for (int i=0;argp[i];++i) {
91                   free(argp[i]);
92                 }
93                 free (argp);
94         }
95 #ifdef __WIN32__
96         if (w_args) free(w_args);
97 #endif
98         pthread_mutex_destroy(&write_lock);
99 }
100
101 void *
102 interposer_thread (void *arg) {
103         SystemExec *sex = static_cast<SystemExec *>(arg);
104         sex->output_interposer();
105         pthread_exit(0);
106         return 0;
107 }
108
109 #ifdef __WIN32__ /* Windows Process */
110
111 /* HELPER FUNCTIONS */
112
113 static void create_pipe (HANDLE *pipe, bool in) {
114         SECURITY_ATTRIBUTES secAtt = { sizeof( SECURITY_ATTRIBUTES ), NULL, TRUE };
115         HANDLE tmpHandle;
116         if (in) {
117                 if (!CreatePipe(&pipe[0], &tmpHandle, &secAtt, 1024 * 1024)) return;
118                 if (!DuplicateHandle(GetCurrentProcess(), tmpHandle, GetCurrentProcess(), &pipe[1], 0, FALSE, DUPLICATE_SAME_ACCESS)) return;
119         } else {
120                 if (!CreatePipe(&tmpHandle, &pipe[1], &secAtt, 1024 * 1024)) return;
121                 if (!DuplicateHandle(GetCurrentProcess(), tmpHandle, GetCurrentProcess(), &pipe[0], 0, FALSE, DUPLICATE_SAME_ACCESS)) return;
122         }
123         CloseHandle(tmpHandle);
124 }
125
126 static void destroy_pipe (HANDLE pipe[2]) {
127         if (pipe[0] != INVALID_HANDLE_VALUE) {
128                 CloseHandle(pipe[0]);
129                 pipe[0] = INVALID_HANDLE_VALUE;
130         }
131         if (pipe[1] != INVALID_HANDLE_VALUE) {
132                 CloseHandle(pipe[1]);
133                 pipe[1] = INVALID_HANDLE_VALUE;
134         }
135 }
136
137 static BOOL CALLBACK my_terminateApp(HWND hwnd, LPARAM procId)
138 {
139         DWORD currentProcId = 0;
140         GetWindowThreadProcessId(hwnd, &currentProcId);
141         if (currentProcId == (DWORD)procId)
142                 PostMessage(hwnd, WM_CLOSE, 0, 0);
143         return TRUE;
144 }
145
146 /* PROCESS API */
147
148 void
149 SystemExec::make_envp() {
150         ;/* environemt is copied over with CreateProcess(...,env=0 ,..) */
151 }
152
153 void
154 SystemExec::make_wargs(char **a) {
155         std::string wa = cmd;
156         if (cmd[0] != '"' && cmd[cmd.size()] != '"' && strchr(cmd.c_str(), ' ')) { wa = "\"" + cmd + "\""; }
157         std::replace(cmd.begin(), cmd.end(), '/', '\\' );
158         char **tmp = a;
159         while (tmp && *tmp) {
160                 wa.append(" \"");
161                 wa.append(*tmp);
162                 wa.append("\"");
163                 tmp++;
164         }
165         w_args = strdup(wa.c_str());
166 }
167
168 void
169 SystemExec::make_argp(std::string args) {
170         std::string wa = cmd;
171         if (cmd[0] != '"' && cmd[cmd.size()] != '"' && strchr(cmd.c_str(), ' ')) { wa = "\"" + cmd + "\""; }
172         std::replace(cmd.begin(), cmd.end(), '/', '\\' );
173         wa.append(" ");
174         wa.append(args);
175         w_args = strdup(wa.c_str());
176 }
177
178 void
179 SystemExec::terminate ()
180 {
181         ::pthread_mutex_lock(&write_lock);
182         if (pid) {
183                 /* terminate */
184                 EnumWindows(my_terminateApp, (LPARAM)pid->dwProcessId);
185                 PostThreadMessage(pid->dwThreadId, WM_CLOSE, 0, 0);
186
187                 /* kill ! */
188                 TerminateProcess(pid->hProcess, 0xf291);
189
190                 CloseHandle(pid->hThread);
191                 CloseHandle(pid->hProcess);
192                 destroy_pipe(stdinP);
193                 destroy_pipe(stdoutP);
194                 destroy_pipe(stderrP);
195                 delete pid;
196                 pid=0;
197         }
198         ::pthread_mutex_unlock(&write_lock);
199 }
200
201 int
202 SystemExec::wait (int options)
203 {
204         while (is_running()) {
205                 WaitForSingleObject(pid->hProcess, INFINITE);
206                 Sleep(20);
207         }
208         return 0;
209 }
210
211 bool
212 SystemExec::is_running ()
213 {
214         return pid?true:false;
215 }
216
217 int
218 SystemExec::start (int stderr_mode)
219 {
220         char* working_dir = 0;
221
222         if (pid) { return 0; }
223
224         pid = new PROCESS_INFORMATION;
225         memset(pid, 0, sizeof(PROCESS_INFORMATION));
226
227         create_pipe(stdinP, true);
228         create_pipe(stdoutP, false);
229
230         if (stderr_mode == 2) {
231         /* merge stout & stderr */
232                 DuplicateHandle(GetCurrentProcess(), stdoutP[1], GetCurrentProcess(), &stderrP[1], 0, TRUE, DUPLICATE_SAME_ACCESS);
233         } else if (stderr_mode == 1) {
234                 //TODO read/flush this pipe or close it...
235                 create_pipe(stderrP, false);
236         } else {
237                 //TODO: keep stderr of this process mode.
238         }
239
240         bool success = false;
241         STARTUPINFOA startupInfo = { sizeof( STARTUPINFO ), 0, 0, 0,
242                 (unsigned long)CW_USEDEFAULT, (unsigned long)CW_USEDEFAULT,
243                 (unsigned long)CW_USEDEFAULT, (unsigned long)CW_USEDEFAULT,
244                 0, 0, 0,
245                 STARTF_USESTDHANDLES,
246                 0, 0, 0,
247                 stdinP[0], stdoutP[1], stderrP[1]
248         };
249
250         success = CreateProcess(0, w_args,
251                 0, 0, /* bInheritHandles = */ TRUE,
252                 (CREATE_NO_WINDOW&0) | CREATE_UNICODE_ENVIRONMENT | (0&CREATE_NEW_CONSOLE),
253                 /*env = */ 0,
254                 working_dir,
255                 &startupInfo, pid);
256
257         if (stdinP[0] != INVALID_HANDLE_VALUE) {
258                 CloseHandle(stdinP[0]);
259                 stdinP[0] = INVALID_HANDLE_VALUE;
260         }
261         if (stdoutP[1] != INVALID_HANDLE_VALUE) {
262                 CloseHandle(stdoutP[1]);
263                 stdoutP[1] = INVALID_HANDLE_VALUE;
264         }
265         if (stderrP[1] != INVALID_HANDLE_VALUE) {
266                 CloseHandle(stderrP[1]);
267                 stderrP[1] = INVALID_HANDLE_VALUE;
268         }
269
270         if (!success) {
271                 CloseHandle(pid->hThread);
272                 CloseHandle(pid->hProcess);
273                 destroy_pipe(stdinP);
274                 destroy_pipe(stdoutP);
275                 destroy_pipe(stderrP);
276                 delete pid;
277                 pid=0;
278                 return -1;
279         }
280
281         int rv = pthread_create(&thread_id_tt, NULL, interposer_thread, this);
282         thread_active=true;
283         if (rv) {
284                 thread_active=false;
285                 terminate();
286                 return -2;
287         }
288         Sleep(20);
289         return 0;
290 }
291
292 void
293 SystemExec::output_interposer()
294 {
295         DWORD bytesRead = 0;
296         char data[BUFSIZ];
297 #if 0 // untested code to set up nonblocking
298         unsigned long l = 1;
299         ioctlsocket(stdoutP[0], FIONBIO, &l);
300 #endif
301         while(1) {
302 #if 0 // for non-blocking pipes..
303                 DWORD bytesAvail = 0;
304                 PeekNamedPipe(stdoutP[0], 0, 0, 0, &bytesAvail, 0);
305                 if (bytesAvail < 1) {Sleep(500); printf("N/A\n"); continue;}
306 #endif
307                 if (stdoutP[0] == INVALID_HANDLE_VALUE) break;
308                 if (!ReadFile(stdoutP[0], data, BUFSIZ, &bytesRead, 0)) break;
309                 if (bytesRead < 1) continue; /* actually not needed; but this is safe. */
310                 data[bytesRead] = 0;
311                 ReadStdout(data, bytesRead);/* EMIT SIGNAL */
312         }
313         Terminated();/* EMIT SIGNAL */
314 }
315
316 void
317 SystemExec::close_stdin()
318 {
319         if (stdinP[0]!= INVALID_HANDLE_VALUE)  FlushFileBuffers(stdinP[0]);
320         if (stdinP[1]!= INVALID_HANDLE_VALUE)  FlushFileBuffers(stdinP[1]);
321         Sleep(200);
322         destroy_pipe(stdinP);
323 }
324
325 int
326 SystemExec::write_to_stdin(std::string d, size_t len)
327 {
328         const char *data;
329         DWORD r,c;
330
331         ::pthread_mutex_lock(&write_lock);
332
333         data=d.c_str();
334         if (len == 0) {
335                 len=(d.length());
336         }
337         c=0;
338         while (c < len) {
339                 if (!WriteFile(stdinP[1], data+c, len-c, &r, NULL)) {
340                         if (GetLastError() == 0xE8 /*NT_STATUS_INVALID_USER_BUFFER*/) {
341                                 Sleep(100);
342                                 continue;
343                         } else {
344                                 fprintf(stderr, "SYSTEM-EXEC: stdin write error.\n");
345                                 break;
346                         }
347                 }
348                 c += r;
349         }
350         ::pthread_mutex_unlock(&write_lock);
351         return c;
352 }
353
354
355 /* end windows process */
356 #else
357 /* UNIX/POSIX process */
358
359 extern char **environ;
360 void
361 SystemExec::make_envp() {
362         int i=0;
363         envp = (char **) calloc(1, sizeof(char*));
364         /* copy current environment */
365         for (i=0;environ[i];++i) {
366           envp[i] = strdup(environ[i]);
367           envp = (char **) realloc(envp, (i+2) * sizeof(char*));
368         }
369         envp[i] = 0;
370 }
371
372 void
373 SystemExec::make_argp(std::string args) {
374         int argn = 1;
375         char *cp1;
376         char *cp2;
377
378         char *carg = strdup(args.c_str());
379
380         argp = (char **) malloc((argn + 1) * sizeof(char *));
381         if (argp == (char **) 0) {
382                 free(carg);
383                 return; // FATAL
384         }
385
386         argp[0] = strdup(cmd.c_str());
387
388         /* TODO: quotations and escapes
389          * http://stackoverflow.com/questions/1511797/convert-string-to-argv-in-c
390          *
391          * It's actually not needed. All relevant invocations specify 'argp' directly.
392          * Only 'xjadeo -L -R' uses this function and that uses neither quotations
393          * nor arguments with white-space.
394          */
395         for (cp1 = cp2 = carg; *cp2 != '\0'; ++cp2) {
396                 if (*cp2 == ' ') {
397                         *cp2 = '\0';
398                         argp[argn++] = strdup(cp1);
399                         cp1 = cp2 + 1;
400             argp = (char **) realloc(argp, (argn + 1) * sizeof(char *));
401                 }
402         }
403         if (cp2 != cp1) {
404                 argp[argn++] = strdup(cp1);
405                 argp = (char **) realloc(argp, (argn + 1) * sizeof(char *));
406         }
407         argp[argn] = (char *) 0;
408         free(carg);
409 }
410
411
412
413 void
414 SystemExec::terminate ()
415 {
416         ::pthread_mutex_lock(&write_lock);
417         close_stdin();
418         if (pid) {
419                 ::usleep(50000);
420                 sched_yield();
421                 wait(WNOHANG);
422         }
423
424         if (pid) {
425                 ::kill(pid, SIGTERM);
426                 ::usleep(50000);
427                 sched_yield();
428                 wait(WNOHANG);
429         }
430         if (pid) {
431                 ::fprintf(stderr, "Process is still running! trying SIGKILL\n");
432                 ::kill(pid, SIGKILL);
433         }
434
435         wait();
436         if (thread_active) pthread_join(thread_id_tt, NULL);
437         thread_active = false;
438         ::pthread_mutex_unlock(&write_lock);
439 }
440
441 int
442 SystemExec::wait (int options)
443 {
444         int status=0;
445         if (pid==0) return -1;
446         if (pid==::waitpid(pid, &status, options)) {
447                 pid=0;
448         }
449         if (errno == ECHILD) {
450                 pid=0;
451         }
452         return status;
453 }
454
455 bool
456 SystemExec::is_running ()
457 {
458         int status=0;
459         if (pid==0) return false;
460         if (::waitpid(pid, &status, WNOHANG)==0) return true;
461         return false;
462 }
463
464 int
465 SystemExec::start (int stderr_mode)
466 {
467         if (is_running()) {
468                 return 0; // mmh what to return here?
469         }
470         int r;
471
472         if (::pipe(pin) < 0 || ::pipe(pout) < 0 || ::pipe(pok) < 0) {
473                 /* Something unexpected went wrong creating a pipe. */
474                 return -1;
475         }
476
477         r = ::fork();
478         if (r < 0) {
479                 /* failed to fork */
480                 return -2;
481         }
482
483         if (r > 0) {
484                 /* main */
485                 pid=r;
486
487                 /* check if execve was successful. */
488                 ::close(pok[1]);
489                 char buf;
490                 for ( ;; ) {
491                         ssize_t n = ::read(pok[0], &buf, 1 );
492                         if ( n==1 ) {
493                                 /* child process returned from execve */
494                                 pid=0;
495                                 ::close(pok[0]);
496                                 ::close(pin[1]);
497                                 ::close(pin[0]);
498                                 ::close(pout[1]);
499                                 ::close(pout[0]);
500                                 pin[1] = -1;
501                                 return -3;
502                         } else if ( n==-1 ) {
503                                  if ( errno==EAGAIN || errno==EINTR )
504                                          continue;
505                         }
506                         break;
507                 }
508                 ::close(pok[0]);
509                 /* child started successfully */
510
511 #if 0
512 /* use fork for output-interposer
513  * it will run in a separated process
514  */
515                 /* catch stdout thread */
516                 r = ::fork();
517                 if (r < 0) {
518                         // failed to fork
519                         terminate();
520                         return -2;
521                 }
522                 if (r == 0) {
523                         /* 2nd child process - catch stdout */
524                         ::close(pin[1]);
525                         ::close(pout[1]);
526                         output_interposer();
527                         exit(0);
528                 }
529                 ::close(pout[1]);
530                 ::close(pin[0]);
531                 ::close(pout[0]);
532 #else /* use pthread */
533                 ::close(pout[1]);
534                 ::close(pin[0]);
535                 int rv = pthread_create(&thread_id_tt, NULL, interposer_thread, this);
536
537                 thread_active=true;
538                 if (rv) {
539                         thread_active=false;
540                         terminate();
541                         return -2;
542                 }
543 #endif
544                 return 0; /* all systems go - return to main */
545         }
546
547         /* child process - exec external process */
548         ::close(pok[0]);
549         ::fcntl(pok[1], F_SETFD, FD_CLOEXEC);
550
551         ::close(pin[1]);
552         if (pin[0] != STDIN_FILENO) {
553           ::dup2(pin[0], STDIN_FILENO);
554         }
555         ::close(pin[0]);
556         ::close(pout[0]);
557         if (pout[1] != STDOUT_FILENO) {
558                 ::dup2(pout[1], STDOUT_FILENO);
559         }
560
561         if (stderr_mode == 2) {
562                 /* merge STDERR into output */
563                 if (pout[1] != STDERR_FILENO) {
564                         ::dup2(pout[1], STDERR_FILENO);
565                 }
566         } else if (stderr_mode == 1) {
567                 /* ignore STDERR */
568                 ::close(STDERR_FILENO);
569         } else {
570                 /* keep STDERR */
571         }
572
573         if (pout[1] != STDOUT_FILENO && pout[1] != STDERR_FILENO) {
574                 ::close(pout[1]);
575         }
576
577         if (nicelevel !=0) {
578                 ::nice(nicelevel);
579         }
580
581 #if 0
582         /* chdir to executable dir */
583         char *directory;
584         directory = strdup(cmd.c_str());
585         if (strrchr(directory, '/') != (char *) 0) {
586                 ::chdir(directory);
587         }
588         free(directory);
589 #endif
590
591 #ifdef HAVE_SIGSET
592         sigset(SIGPIPE, SIG_DFL);
593 #else
594         signal(SIGPIPE, SIG_DFL);
595 #endif
596
597         ::execve(argp[0], argp, envp);
598         /* if we reach here something went wrong.. */
599         char buf = 0;
600         (void) ::write(pok[1], &buf, 1 );
601         (void) ::close(pok[1]);
602         exit(-1);
603         return -1;
604 }
605
606 void
607 SystemExec::output_interposer()
608 {
609         int rfd=pout[0];
610         char buf[BUFSIZ];
611         ssize_t r;
612         unsigned long l = 1;
613
614   ioctl(rfd, FIONBIO, &l); // set non-blocking I/O
615
616         for (;fcntl(rfd, F_GETFL)!=-1;) {
617                 r = read(rfd, buf, sizeof(buf));
618                 if (r < 0 && (errno == EINTR || errno == EAGAIN)) {
619                         ::usleep(1000);
620                         continue;
621                 }
622                 if (r <= 0) {
623                         break;
624                 }
625                 buf[r]=0;
626                 std::string rv = std::string(buf,r); // TODO: check allocation strategy
627                 ReadStdout(rv, r);/* EMIT SIGNAL */
628         }
629         Terminated();/* EMIT SIGNAL */
630 }
631
632 void
633 SystemExec::close_stdin()
634 {
635         if (pin[1]<0) return;
636         ::close(pin[0]);
637         ::close(pin[1]);
638         ::close(pout[0]);
639         ::close(pout[1]);
640         pin[1] = - 1; // mark as closed
641 }
642
643 int
644 SystemExec::write_to_stdin(std::string d, size_t len)
645 {
646         const char *data;
647         size_t r,c;
648         ::pthread_mutex_lock(&write_lock);
649
650         data=d.c_str();
651         if (len == 0) {
652                 len=(d.length());
653         }
654         c=0;
655         while (c < len) {
656                 for (;;) {
657                         r=::write(pin[1], data+c, len-c);
658                         if (r < 0 && (errno == EINTR || errno == EAGAIN)) {
659                                 sleep(1);
660                                 continue;
661                         }
662                         if (r != (len-c)) {
663                                 ::pthread_mutex_unlock(&write_lock);
664                                 return c;
665                         }
666                         break;
667                 }
668                 c += r;
669         }
670         fsync(pin[1]);
671         ::pthread_mutex_unlock(&write_lock);
672         return c;
673 }
674
675 #endif // end UNIX process
676
677 #endif /* WITH_VIDEOTIMELINE */