How can I intercept Ctrl+C in a CLI application?
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() { /*
my shutdown code here
*/ }
});
This should be able to intercept the signal, but only as an intermediate step before the JVM completely shutdowns itself, so it may not be what you are looking after.
You need to use a SignalHandler
(sun.misc.SignalHandler
) to intercept the SIGINT
signal triggered by a Ctrl+C (on Unix as well as on Windows).
See this article (pdf, page 8 and 9).
How do I trap Ctrl+C (SIGINT) in a C# console app?
See MSDN:
Console.CancelKeyPress Event
Article with code samples:
Ctrl-C and the .NET console application
Can I send a ctrl-C (SIGINT) to an application on Windows?
The closest that I've come to a solution is the SendSignal 3rd party app. The author lists source code and an executable. I've verified that it works under 64-bit windows (running as a 32-bit program, killing another 32-bit program), but I've not figured out how to embed the code into a windows program (either 32-bit or 64-bit).
How it works:
After much digging around in the debugger I discovered that the entry point that actually does the behavior associated with a signal like ctrl-break is kernel32!CtrlRoutine. The function had the same prototype as ThreadProc, so it can be used with CreateRemoteThread directly, without having to inject code. However, that's not an exported symbol! It's at different addresses (and even has different names) on different versions of Windows. What to do?
Here is the solution I finally came up with. I install a console ctrl handler for my app, then generate a ctrl-break signal for my app. When my handler gets called, I look back at the top of the stack to find out the parameters passed to kernel32!BaseThreadStart. I grab the first param, which is the desired start address of the thread, which is the address of kernel32!CtrlRoutine. Then I return from my handler, indicating that I have handled the signal and my app should not be terminated. Back in the main thread, I wait until the address of kernel32!CtrlRoutine has been retrieved. Once I've got it, I create a remote thread in the target process with the discovered start address. This causes the ctrl handlers in the target process to be evaluated as if ctrl-break had been pressed!
The nice thing is that only the target process is affected, and any process (even a windowed process) can be targeted. One downside is that my little app can't be used in a batch file, since it will kill it when it sends the ctrl-break event in order to discover the address of kernel32!CtrlRoutine.
(Precede it with start
if running it in a batch file.)
Catching Ctrl+C in Java
You can attach a shutdown hook to the VM which gets run whenever the VM shuts down:
The Java virtual machine shuts down in response to two kinds of events:
The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or
The virtual machine is terminated in response to a user interrupt, such as typing Ctrl+C, or a system-wide event, such as user logoff or system shutdown.
The thread you pass as shutdown hook has to follow several rules, though, so read the linked documentation carefully to avoid any problems. This includes ensuring thread-safety, quick termination of the thread, etc.
Also, as commenter Jesper points out, shutdown hooks are guaranteed to run on normal shutdown of the VM but if the VM process is terminated forcibly they don't. This can happen if native code screws up or if you forcibly kill the process (kill -9
, taskkill /f
).
But in those scenarios all bets are off anyway, so I wouldn't waste too much thought on it.
How can I catch a ctrl-c event?
signal
isn't the most reliable way as it differs in implementations. I would recommend using sigaction
. Tom's code would now look like this :
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
void my_handler(int s){
printf("Caught signal %d\n",s);
exit(1);
}
int main(int argc,char** argv)
{
struct sigaction sigIntHandler;
sigIntHandler.sa_handler = my_handler;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
sigaction(SIGINT, &sigIntHandler, NULL);
pause();
return 0;
}
How to catch Ctrl-C signal inside an Objective-C function?
Technically inside your Objective-C method you can't catch a SIGINT
signal (generated by user upon pressing CTRL-C) - your program gets interrupted.
The control of flow at this point is handled by kernel. The state of cpu registers valid during execution of your objective-c run
method are inevitably lost. Hence you can't continue executing your run
method anymore.
What you can do is register a custom SIGINT
handler using C API.
#import <signal.h>
void sigHandler(int sig) {
//as noted by @bbum list of functions with guaranteed behavior in sighandler is very limited
//obj-c runtime is definitely NOT on the list
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
[process1 stop];
[process2 stop];
});
//give extra time for the async part to run
usleep(50);
}
int main(int argc, const char * argv[]) {
signal(SIGINT, sigHandler);
@autoreleasepool {
//your normal program launch goes here
}
return 0;
}
If you have a console app alternatively you could consider route here
so basically disable CTRL-C firing SIGINT
and asynchronously handle the keyboard reading for CTRL-C yourself. The main drawback is if your program would hit an endless loop it cannot be interrupted with CTRL-C. So to minimise this effect you could set this special terminal mode at the beginning of your run
method and restore it once you're done.
Related Topics
Import Maven Dependencies in Intellij Idea
Convert Existing Eclipse Project to Maven Project
Loading a Properties File from Java Package
How to Exclude Some Concrete Urls from <Url-Pattern> Inside <Filter-Mapping>
How to Load Rsa Private Key from File
Java Embedded Databases Comparison
How to Use Classes from .Jar Files
Get Domain Name from Given Url
Cannot Create an Array of Linkedlists in Java
Picking a Random Element from a Set
Execute Another Jar in a Java Program
How to Run Certain Task Every Day at a Particular Time Using Scheduledexecutorservice
Mod in Java Produces Negative Numbers
How to Set Timeout in Retrofit Library
How to Iterate an Arraylist Inside a Hashmap Using Jstl