Handling SIGABRT in Mac Apps - macos

I have created a very simple Desktop app for Mac OS. Due to restrictions, I could not use xcode. I am building the .app directory by hand, and the main executable at the moment is a shell script.
When I was trying my app out, I noticed that if I opened and closed it too quickly, the app would freeze up. At which point, I seemed unable to even force quit it, and had to rm -r the .app itself. A friend mentioned to me, that mac apps must handle SIGABRTs, and if they do not, there is a timeout period where the app could appear as frozen, which might explain what I observed.
I was looking around but uncertain where to find more information about this. Can anyone further explain this situation? Under what circumstances will the app receive a SIGABRT, and how should it be handled? Any links or literature on this topic, would be very appreciated.

In case anyone ever stumbles upon this:
So my friend was referring to Unix signals here. https://people.cs.pitt.edu/~alanjawi/cs449/code/shell/UnixSignals.htm
(to see what is available on your OS, give 'kill -l')
My main executable, in my MyApp.app/Contents/MacOS, is a shell script. So what I've found I can do, is use trap command. This will give a behavior to perform, if the executable receives one of the signals. Example - I now add this line near the top of my shell script:
trap 'exit' 5 6
This means that if the executable receives with a SIGABRT (6) or a SIGTRAP (5) signal, it will perform the command 'exit' and will exit. (I am not certain which all signals should be handled and what is the best course, I guess that might depend on your own app, but that was just as an example of something to do)
Here is a resource about trap commands and unix signals: https://www.tutorialspoint.com/unix/unix-signals-traps.htm
Why does this make a difference - I believe previously, there were scenarios where for example if I opened the app while it was already open, it was receiving a Unix signal like a SIGABRT. This signal was not being handled and the app did not know what to do in that scenario, and was freezing up. Though I have not confirmed this is what was happening.

Related

Run function when Mac machine wakes

I'm looking for a function which will get called when a macOS machine wakes up from sleep.
What are some ways to achieve this?
I'm looking to run code in my Swift application when the computer awakens. I'm trying to open a new websocket when this happens. If I open the lid -> new websocket, if I press the any key -> new websocket.
What I've found useful so far is this which stems from what #Rob Napier has suggested (didWakeNotification)
You'll need to give more information than this. Is this an user-level (GUI?) application that will be running when the machine goes to sleep? Is this a daemon? Do you expect your program to be launched if it isn't already running? Is the program sandboxed? Do you expect to have root access? What if no one is logged in? "Wakes up from sleep" has many subtle corner cases (for example, it includes a "dark wake" mode which are not quite sleep and not quite wake).
That said, the high-level answer is "observe NSWorkspace.didWakeNotification" and the low-level answer is "call IORegisterForSystemPower." But whether either of those help you depends a lot on what problem you're solving.

How to daemonize non-privileged script in OSX Yosemite 10.10.3+

