I am attempting to trap a SIGINT for a UI application made for MacOS. In the app delegate class, I see the following method:
func applicationWillTerminate(_ aNotification: Notification) {
}
However, a Ctrl + C, SIGINT, never gets caught in here. Reading around the internet, has shown that this function is not guaranteed to execute, especially if the app goes in the background.
What can I do in the app delegate to catch a SIGINT? Or is there an alternate place I am to catch the interrupt so that I can close the resources appropriately?
Charles's answer is correct, but his caveat ("Be sure only to call reentrant functions from within the handler") is an extreme limitation. It's possible to redirect handling of a signal to a safer environment using kqueue and CFFileDescriptor.
Technical Note TN2050: Observing Process Lifetimes Without Polling is on a different subject but illustrates the technique. There, Apple describes Charles's caveat this way:
Listening for a signal can be tricky because of the wacky execution
environment associated with signal handlers. Specifically, if you
install a signal handler (using signal or sigaction), you must be very
careful about what you do in that handler. Very few functions are safe
to call from a signal handler. For example, it is not safe to allocate
memory using malloc!
The functions that are safe from a signal handler (the async-signal
safe functions) are listed on the sigaction man page.
In most cases you must take extra steps to redirect incoming signals
to a more sensible environment.
I've taken the code illustration from there and modified it for handling SIGINT. Sorry, it's Objective-C. Here's the one-time setup code:
// Ignore SIGINT so it doesn't terminate the process.
signal(SIGINT, SIG_IGN);
// Create the kqueue and set it up to watch for SIGINT. Use the
// EV_RECEIPT flag to ensure that we get what we expect.
int kq = kqueue();
struct kevent changes;
EV_SET(&changes, SIGINT, EVFILT_SIGNAL, EV_ADD | EV_RECEIPT, NOTE_EXIT, 0, NULL);
(void) kevent(kq, &changes, 1, &changes, 1, NULL);
// Wrap the kqueue in a CFFileDescriptor. Then create a run-loop source
// from the CFFileDescriptor and add that to the runloop.
CFFileDescriptorContext context = { 0, self, NULL, NULL, NULL };
CFFileDescriptorRef kqRef = CFFileDescriptorCreate(NULL, kq, true, sigint_handler, &context);
CFRunLoopSourceRef rls = CFFileDescriptorCreateRunLoopSource(NULL, kqRef, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
CFRelease(rls);
CFFileDescriptorEnableCallBacks(kqRef, kCFFileDescriptorReadCallBack);
CFRelease(kqRef);
And here's how you would implement the sigint_handler callback referenced above:
static void sigint_handler(CFFileDescriptorRef f, CFOptionFlags callBackTypes, void *info)
{
struct kevent event;
(void) kevent(CFFileDescriptorGetNativeDescriptor(f), NULL, 0, &event, 1, NULL);
CFFileDescriptorEnableCallBacks(f, kCFFileDescriptorReadCallBack);
// You've been notified!
}
Note that this technique requires that you run the setup code on a thread which will live as long as you're interested in handling SIGINT (perhaps the app's lifetime) and service/run its run loop. Threads created by the system for its own purposes, such as those which service Grand Central Dispatch queues, are not suitable for this purpose.
The main thread of the app will work and you can use it. However, if the main thread locks up or become unresponsive, then it's not servicing its run loop and the SIGINT handler won't be called. Since SIGINT is often used to interrupt exactly such a stuck process, the main thread may not be suitable.
So, you may want to spawn a thread of your own just to monitor this signal. It should do nothing else, because anything else might cause it to get stuck, too. Even there, though, there are issues. Your handler function will be called on this background thread of yours and the main thread may still be locked up. There's a lot of stuff that is main-thread-only in the system libraries and you won't be able to do any of that. But you'll have much greater flexibility than in a POSIX-style signal handler.
I should add that GCD's dispatch sources can also monitor UNIX signals and are easier to work with, especially from Swift. However, they won't have a dedicated thread pre-created to run the handler. The handler will be submitted to a queue. Now, you may designate a high-priority/high-QOS queue, but I'm not entirely certain that the handler will get run if the process has numerous runaway threads already running. That is, a task that's actually running on a high-priority queue will take precedence over lower-priority threads or queues, but starting a new task might not. I'm not sure.
You can do this via the sigaction() function:
import Foundation
let handler: #convention(c) (Int32) -> () = { sig in
// handle the signal somehow
}
var action = sigaction(__sigaction_u: unsafeBitCast(handler, to: __sigaction_u.self),
sa_mask: 0,
sa_flags: 0)
sigaction(SIGINT, &action, nil)
Be sure only to call reentrant functions from within the handler.
Although I won't dare to compete with the great answers above, I think there is something important to say that may simplify the solution a lot.
I think your question mixes two very different levels of MacOS program life-cycle management.
True, you can run simple posix-style executables on Mac - but a Mac Cocoa app IS NOT a posix app with "attached UI". Mac application relies on a very verbose, complete, and feature-rich life-cycle mechanism that allows much more than anything posix process can -- from state preservation and restoration (when killed/re-launched) to being auto-launched in response to opening a file. Energy management, handling computer sleep, background and foreground transitions, attaching to the same app on close-by device, modes etc. etc.
Furthermore -- I can't see how one can ever expect a 'ctrl-C' from the keyboard to reach a Cocoa ("UI") application, as keyboard shortcuts are totally different in this context, and you can't run "UI" app from a terminal/shell synchronously.
Now the right wa to 'interrupt' a Cocoa app that is "stuck" or takes too long to perform something, is using the convention command-preiod key-combination, still widely implemented by many apps (Photoshop, video-editors, the Finder etc.) I'm sorry I could not locate this definition in Apple User Interface Guidelines - maybe it is no longer part of the standard. However, Ctrl-C certainly isn't!!!
you can implement Cmd-Period (⌘.) in your app (i.e. register for this high-level "interrupt" action, and handle it gracefully.
There is a good reason why NSApplication object wrapping the Cocoa App ignores SIGINT! it is completely out of context.
I am trying to cancel when a process calls wait(), read(), recvfrom() or similar, because if I use ptrace on it, after the PTRACE_ATTACH and later PTRACE_CONT, my tracer becomes blocked until the function in the tracee returns. Also I think it happens the same with sleep().
Would be possible to cancel the call, or reproduce a fake return?
Thanks.
Yes, you should send a PTRACE_INTERRUPT. This will trigger the syscall to exit.
To do this, you need not to waitpid on your tracee, because that would block you (the tracer) too.
You can either have multiple threads: one that will block on the tracee, one that will "decide" to cancel the blocking syscall - e.g. a GUI thread that the user will press "cancel" (like a normal debugger, e.g. GDB).
Or you can use PTRACE_SYSCALL to manually diagnose every syscall the program is doing and then decide preemptively if you wish to execute that syscall. This way you can decide to not run wait at all, or perhaps mock them by having your return value instead.
I'm concerned about data corruption while executing a Storable::store operation. I'm writing about 100 MB to an NFS to backup my calculations at particular checkpoints but the process isn't exactly speedy.
To try to prevent corruption, I have a SIG{INT} signal handler. Right before Storable::store is called, a global variable is set indicating it isn't safe to terminate. As soon as Storable::store completes, that global variable is returned to a value to indicate it's okay to interrupt.
That global variable is used to indicate whether or not the signal handler will call die or whether it will just print a statement saying "Can't stop yet."
But am I really helping thing? I see now from reading perlipc that interrupting IO is sometimes done safely, and sometimes it is not... That is, should my signal handler end up being called in the middle of my Storeable::store operation, such a brief diversion to my signal handler subroutine may still be enough to screw things up.
Does anyone know how Storable performs in such a situation? Or is my signal handling setup actually appropriate?
Since 5.8.1, Perl uses "safe signals" (by default). When you setup a signal handler through %SIG, Perl actually installs a simple signal handler that does nothing but increment a counter. In between Perl ops, Perl checks if the counter is non-zero, and calls your signal handler if it is. That way, your signal handlers don't execute in the middle of a system call or library call.
There are only two things you need to worry about:
Modifying global vars (e.g. $!) in your signal handler.
System calls returning EINTR or EAGAIN because a signal came in during the call.
If you're really concerned that SIGINT could break store, try adding SA_RESTART to your signal handler. On Linux, this will force the system calls to be automatically retried upon a signal. This will probably defer your signal handler indefinitely since SIGINT will not be able to break out of the I/O operation. However, it should enable safe operation of Storable::store under any interruption circumstance.
In the past, I have used libraries that would allow me to register a callback so that the library can call my method when some event happens (e.g. it is common to see in code that use GUI libraries to look like button.onClick(clickHandler)).
Naively, I suppose the library's handling mechanism could be implemented like:
while(1){
if (event1) { event1Handler(); }
if (event2) { event2Handler(); }
...
}
but that would be really wasteful right? Or is that really how it is done (for instance do well known GUI libraries like java swing, or GTK+ do it this way)?
background:
This question hadn't really occured to me until I encountered curses. I thought about implementing my own callback system, until I realized I didn't know how.
The while loop will typically wait for an interrupt from the user (GetMessage in Windows). When an interrupt arrives GetMessage returns and then it ends up in the callback function. The if statements are typically implemented as a switch-case. See Windows Message Loop on Wikipedia.
In more detail, what happens is the following:
The user application calls GetMessage, which forces the process to sleep until an input message for that application arrives from the systems queue. When a message arrives, the user app calls DispatchMessage, which calls the callback function associated with the window that the message was aimed at.
Windows API uses one callback which handles all events in a switch case. Other libraries use one callback per event class instead.
The function pointers themselves are stored together with other window data in a struct.
Callback system implementation probably has different implementation in different technologies, however, I suppose they should be working this way:
A data structure stores the callback IDs and pointers to the handlers.
A callback handler has a validator
Event handlers have callback callers, which know what are the possible callbacks and check their validity this way:
for each callback in event.callbacks
if (callback.isValid())
call callback()
end if
end for
When you add a handler to a function the system will automatically know where the callback is valid and will add the callback to the datastructure described in 1.
Correct me if I'm wrong, this description is just a guess.
I've looked through the documentation, etc, but I'm not seeing anything obvious. I'd like to have a signal handler that can intercept ^C, ^\, or some other keypress that could be used to interrupt a long-running script (each discrete computation is typically <1s) and allow it to exit gracefully and save current state.
Matlab does have event handlers for COM, but it's windows-only and I'm in a *nix environment.
If the answer is 'tough luck', I'm cool with that ... I'm just not seeing anything that says I'm SOL yet.
MATLAB already interprets ^C as an interrupt. You can use onCleanup objects to ensure that your program state is preserved correctly. I.e. something like:
function testFcn
x = onCleanup( #() disp('perform cleanup here...') );
for ii=1:1000, disp(ii), pause(1), end
Run the above and hit ^C when you get bored. Obviously, you can hook any function handle in to your onCleanup object. See also the reference page for onCleanup.