Vuo  2.3.2
VuoRuntime.cc
Go to the documentation of this file.
1 
10 #include <getopt.h>
11 #include <mach-o/dyld.h> // for _NSGetExecutablePath()
12 #include <dirent.h>
13 #include <dlfcn.h>
14 
15 #include "VuoApp.h"
16 #include "VuoEventLoop.h"
17 #include "VuoException.hh"
18 #include "VuoRuntime.h"
21 #include "VuoRuntimeState.hh"
22 #include "module.h"
23 
24 extern "C"
25 {
26 
27 static VuoRuntimeState *runtimeState = NULL;
28 void *vuoRuntimeState = NULL;
29 
33 void vuoInit(int argc, char **argv)
34 {
35  bool doAppInit = false;
36  char *controlURL = NULL;
37  char *telemetryURL = NULL;
38  bool isPaused = false;
39  pid_t runnerPid = 0;
40  int runnerPipe = -1;
41  bool continueIfRunnerDies = false;
42  bool doPrintHelp = false;
43  bool doPrintLicenses = false;
44 
45  // parse commandline arguments
46  {
47  int getoptArgC = 0;
48  char **getoptArgV = (char **)malloc(sizeof(char *) * argc);
49  for(int i = 0; i < argc; ++i)
50  {
51  // Don't pass the OS X Process Serial Number argument to getopt, since it can't handle long arguments with a single hyphen.
52  if (strncmp(argv[i], "-psn_", 5) == 0)
53  {
54  // Since we have a process serial number, we can assume this is an exported app being invoked by LaunchServices.
55  // Therefore we need to initialize the app (so it shows up in the dock).
56  doAppInit = true;
57  continue;
58  }
59 
60  getoptArgV[getoptArgC++] = argv[i];
61  }
62 
63  static struct option options[] = {
64  {"help", no_argument, NULL, 0},
65  {"vuo-control", required_argument, NULL, 0},
66  {"vuo-telemetry", required_argument, NULL, 0},
67  {"vuo-pause", no_argument, NULL, 0},
68  {"vuo-loader", required_argument, NULL, 0},
69  {"vuo-runner-pipe", required_argument, NULL, 0},
70  {"vuo-continue-if-runner-dies", no_argument, NULL, 0},
71  {"vuo-licenses", no_argument, NULL, 0},
72  {"vuo-runner-pid", required_argument, NULL, 0},
73  {NULL, no_argument, NULL, 0}
74  };
75  int optionIndex=-1;
76  int ret;
77  while ((ret = getopt_long(getoptArgC, getoptArgV, "", options, &optionIndex)) != -1)
78  {
79  if (ret == '?')
80  continue;
81 
82  switch(optionIndex)
83  {
84  case 0: // --help
85  doPrintHelp = true;
86  break;
87  case 1: // --vuo-control
88  if (controlURL)
89  free(controlURL);
90  controlURL = strdup(optarg);
91  break;
92  case 2: // --vuo-telemetry
93  if (telemetryURL)
94  free(telemetryURL);
95  telemetryURL = strdup(optarg);
96  break;
97  case 3: // --vuo-pause
98  isPaused = true;
99  break;
100  case 4: // --vuo-loader (ignored, but added here to avoid "unrecognized option" warning)
101  break;
102  case 5: // --vuo-runner-pipe
103  runnerPipe = atoi(optarg);
104  break;
105  case 6: // --vuo-continue-if-runner-dies
106  continueIfRunnerDies = true;
107  break;
108  case 7: // --vuo-licenses
109  doPrintLicenses = true;
110  break;
111  case 8: // --vuo-runner-pid
112  runnerPid = atoi(optarg);
113  break;
114  default:
115  VUserLog("Error: Unknown option %d.", optionIndex);
116  break;
117  }
118  }
119  free(getoptArgV);
120  }
121 
122  // macOS 10.14 no longer provides the `-psn_` argument, so use an alternate method to detect LaunchServices.
123  // launchd is pid 1.
124  if (!doAppInit && !controlURL && getppid() == 1)
125  doAppInit = true;
126 
127  // Get the exported executable path.
128  char rawExecutablePath[PATH_MAX+1];
129  uint32_t size = sizeof(rawExecutablePath);
130  _NSGetExecutablePath(rawExecutablePath, &size);
131 
132  if (doPrintHelp)
133  {
134  printf("Usage: %s [options]\n"
135  "Options:\n"
136  " --help Display this information.\n"
137  " --vuo-licenses Display license information.\n",
138  argv[0]);
139 
140  exit(0);
141  }
142  else if (doPrintLicenses)
143  {
144  printf("This composition may include software licensed under the following terms:\n\n");
145 
146  // Derive the path of the app bundle's "Licenses" directory from its executable path.
147  char licensesPath[PATH_MAX+1];
148  licensesPath[0] = 0;
149  if (strlen(VuoGetFrameworkPath()))
150  {
151  strncpy(licensesPath, VuoGetFrameworkPath(), PATH_MAX);
152  strncat(licensesPath, "/Vuo.framework/Versions/" VUO_FRAMEWORK_VERSION_STRING "/Documentation/Licenses", PATH_MAX);
153  }
154  else if (strlen(VuoGetRunnerFrameworkPath()))
155  {
156  strncpy(licensesPath, VuoGetRunnerFrameworkPath(), PATH_MAX);
157  strncat(licensesPath, "/VuoRunner.framework/Versions/" VUO_FRAMEWORK_VERSION_STRING "/Documentation/Licenses", PATH_MAX);
158  }
159 
160  bool foundLicenses = false;
161  if (licensesPath[0] && access(licensesPath, 0) == 0)
162  {
163  DIR *dirp = opendir(licensesPath);
164  struct dirent *dp;
165  while ((dp = readdir(dirp)) != NULL)
166  {
167  if (dp->d_name[0] == '.')
168  continue;
169 
170  printf("=== %s =====================================================\n\n",dp->d_name);
171 
172  size_t pathSize = strlen(licensesPath) + dp->d_namlen + 2;
173  char licensePath[pathSize];
174  strlcpy(licensePath, licensesPath, pathSize);
175  strlcat(licensePath, "/", pathSize);
176  strlcat(licensePath, dp->d_name, pathSize);
177 
178  int fd = open(licensePath, O_RDONLY);
179  char data[1024];
180  int bytesRead;
181  while((bytesRead = read(fd, data, 1024)) > 0)
182  write(1, data, bytesRead);
183  close(fd);
184 
185  printf("\n\n\n");
186  foundLicenses = true;
187  }
188  closedir(dirp);
189  }
190 
191  if (!foundLicenses)
192  printf("(No license information found.)\n");
193 
194  free(controlURL);
195  free(telemetryURL);
196  exit(0);
197  }
198 
199  void *executableHandle = dlopen(rawExecutablePath, 0);
200  if (! executableHandle)
201  {
202  VUserLog("The composition couldn't be started because a handle to the executable couldn't be obtained : %s", dlerror());
203  free(controlURL);
204  free(telemetryURL);
205  return;
206  }
207 
209  executableHandle, NULL, doAppInit);
210 
211  dlclose(executableHandle);
212 
213  free(controlURL);
214  free(telemetryURL);
215 }
216 
235 void vuoInitInProcess(void *ZMQContext, const char *controlURL, const char *telemetryURL, bool isPaused, pid_t runnerPid,
236  int runnerPipe, bool continueIfRunnerDies, const char *workingDirectory,
237  void *compositionBinaryHandle, void *previousRuntimeState, bool doAppInit)
238 {
239  runtimeState = (VuoRuntimeState *)previousRuntimeState;
240  if (! runtimeState)
241  {
247  }
248 
249  vuoRuntimeState = (void *)runtimeState;
250 
251  VuoCompositionState *compositionState = new VuoCompositionState;
252  compositionState->runtimeState = runtimeState;
253  compositionState->compositionIdentifier = "";
255 
256  try
257  {
259  workingDirectory, compositionBinaryHandle);
260  }
261  catch (VuoException &e)
262  {
263  VUserLog("%s", e.what());
264  return;
265  }
266 
267  if (doAppInit)
268  {
269  typedef void (*vuoAppInitType)(bool requiresDockIcon);
270  vuoAppInitType vuoAppInit = (vuoAppInitType) dlsym(RTLD_SELF, "VuoApp_init");
271  if (vuoAppInit)
272  vuoAppInit(true);
273  }
274 
276 
277  // If the composition had a pending call to vuoStopComposition() when it was stopped, call it again.
280 
282 }
283 
291 void * vuoFini(void)
292 {
293  runtimeState->fini();
294  return (void *)runtimeState;
295 }
296 
301 {
302  delete (VuoRuntimeState *)runtimeState;
303 }
304 
308 typedef void (*VuoCompositionFiniCallback)(void);
309 
315 {
316  VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
317  if (r)
319  else
321 }
322 
327 pid_t vuoGetRunnerPid(VuoCompositionState *compositionState)
328 {
329  VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
330  if (r)
331  return r->getRunnerPid();
332  else
333  return -1;
334 }
335 
341 {
342  VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
343  if (r)
345 }
346 
352 {
353  VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
354  if (r)
356 }
357 
363 {
364  VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
365  if (r)
366  r->disableTermination();
367 }
368 
374 {
375  VuoRuntimeState *r = (compositionState ? (VuoRuntimeState *)compositionState->runtimeState : runtimeState);
376  if (r)
377  r->enableTermination();
378 }
379 
386 {
387  return runtimeState->isStopped();
388 }
389 
390 } // extern "C"