Do work out of process in a cocoa app? - cocoa

I've got a cocoa app that needs to do some work in a second process (because it might crash due to buggy libraries). I'd like to keep my project as simple as possible, so ideally I would use the same binary as the parent process and just control the child with command line parameters. It would also be nice if the parent could get handles to the new process's stdin & stdout so that they can communicate (although something I create with pipe() would work too). Has anyone solved this problem before? What did you learn? I come from a Win32/Linux background, so I'm not sure if there are any special capabilities I get with Cocoa/OS X that I should be using.

I'd like to keep my project as simple as possible, so ideally I would use the same binary as the parent process and just control the child with command line parameters.
fork and exec work the same on Mac OS X as on Linux and other POSIX environments, with one catch: In a Cocoa app, you can't just fork and not exec, because Core Foundation will not allow you to use any CF- or Cocoa-based APIs in the new process. If you fork in a Cocoa app, you must exec pretty much immediately afterward.
You can exec the same binary by using your own argv[0] in the [0] of the argv that you pass to exec.
There is a Cocoa version of fork+exec: Create an NSTask and set its launch path to your own [[[NSProcessInfo processInfo] arguments] objectAtIndex:0]. There is no way to fork and not exec with NSTask, for the above reason.
It would also be nice if the parent could get handles to the new process's stdin & stdout so that they can communicate (although something I create with pipe() would work too).
pipe also works as you would expect.
If you use NSTask, the Cocoa version of pipe is [NSPipe pipe].

Related

freopen() on OSX 10.10.3

I have a C program which spawns a pthread to act as an interactive terminal: reading lines from stdin & acting upon them. The program acts as a kind of shell, fork-ing off processes; each process so created has its stdin re-directed using a call to freopen() before using exec to load the new executable.
Before the interactive thread is started, all works fine. Once it has started (or, more specifically, whenever it is waiting for input), calls to freopen() hang. Is there some way to avoid this problem?
The solution that is working for me can be found in R.'s answer to Is close/fclose on stdin guaranteed to be correct?
Basically, the idea is to open the file you want to redirect to, duplicate that to stdin, and then close the file description just opened.

Launching an application from another process

We have an application that we have built as a bundle and we want to launch it from another process.
How should we do it?
From what I understand we can use openUrls(), openFile() or execve()
but I don't know which one better suits us.
Thanks
Since you're talking about an application, you don't want to go through the file association mechanisms. They're for opening documents, images etc. with an appropriate application. Since you don't seem to be sure what to ask, I'd say keep it simple:
The exec* family launches an executable directly. But note that it replaces the launching process with the launched application. Your launcher will stop executing at that point. If you want the launcher to continue to run, you want to use something that launches a subprocess. The low-level way is fork/vfork followed by exec, but it's far simpler to launch your app with system, which takes care of all that behind the scenes. (Assuming there are no security concerns about users on the other side of the world injecting execution paths).
If the launcher does not terminate as soon as it launches your app, you'll want to think about whether it "blocks" until the launched application terminates, or whether it launches the app asynchronously-- so that they then run in parallel. The launcher might also "wait" for the return value of the app, to check whether it succeeded and maybe do something afterwards. There are ways to do all that, but since we don't know what you need, I won't go into details.
In short: If the only job of your launcher is to start your app, use execl. If your launcher needs to do more, use system. If neither one quite fits your needs, you'll need to provide more information-- starting with the language your launcher is written in.
PS. Both of these have the advantage of generality and portability. They work for GUI and commandline applications, and they'll work on any Unix-like system, and to some extent on Windows. There's no need to lock yourself into Cocoa for something so simple.
If you're using Cocoa, you can use NSWorkspace's -launchApplication:.
From OSX documentation on NSWorkspaces:
openFile: Opens the specified file specified using the default application associated with its type.
openURL: Opens the location at the specified URL.
With url you can open also file on ftp, or http for example.

How can i execute a shell script and close my app in cocoa

I would like to run a shell script from my cocoa app when clicking on a button. I can easily use the system() call to do that, but that's not all i need. I need the app to close as soon as it calls the script, or even before it calls the script. Basically the script should take a few seconds to run so i need the app to close by that time. The reason i need this is because i'm writing a simple application that puts the mac to sleep, but before that it does lots of cleaning up via a shell script and i basically don't want this app to be open when i brind the system back from sleep.
Would using a fork or something like that do the job or do i need some special magic to do this?
Thank you
If you're in Cocoa, you'll want to use NSTask. If your script needs admin privileges, there's always STPrivilegedTask.
You can use popen() instead of system(). The init process should inherit ownership of the script you run once your application exits. You could also fork/exec, but popen will be simpler as its semantics are much closer to that of system().

Can Xcode open an application without fork?

My question is just that. Is there a command in Xcode that uses a process other than fork?
There are other APIs to launch applications, but they all ultimately rely on fork()/exec(). There's no other way on UNIX to start a new process from userland than forking an existing process. You can install another task as a launchd job, then launch it by satisfying its start conditions - that doesn't directly use fork() (though of course it causes launchd to fork).

fork within Cocoa application

My problem is not the best scenario for fork(). However, this is the best func I can get.
I am working on a Firefox plugin on Mac OSX. To make it robust, I need to create a new process to run my plugin. The problem is, when I forked a new process, much like this:
if (fork() == 0) exit(other_main());
However, since the state is not cleaned, I cannot properly initialized my new process (call NSApplicationLoad etc.). Any ideas? BTW, I certainly don't want create a new binary and exec it.
In general, you need to exec() after fork() on Mac OS X.
From the fork(2) man page:
There are limits to what you can do in the child process. To be totally safe you should restrict your-self to only executing async-signal safe operations until such time as one of the exec functions is called. All APIs, including global data symbols, in any framework or library should be assumed to be unsafe after a fork() unless explicitly documented to be safe or async-signal safe. If you need to use these frameworks in the child process, you must exec. In this situation it is reasonable to exec yourself.
TN2083 also comments on this subject:
Many Mac OS X frameworks do not work reliably if you call fork but do not call exec. The only exception is the System framework and, even there, the POSIX standard places severe constraints on what you can do between a fork and an exec.
IMPORTANT: In fact, in Mac OS X 10.5 and later, Core Foundation will detect this situation and print the warning message shown in Listing 13.
Listing 13: Core Foundation complaining about fork-without-exec
The process has forked and you cannot use this CoreFoundation functionality safely. You MUST exec().
Break on __THE_PROCESS_HAS_FORKED_AND_YOU_CANNOT_USE_THIS_COREFOUNDATION_FUNCTIONALITY___YOU_MUST_EXEC__() to debug.
fork without exec is basically entirely unsafe on OSX. You will end up with stale mach ports for example.
I'm writing the FreeWRL plugin for Firefox (Linux at the moment, Mac & Windows soon).
http://freewrl.sourceforge.net/
It's based on fork+exec to launch FreeWRL and swallow its window into Firefox.
You'll have to use a pipe to correctly handle the possible failure of fork+exec or the failure of your child process :
How to handle execvp(...) errors after fork()?
Cheers,
C

Resources