For years we've had a process-monitoring/control script as part of our application. The default behavior of the script is to daemonize itself. Often the script is launched, of necessity, by non-privileged users. For reasons I'll not elaborate, we need to keep both the script and this behavior.
On OSX systems, we have traditionally had the script restart itself in the background via the /usr/libexec/StartupItemContext launch script provided by Apple. This puts our process in the Mach StartupItem bootstrap context rather than the login bootstrap context. This is necessary because without that context switch, if and when the user logs out, which is also often necessary, the script loses access to directory services, getpwuid(), DNS services, etc. The original internal lines that daemonized the script looked essentially like this (in perl):
my $cmd = "/usr/libexec/StartupItemContext myscript #Commandline > logs/startup 2>&1" ;
system( "$cmd &") ;
exit 0 ;
When OSX Yosemite came out, that StartupItemContext script disappeared, so we switched to direct invocation of launchctl:
my $cmd = "/usr/launchctl bsexec / myscript #Commandline > logs/startup 2>&1" ;
system( "$cmd &") ;
exit 0 ;
With the recent OSX 10.10.3 upgrade, however, the bsexec subcommand of launchctl suddenly requires root privileges:
% launchctl bsexec
This subcommand requires root privileges: bsexec
%
This creates for us the showstopper problem that non-privileged users can no longer get our monitoring/control script to daemonize itself.
It seems that Glassfish has encountered this problem and addressed it with a patch that replaces
/bin/launchctl bsexec /
with
nohup
This may work for the Glassfish implementation, however I don't think for us. Notwithstanding the fact that I don't understand it -- i.e. why a simple blocking of SIGHUP would prevent a process in decommissioned login bootstrap context from losing services -- it also doesn't seem to work in our tests for all system services we need.
What is the new, canonical way to daemonize a process on OSX starting from a non-privileged, Mach "login" bootstrap context, without losing access to critical system services like DNS etc. when the user logs out?
"from a non-privileged, Mach "login" bootstrap context" unfortunately is very unlikely to have a "canonical way." The only canonical way is to launch services on demand via launchd. Even "bsexec" is barely supported and hardly documented. In my experience, it isn't possible to keep up with OS X changes and never redesign your launch systems. I redesign the daemon system about every other release because Apple breaks it, and they're going to keep breaking it. The only answer is to keep trying to make your requirements simpler. But pretty much any process that wants to run all the time, rather than on demand, is in direct violation of Apple's stated intent, so it's going to tend to break.
The solution given by Apple is to create a LaunchDaemon and assign it a UserName in your launchd plist. You must start privileged, and then switch to the user (and it needs to be a fixed user, not "the logged in user" since that would be a LaunchAgent). You can't upgrade your access this way. You must not daemonize yourself (again, the canonical answer is: don't do that. See the launchd.plist man page.)
I suspect the Glassfish nohup solution is just a dodge that doesn't actually put them in the Mach context. They're just trying to avoid being killed when the parent shell exits. That probably won't help you.
In my experience, the most robust solutions are multi-part. You wind up with one piece that is run as a system LaunchDaemon (with KeepAlive), and another piece that is a user LaunchAgent, and you let them communicate over IPC so that you can access the context you need for each activity you need to do. Yes, this is typically much more complicated to implement. Simpler solutions tend not to work.
And of course you have to constantly ask yourself "is there any way I could achieve this by doing things the way Apple wants me to." That means XPC is strongly preferred, followed by on-demand LaunchDaemons and LaunchAgents. If you build your system to use XPC components, you'll likely survive more OS X upgrades. Any work around you figure out that doesn't use these pieces will probably have to be fixed again in 10.11.

Automatically force quit frozen applications in OSX maybe using a ruby script?

I built an application using openframeworks that is live 24/7 on a kiosk. Every now and then (every few weeks) it will randomly go unresponsive and I still can't get to the bottom of it because it's so random and infrequent it is hard to debug.
I wrote a ruby script that looks for the application running and if it doesn't exist it will start it up. This works in all cases where the application name doesn't show up in activity monitor. Meaning if the app crashes and completely force quits itself or something. It works just fine.
However, if the app just freezes and goes unresponsive (red highlight in activity monitor) the app doesn't quit out completely unless I force quit manually. Is there some kind of script I can write to look for all "unresponsive apps/processes" every few seconds and force quits them automatically? That way my app launcher script will be able to detect that the app isn't running and boot it up again.
I suggest you look at Monit because it's solid, well tested, well documented, and easy to learn.
If you still want to write your own monitoring script, Monit is a good example to follow.
The most reliable way to detect an unresponsive app is to have a "vital sign" which is a generic term for a signal that an app emit to prove it's healthy. Some people call this a "pulse" or "heartbeat" or "brainwave". Your external script watches the vital sign. If your external script sees the vital sign flatline, then the script takes action to cure the app or restart it.
An alternate way is to have a "ping" which is a generic term for your external script sending a signal to the app or the system, then listening for a reply. You can use tools such as the Unix ps command for processes, or AppleScript Activity Monitor. As far as I know, these do a pretty good job of catching common cases, but have trouble catching apps that are soaking up resources, such as being caught in endless loops.

