Looking for a named IPC on macOS

Hello!

I am looking for a way for a process to publish some string system wide (or, preferably, user-session wide, if possible), so another process or processes could search for this string upon launch. What is important is that this string should disappear once the publishing process dies or gets killed.

I know there exist POSIX named semaphores (sem_open() ) and POSIX named shared memory segments (shmopen()), but both allow specifying a maximum of 31 bytes in their names. I need at least 255.


I was considering something like NSUserDefaults (or just regular files), but it is impossible to reliably clean them up upon process termination, which is essential.


Are there any other options available on macOS I could try?


It would be ideal, if this approach, apart from publishing a string that is accessible to other interested processes, also allowed sending messages between these processes, but this is not critical.


My main goal is to make a process and some of its configuration parameters discoverable by other instances of this process upon launch.


Thank you for answers!

Replies

It sounds like NSUserDefaults is what you want to use. It is reliable and guaranteed to work. If this architecture fails, virtually every Mac app in the world fails. That's Apple's problem to fix. If you come up with something funky based on ancient UNIX, it is quite likely to fail one day because of a change to the sandbox or some funky Apple security change. When that happens, you are the only one with a broken app. That's your problem to fix.


Your requirement to reliably clean up the resources upon process termination is impossible no matter what option you pick. If someone sends kill -9 to your app, it isn't going to clean anything up. The only guaranteed way to clean something up is to set a "running" flag somewhere, either in defaults or with a PID file, and then clean it up at the next launch of your process. You can do that regardless of how you implement your persistence.

Extending John's explanation, you can delete your user defaults values during controlled exit conditions (right before you exit, as part of signal handlers, exceptions handlers if you're using C++,Swift, trap handlers, atexit handlers, etc.. Extraordinary conditions like SIGKILLs are not going to be places where you'll have to have much luck intercepting the chain, and you'll need a recovery option similar to what John outlined above.


XPC is preferred solution for inter-process communication using Apple frameworks. Unix sockets and pipes are time-tested and likely to be supported indefinitely since they are pretty low-level.

It’s hard to answer this without knowing more about the runtime environment of the publisher and its clients. Are any of them distributed via the Mac App Store? Are any of them sandboxed?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hello Quinn,

No, they are neither sandboxed nor published at the AppStore.


These are the requirements:

1) upon its launch, an app must publish a string to some global namespace, so other instances of the app can detect whether they are ran with the same configuration.

2) upon termination, operating system must remove this string from the global namespace.


Thank you

Thanks for the reply John.

It is crucial that the string disappears once the app terminates in any way - either by getting a signal or a normal termination.

You have two options:


1) Have your app function as a server over a TCP or UNIX socket. The location of said socket can be stored in preferences. Any other app that wants to access the “string” will have ro connect to the service to retrieve it. If the app isn’t running, no string.


I guess there are more than two options, but they are all architecturally identical. You need a globally known address, such as a UNIX socket path, bonjour-published TCP server/port, or maybe a PID file. To access the value, you’ll have to make some query to pull it from the running app, or return an error if the app isn’t running. But it has to be some kind of active response from the app. The system isn’t going to help much. I guess the PID file is the closest to the system, but the app has to write the file to a known location.


You could also use a launchd task to get notified of when your other task is no longer running.

These are the requirements:

1) upon its launch, an app must publish a string to some global namespace

But, to be clear, you’re talking about a global namespace, right? Because earlier you wrote:

(or, preferably, user-session wide, if possible)

I’m presuming by “user-session wide” you’re referring to a GUI login session? That is, you’re not concerned about user programs running in a non-GUI login session, like an SSH login session.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"