15#include <CoreFoundation/CoreFoundation.h>
49 void *compositionBinaryHandle)
58 hasBeenUnpaused =
false;
60 wasStopCompositionCalled =
false;
65 terminationDisabledCount = 0;
66 terminationDisabledQueue = dispatch_queue_create(
"org.vuo.runtime.terminationDisabled", NULL);
68 stopQueue = dispatch_queue_create(
"org.vuo.runtime.stop", NULL);
70 waitForStopTimer = NULL;
71 waitForStopCanceledSemaphore = NULL;
75 vuoInstanceInit = NULL;
76 vuoInstanceFini = NULL;
77 vuoInstanceTriggerStart = NULL;
78 vuoInstanceTriggerStop = NULL;
95 dispatch_source_cancel(waitForStopTimer);
96 dispatch_semaphore_wait(waitForStopCanceledSemaphore, DISPATCH_TIME_FOREVER);
97 dispatch_release(waitForStopTimer);
98 dispatch_release(waitForStopCanceledSemaphore);
103 dispatch_release(stopQueue);
113 ostringstream errorMessage;
115 vuoSetup = (vuoSetupType) dlsym(compositionBinaryHandle,
"vuoSetup");
118 errorMessage <<
"The composition couldn't be started because its vuoSetup() function couldn't be found : " << dlerror();
122 vuoCleanup = (vuoCleanupType) dlsym(compositionBinaryHandle,
"vuoCleanup");
125 errorMessage <<
"The composition couldn't be started because its vuoCleanup() function couldn't be found : " << dlerror();
129 vuoInstanceInit = (vuoInstanceInitType) dlsym(compositionBinaryHandle,
"vuoInstanceInit");
130 if (! vuoInstanceInit)
132 errorMessage <<
"The composition couldn't be started because its vuoInstanceInit() function couldn't be found : " << dlerror();
136 vuoInstanceFini = (vuoInstanceFiniType) dlsym(compositionBinaryHandle,
"vuoInstanceFini");
137 if (! vuoInstanceFini)
139 errorMessage <<
"The composition couldn't be started because its vuoInstanceFini() function couldn't be found : " << dlerror();
143 vuoInstanceTriggerStart = (vuoInstanceTriggerStartType) dlsym(compositionBinaryHandle,
"vuoInstanceTriggerStart");
144 if (! vuoInstanceTriggerStart)
146 errorMessage <<
"The composition couldn't be started because its vuoInstanceTriggerStart() function couldn't be found : " << dlerror();
150 vuoInstanceTriggerStop = (vuoInstanceTriggerStopType) dlsym(compositionBinaryHandle,
"vuoInstanceTriggerStop");
151 if (! vuoInstanceTriggerStop)
153 errorMessage <<
"The composition couldn't be started because its vuoInstanceTriggerStop() function couldn't be found : " << dlerror();
188bool VuoRuntimeState::isRunnerInCurrentProcess(
void)
190 return runnerPid == getpid();
196bool VuoRuntimeState::mayBeTerminated(
void)
199 dispatch_sync(terminationDisabledQueue, ^{
200 ret = (terminationDisabledCount == 0);
214 dispatch_sync(terminationDisabledQueue, ^{
215 ++terminationDisabledCount;
224 dispatch_sync(terminationDisabledQueue, ^{
225 --terminationDisabledCount;
226 if (terminationDisabledCount < 0)
227 terminationDisabledCount = 0;
247 hasBeenUnpaused =
true;
248 __block
bool initDone =
false;
249 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
251 vuoInstanceTriggerStart();
262 if (! continueIfRunnerDies)
272 vuoInstanceTriggerStop();
282 if (! hasBeenUnpaused)
284 hasBeenUnpaused =
true;
287 vuoInstanceTriggerStart();
296 if (! isBeingReplaced)
301 stopComposition(isBeingReplaced, timeoutInSeconds);
303 if (timeoutInSeconds >= 0)
306 dispatch_sync(dispatch_get_main_queue(), ^{
332 if (persistentState->communicator->hasZmqConnection())
334 persistentState->communicator->sendStopRequested();
337 waitForStopTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, persistentState->communicator->getControlQueue());
338 dispatch_source_set_timer(waitForStopTimer, dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 2.), NSEC_PER_SEC * 2, NSEC_PER_SEC/10);
339 waitForStopCanceledSemaphore = dispatch_semaphore_create(0);
341 dispatch_source_set_event_handler(waitForStopTimer, ^{
342 stopComposition(false, 5);
343 dispatch_source_cancel(waitForStopTimer);
346 dispatch_source_set_cancel_handler(waitForStopTimer, ^{
347 dispatch_semaphore_signal(waitForStopCanceledSemaphore);
350 dispatch_resume(waitForStopTimer);
354 stopComposition(false, 5);
358 persistentState->communicator->interruptListeningForControl();
370void VuoRuntimeState::stopComposition(
bool isBeingReplaced,
int timeoutInSeconds)
372 dispatch_retain(stopQueue);
374 dispatch_sync(stopQueue, ^{
378 if (wasStopCompositionCalled)
380 wasStopCompositionCalled =
true;
382 killProcessAfterTimeout(timeoutInSeconds);
384 dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
390 vuoInstanceTriggerStop();
397 if (! isBeingReplaced && ! isRunnerInCurrentProcess())
403 typedef void (*VuoImageRendererFiniType)(void);
404 VuoImageRendererFiniType vuoImageRendererFini = (VuoImageRendererFiniType) dlsym(RTLD_DEFAULT,
"VuoImageRenderer_fini");
405 if (vuoImageRendererFini)
406 vuoImageRendererFini();
409 typedef void (*VuoImageTextCacheFiniType)(void);
410 VuoImageTextCacheFiniType vuoImageTextCacheFini = (VuoImageTextCacheFiniType) dlsym(RTLD_DEFAULT,
"VuoImageTextCache_fini");
411 if (vuoImageTextCacheFini)
412 vuoImageTextCacheFini();
415 typedef void (*VuoAppFiniType)(void);
416 VuoAppFiniType vuoAppFini = (VuoAppFiniType) dlsym(RTLD_DEFAULT,
"VuoApp_fini");
433 dispatch_release(stopQueue);
450void VuoRuntimeState::killProcessAfterTimeout(
int timeoutInSeconds)
452 if (timeoutInSeconds < 0)
455 if (isRunnerInCurrentProcess())
460 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, timeoutInSeconds * NSEC_PER_SEC),
461 dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
465 dispatch_source_t backupTimer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, DISPATCH_TIMER_STRICT, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0));
466 dispatch_source_set_timer(backupTimer, dispatch_time(DISPATCH_TIME_NOW, timeoutInSeconds * NSEC_PER_SEC), timeoutInSeconds * NSEC_PER_SEC, NSEC_PER_SEC/10);
467 dispatch_source_set_event_handler(backupTimer, ^{
468 if (mayBeTerminated())
471 VUserLog(
"Warning: Waited %d seconds for the composition to cleanly shut down, but it's still running. Now I'm force-quitting it.", timeoutInSeconds * 2);
472 kill(getpid(), SIGKILL);
475 dispatch_resume(backupTimer);
477 __block
bool eventLoopMayBeTerminated;
478 std::mutex *mainMutex =
new std::mutex;
480 CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopCommonModes, ^{
484 CFRunLoopWakeUp(CFRunLoopGetMain());
490 if (mayBeTerminated() && eventLoopMayBeTerminated)
493 VUserLog(
"Warning: Waited %d seconds for the composition to cleanly shut down, but it's still running. Now I'm force-quitting it.", timeoutInSeconds);
494 kill(getpid(), SIGKILL);
497 dispatch_source_cancel(backupTimer);
498 dispatch_release(backupTimer);