Cocoa program can't be stopped

I'm trying to write an OS X app that uses a serial port. I found an example (cocoa) and got it running in Xcode 4. On the first run, it opens the port and I'm able to exchange data with the hardware.
If I try to change the port the program goes rogue. The pinwheel starts and the UI is unresponsive. I can't stop the program from Xcode, nor can I kill it from Terminal, or Force Quit. Force Quit of Xcode doesn't do it. Although the PID goes away with a kill from Terminal, the UI is still present with the merrily spinning pinwheel.
The only way out is a re-boot. Any ideas on how to track down the errant code are welcome. I'm new to Cocoa/Objective C, so simple terms are better.
Most likely it became a zombie. It should show up in ps auxww (or similar) with a 'Z' in its status. Activity Monitor might also still show it.
This is relatively common when working with hardware, such as a serial port. Zombies can arise for either of two reasons, most likely the first in this case:
The process is blocked in a kernel call of some kind, that's not interruptible.
The process has exited but its parent hasn't acknowledged that (via wait() or similar).
In the first case it's usually a fundamental bug or design flaw of some kind, and you may not have any good options short of figuring out exactly what code path tickles the problem, and avoiding that.
In the second case the solution is generally simple - find the parent process of your zombie and kill it. Repeat as necessary until your zombie gets adopted by a parent process that does call wait() to reap it (launchd will do this if nothing else).

How to handle abnormal program termination in Perl on Windows

I have a Perl program on Windows that needs to execute cleanup actions on exit. I wrote a signal handler using sigtrap, but it doesn't always work. I can intercept Ctrl-C, but if the machine is rebooted or the program is killed some other way, neither the signal handler nor the END block are run. I've read that Windows doesn't really have signals, and signal handling on windows is sort of a hack in Perl. My question is, how can I handle abnormal termination the Windows way? I want to run my cleanup code regardless of how or why the program terminates (excluding events that can't be caught). I've read that Windows uses events instead of signals, but I can't find information on how to deal with Windows events in Perl.
Unfortunately, I don't have the authority to install modules from CPAN, so I'll have to use vanilla ActiveState Perl. And to make things even more interesting, most of the machines I'm using only have Perl 5.6.1.
Edit: I would appreciate any answers, even if they require CPAN modules or newer versions of Perl. I want to learn about Windows event handling in Perl, and any information would be welcome.
In all operating systems, you can always abruptly terminate any program. Think of kill -9 command in Unix/Linux. You do that on any program, and it stops instantly. No way to trap it. No way for the program to request a few more operating system cycles for a clean up.
I'm not up on the difference between Unix and Windows signals, but you can imagine why each OS must allow what we call in Unix SIGKILL - a sure and immediate way to kill any program.
Imagine you have a buggy program that intercepts a request to terminate (a SIGTERM in Unix), and it enters a cleanup phase. Instead of cleaning up, the program instead gets stuck in a loop that requests more and more memory. If you couldn't pull the SIGKILL emergency cord, you'd be stuck.
The ultimate SIGKILL, of course is the plug in the wall. Pull it, and the program (along with everything else) comes to a screeching halt. There's no way your program can say "Hmm... the power is out and the machines has stopped running... Better start up the old cleanup routine!"
So, there's no way you can trap every program termination signal, and, your program will have to account for that. What you can do is see if your program needs to do a cleanup before running. On Windows, you can put an entry in the registry when your program starts up, and remove it when it shuts down and does a cleanup. In Unix, you can put a file or directory name starting wit a period in the $ENV{HOME} directory.
Back in the 1980s, I wrote accounting software for a very proprietary OS. When the user pressed the ESCAPE button, we were suppose return immediately to the main menu. If the user was entering an order, and took stuff out of inventory, the transaction would be incomplete, and inventory would be showing the items as being sold even though the order was incomplete. The solution was to check for these incomplete orders the next time someone entered an order, and back out the changes in inventory before entering the new order. Your program may have to do something similar.

Resources