LMMS
Loading...
Searching...
No Matches
ChildProcess.cpp
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the Water library.
5 Copyright (c) 2016 ROLI Ltd.
6 Copyright (C) 2017-2022 Filipe Coelho <falktx@falktx.com>
7
8 Permission is granted to use this software under the terms of the ISC license
9 http://www.isc.org/downloads/software-support-policy/isc-license/
10
11 Permission to use, copy, modify, and/or distribute this software for any
12 purpose with or without fee is hereby granted, provided that the above
13 copyright notice and this permission notice appear in all copies.
14
15 THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH REGARD
16 TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT,
18 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
19 USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21 OF THIS SOFTWARE.
22
23 ==============================================================================
24*/
25
26#include "ChildProcess.h"
27#include "../files/File.h"
28#include "../misc/Time.h"
29
30#ifdef CARLA_OS_MAC
31# include <crt_externs.h>
32# include <spawn.h>
33#endif
34
35#ifndef CARLA_OS_WIN
36# include <signal.h>
37# include <sys/wait.h>
38#endif
39
40#include "CarlaProcessUtils.hpp"
41
42namespace water {
43
44#ifdef CARLA_OS_WIN
45//=====================================================================================================================
47{
48public:
49 ActiveProcess (const String& command)
50 : ok (false)
51 {
52 STARTUPINFOA startupInfo;
53 carla_zeroStruct(startupInfo);
54 startupInfo.cb = sizeof (startupInfo);
55
56 ok = CreateProcessA (nullptr, const_cast<LPSTR>(command.toRawUTF8()),
57 nullptr, nullptr, TRUE, CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT,
58 nullptr, nullptr, &startupInfo, &processInfo) != FALSE;
59 }
60
62 {
63 closeProcessInfo();
64 }
65
66 void closeProcessInfo() noexcept
67 {
68 if (ok)
69 {
70 ok = false;
71 CloseHandle (processInfo.hThread);
72 CloseHandle (processInfo.hProcess);
73 }
74 }
75
77 {
78 return WaitForSingleObject (processInfo.hProcess, 0) != WAIT_OBJECT_0;
79 }
80
82 {
83 if (isRunning())
84 return true;
85
86 ok = false;
87 CloseHandle (processInfo.hThread);
88 CloseHandle (processInfo.hProcess);
89 return false;
90 }
91
93 {
94 return TerminateProcess (processInfo.hProcess, 0) != FALSE;
95 }
96
98 {
99 return TerminateProcess (processInfo.hProcess, 0) != FALSE;
100 }
101
103 {
104 DWORD exitCode = 0;
105 GetExitCodeProcess (processInfo.hProcess, &exitCode);
106 closeProcessInfo();
107 return (uint32) exitCode;
108 }
109
110 int getPID() const noexcept
111 {
112 return 0;
113 }
114
115 bool ok;
116
117private:
118 PROCESS_INFORMATION processInfo;
119
121};
122#else
124{
125public:
126 ActiveProcess (const StringArray& arguments, const Type type)
127 : childPID (0)
128 {
129 String exe (arguments[0].unquoted());
130
131 // Looks like you're trying to launch a non-existent exe or a folder (perhaps on OSX
132 // you're trying to launch the .app folder rather than the actual binary inside it?)
133 wassert (File::getCurrentWorkingDirectory().getChildFile (exe).existsAsFile()
134 || ! exe.containsChar (File::separator));
135
137 for (int i = 0; i < arguments.size(); ++i)
138 if (arguments[i].isNotEmpty())
139 argv.add (const_cast<char*> (arguments[i].toRawUTF8()));
140
141 argv.add (nullptr);
142
143#ifdef CARLA_OS_MAC
144 cpu_type_t pref;
145 pid_t result = -1;
146
147 switch (type)
148 {
149# ifdef __MAC_10_12
150 case TypeARM:
151 pref = CPU_TYPE_ARM64;
152 break;
153# endif
154 case TypeIntel:
155 pref = CPU_TYPE_X86_64;
156 break;
157 default:
158 pref = CPU_TYPE_ANY;
159 break;
160 }
161
162 posix_spawnattr_t attr;
163 posix_spawnattr_init(&attr);
164 // posix_spawnattr_setflags(&attr, POSIX_SPAWN_USEVFORK);
165 CARLA_SAFE_ASSERT_RETURN(posix_spawnattr_setbinpref_np(&attr, 1, &pref, nullptr) == 0,);
166 char*** const environptr = _NSGetEnviron();
168 argv.getRawDataPointer(), environptr != nullptr ? *environptr : nullptr) == 0,);
169 posix_spawnattr_destroy(&attr);
170#else
171 const pid_t result = vfork();
172#endif
173
174 if (result < 0)
175 {
176 // error
177 }
178#ifndef CARLA_OS_MAC
179 else if (result == 0)
180 {
181 // child process
182 carla_terminateProcessOnParentExit(true);
183
184 if (execvp (exe.toRawUTF8(), argv.getRawDataPointer()))
185 _exit (-1);
186 }
187#endif
188 else
189 {
190 // we're the parent process..
192 }
193
194#ifndef CARLA_OS_MAC
195 // unused
196 (void)type;
197#endif
198 }
199
204
206 {
207 if (childPID != 0)
208 {
209 int childState = 0;
210 const int pid = waitpid (childPID, &childState, WNOHANG|WUNTRACED);
211 return pid == 0 || ! (WIFEXITED (childState) || WIFSIGNALED (childState) || WIFSTOPPED (childState));
212 }
213
214 return false;
215 }
216
218 {
219 if (childPID != 0)
220 {
221 int childState = 0;
222 const int pid = waitpid (childPID, &childState, WNOHANG|WUNTRACED);
223 if (pid == 0)
224 return true;
225 if ( ! (WIFEXITED (childState) || WIFSIGNALED (childState) || WIFSTOPPED (childState)))
226 return true;
227
228 childPID = 0;
229 return false;
230 }
231
232 return false;
233 }
234
236 {
237 if (::kill (childPID, SIGKILL) == 0)
238 {
239 childPID = 0;
240 return true;
241 }
242
243 return false;
244 }
245
247 {
248 return ::kill (childPID, SIGTERM) == 0;
249 }
250
252 {
253 if (childPID != 0)
254 {
255 int childState = 0;
256 const int pid = waitpid (childPID, &childState, WNOHANG);
257 childPID = 0;
258
259 if (pid >= 0 && WIFEXITED (childState))
260 return WEXITSTATUS (childState);
261 }
262
263 return 0;
264 }
265
267 {
268 return childPID;
269 }
270
272
273private:
275};
276#endif
277
278//=====================================================================================================================
279
282
284{
285 return activeProcess != nullptr && activeProcess->isRunning();
286}
287
289{
290 return activeProcess == nullptr || activeProcess->killProcess();
291}
292
294{
295 return activeProcess == nullptr || activeProcess->terminateProcess();
296}
297
299{
300 return activeProcess != nullptr ? activeProcess->getExitCodeAndClearPID() : 0;
301}
302
303bool ChildProcess::waitForProcessToFinish (const int timeoutMs)
304{
305 const uint32 timeoutTime = Time::getMillisecondCounter() + (uint32) timeoutMs;
306
307 do
308 {
309 if (activeProcess == nullptr)
310 return true;
311 if (! activeProcess->checkRunningAndUnsetPID())
312 return true;
313
314 carla_msleep(5);
315 }
316 while (timeoutMs < 0 || Time::getMillisecondCounter() < timeoutTime);
317
318 return false;
319}
320
322{
323 return activeProcess != nullptr ? activeProcess->getPID() : 0;
324}
325
326//=====================================================================================================================
327
328#ifdef CARLA_OS_WIN
329bool ChildProcess::start (const String& command, Type)
330{
331 activeProcess = new ActiveProcess (command);
332
333 if (! activeProcess->ok)
334 activeProcess = nullptr;
335
336 return activeProcess != nullptr;
337}
338
339bool ChildProcess::start (const StringArray& args, const Type type)
340{
341 String escaped;
342
343 for (int i = 0, size = args.size(); i < size; ++i)
344 {
345 String arg (args[i]);
346
347 // If there are spaces, surround it with quotes. If there are quotes,
348 // replace them with \" so that CommandLineToArgv will correctly parse them.
349 if (arg.containsAnyOf ("\" "))
350 arg = arg.replace ("\"", "\\\"").quoted();
351
352 escaped << arg;
353
354 if (i+1 < size)
355 escaped << ' ';
356 }
357
358 return start (escaped.trim(), type);
359}
360#else
361bool ChildProcess::start (const String& command, const Type type)
362{
363 return start (StringArray::fromTokens (command, true), type);
364}
365
366bool ChildProcess::start (const StringArray& args, const Type type)
367{
368 if (args.size() == 0)
369 return false;
370
371 activeProcess = new ActiveProcess (args, type);
372
373 if (activeProcess->childPID == 0)
374 activeProcess = nullptr;
375
376 return activeProcess != nullptr;
377}
378#endif
379
380}
#define CARLA_SAFE_ASSERT_RETURN(cond, ret)
Definition CarlaDefines.h:190
#define CARLA_DECLARE_NON_COPYABLE(ClassName)
Definition CarlaDefines.h:242
#define CARLA_SAFE_ASSERT_INT(cond, value)
Definition CarlaDefines.h:183
#define noexcept
Definition DistrhoDefines.h:72
float arg(const fft_t *freqs, off_t x)
Definition OscilGen.cpp:58
CAdPlugDatabase::CRecord::RecordType type
Definition adplugdb.cpp:93
Definition StringArray.h:41
int size() const noexcept
Definition StringArray.h:97
Definition String.h:48
String trim() const
Definition String.cpp:1540
const char * toRawUTF8() const
Definition String.cpp:1925
Definition juce_posix_SharedCode.h:1119
int getPID() const noexcept
Definition juce_posix_SharedCode.h:1269
~ActiveProcess()
Definition juce_posix_SharedCode.h:1184
ActiveProcess(const StringArray &arguments, int streamFlags)
Definition juce_posix_SharedCode.h:1121
bool killProcess() const noexcept
Definition juce_posix_SharedCode.h:1244
bool isRunning() noexcept
Definition juce_posix_SharedCode.h:1193
bool ok
Definition juce_win32_Threads.cpp:497
PROCESS_INFORMATION processInfo
Definition juce_win32_Threads.cpp:501
int exitCode
Definition juce_posix_SharedCode.h:1276
Definition Array.h:57
bool isRunning() const noexcept
Definition ChildProcess.cpp:205
int getPID() const noexcept
Definition ChildProcess.cpp:266
int childPID
Definition ChildProcess.cpp:271
~ActiveProcess()
Definition ChildProcess.cpp:200
bool terminateProcess() const noexcept
Definition ChildProcess.cpp:246
bool killProcess() noexcept
Definition ChildProcess.cpp:235
ActiveProcess(const StringArray &arguments, const Type type)
Definition ChildProcess.cpp:126
bool checkRunningAndUnsetPID() noexcept
Definition ChildProcess.cpp:217
uint32 getExitCodeAndClearPID() noexcept
Definition ChildProcess.cpp:251
bool terminate()
Definition ChildProcess.cpp:293
uint32 getExitCodeAndClearPID()
Definition ChildProcess.cpp:298
ChildProcess()
Definition ChildProcess.cpp:280
Type
Definition ChildProcess.h:47
@ TypeARM
Definition ChildProcess.h:49
@ TypeIntel
Definition ChildProcess.h:50
bool start(const String &command, Type type=TypeAny)
Definition ChildProcess.cpp:361
bool waitForProcessToFinish(int timeoutMs)
Definition ChildProcess.cpp:303
~ChildProcess()
Definition ChildProcess.cpp:281
bool isRunning() const
Definition ChildProcess.cpp:283
uint32 getPID() const noexcept
Definition ChildProcess.cpp:321
bool kill()
Definition ChildProcess.cpp:288
CarlaScopedPointer< ActiveProcess > activeProcess
Definition ChildProcess.h:106
static const water_uchar separator
Definition File.h:691
static File getCurrentWorkingDirectory()
Definition File.cpp:1395
Definition StringArray.h:41
int size() const noexcept
Definition StringArray.h:97
static StringArray fromTokens(StringRef stringToTokenise, bool preserveQuotedStrings)
Definition StringArray.cpp:369
Definition String.h:48
bool containsChar(water_uchar character) const noexcept
Definition String.cpp:921
const char * toRawUTF8() const
Definition String.cpp:1925
register unsigned i
Definition inflate.c:1575
char * argv[]
Definition unzip.c:738
virtual ASIOError start()=0
CARLA_PLUGIN_EXPORT int posix_spawn(pid_t *, const char *, const posix_spawn_file_actions_t *, const posix_spawnattr_t *, char *const[], char *const[])
Definition interposer-safe.cpp:54
#define wassert(expression)
uint32 getMillisecondCounter() noexcept
Definition Time.cpp:117
Definition AudioSampleBuffer.h:33
unsigned int uint32
Definition water.h:98
#define false
Definition ordinals.h:83
#define WAIT_OBJECT_0
char * LPSTR
Definition swell-types.h:189
unsigned int DWORD
Definition swell-types.h:164
DWORD WaitForSingleObject(HANDLE hand, DWORD msTO)
Definition swell.cpp:297
BOOL CloseHandle(HANDLE hand)
Definition swell.cpp:157
ulg size
Definition extract.c:2350
int result
Definition process.c:1455
#define void
Definition unzip.h:396
#define TRUE
Definition unzpriv.h:1295
#define FALSE
Definition unzpriv.h:1298
#define const
Definition zconf.h:137