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.
Related
Why is the following empty program exiting on Ctrl + C with 130 on Linux (which is what I suspect, because my shell bash wraps SIGINT to 130 (128+2).
On Windows with Git Bash (git-bash.exe), I get exit code 2.
package main
func main() {
for {
}
}
Is that Go's behavior on Windows or git-bash.exe? Because I need exit code 2 internally, do I need to wrap it using the signal package?
Well, it's two-fold.
On the one hand, as #Flimzy pointed out, it's shell intervening.
On the other hand, what is missing from his remark is why this happens.
The explanation is, again, two-fold:
A process has certain default signal handling disposition which is how the process reacts to certain signals. A signal can be ignored, handled or left as is which, in most if not all cases means killing the process.
You can read more about this here.
Note that in non-trivial processes such as programs written in Go which have intricate runtime system, the default signal disposition may be different from that of "more plain" processes.
By default the SIGINT signal is not handled meaning it kills the process.
The bash she'll adds 128 to the exit code of a process if it was killed with a fatal signal. More about this — in the bash manual.
Update on the behaviour in Windows.
Let's first put up a quick fact sheet:
Windows does not support the concept of Unix signals, at all.
The way terminal-aware programs work on Unix-like systems is very different from the way console-aware programs work on Windows.
Say, the way Vim looks and behaves in a "Git bash" windows on Windows may look very similar to how it looks in a GNOME Terminal window on a Linux-based OS but the underlying differences are profound.
Let's now dig a bit deeper.
Unix was born without any notion of GUI and the users would interact with a Unix system using hardware terminals.
In order to support them, kernels of Unix-like OSes implement special standardized way to make terminal-aware programs interact with the system; if you're "into" deep-diving into technical details, I highly recommend reading the "TTY demystified" piece.
The two more important highlights of this approach are:
The terminal subsystem is used even by programs running in what the contemporary generation of freshmen calls "terminals"—in windows which typically start out running a shell, in which you call various command-line programs, including those using "full screen"—such as text editors.
This basically means if you take, say Vim or GNU Nano, it will run just fine in any graphical terminal emulator, or directly on Linux's "virtual terminal" (those textual screen you can get on a PC by hitting Ctrl-Alt-F1 or booting with GUI turned off) or on a hardware terminal attached to the computer.
The terminal subsystem allocates certain codes a keyboard may send to it to perform certain actions—as opposed to sending those coder directly to the program attached to that terminal, and Ctrl-C is one of them: in a common default setup pressing that combination of keys makes the terminal subystem send the foreground process the SIGINT Unix signal.
The latter is of particular interest. You can run stty -a in a terminal window on your Linux system; amoung the copious output you'd see something like intr = ^C; quit = ^\; which means Ctrl-C sends interactive attention (SIGINT) signal and Ctrl-\ sends SIGQUIT (yes, "INT" in "SIGINT" does not stand for "interrupt"—contrary to a popular belief).
You could reassign these key combos almost at will (though it's not a wise thing to do as many pieces of software expect ^C and ^\ to be mapped the way they usually do and do not assign their own actions to these gestures—rightfully expecting to not be able to actually ever receive them.
Now back to Windows.
On Windows, there is no terminal subsystem, and no signals.
Console window on Windows was an artefact required to provide compatibility with the older MS-DOS system, and there the situation was like this: Ctrl-Break would trigger a hardware interrupt usually handled by the OS, and Ctrl-C could be explicitly enabled to do the same. The implementation of the console emulation on Windows carefully emulated this behaviour, but since Windows does not have Unix-like signals, the handling of these keyboard combos is done differently—though with much the same effect:
Each console process has its own list of application-defined HandlerRoutine functions that handle CTRL+C and CTRL+BREAK signals. The handler functions also handle signals generated by the system when the user closes the console, logs off, or shuts down the system. Initially, the handler list for each process contains only a default handler function that calls the ExitProcess function.
What this all means to Go?
Let's first see the docs:
~$ GOOS=windows go doc os.Interrupt
package os // import "os"
var (
Interrupt Signal = syscall.SIGINT
Kill Signal = syscall.SIGKILL
)
The only signal values guaranteed to be present in the os package on all systems are os.Interrupt (send the process an interrupt) and os.Kill (force the process to exit). On Windows, sending os.Interrupt to a process with os.Process.Signal is not implemented; it will return an error instead of sending a signal.
So, in a Go program running on Windows you can handle these two "signals"—even though they were not really be implemented as signals.
Let's now move to explaning the difference in the exit codes.
As you know by now, pressing Ctrl-C when a program is running in a terminal emulator windows on a Unix-like system will make the terminal subsystem send the process the actual SIGINT signal.
If this signal is not explicitly handled, the process gets killed by the OS (as that's what the default signal disposition says).
The shell notices that a process it spawned suddenly died, collects its exit code and adds 128 to it (because it wasn't expecting it to die that way).
On Windows, hitting Ctrl-C makes the process perform the ExitProcess system call, which, form the point of view of the shell process looks like normal process exit: it cannot tell this exit apart from the one occured if the process were to call os.Exit(0) explicitly.
I am writing a normal, innocent C++/Qt program in Windows 7/MinGW.
It is the second time in two days that after closing the program the executable remains among the active processes, and there is no way to kill it (I try both from the command line and from Windows Task Manager).
One inconvenience is that I cannot re-link my code, because the binary code cannot be overwritten, being running.
The reason is that the executable was running under the control of the debugger, and this protected the process against any attempt to kill it. Stopping it through the debugger has been successful.
I did not know that the debugger could shield a process from any external attempt to kill it so well...
I have an application made with matlab compiler.
I want to do some shutdown activities whenever it ends. As it seems to be impossible to catch signals in matlab (or I'm not able to), I checked to use onCleanup (Matlab: Is it possible to create signal handlers (.m scripts)). It is working within matlab (native), but not within the compiled application.
I tried to end the application with CTRL-C and with taskkill (which only work with /f). In both cases the onCleanup-method was NOT executed.
For testing purposes here
function sigtest(varargin)
remainder=onCleanup(#()save('exit.mat'));
b=1;
while true
disp(datestr(now));
a=rand(round(5*b));%to be saved
pause(10);
b=a(1);
end
my source code, which I compiled via mcc -m -v sigtest.m.
As onether try, I inserted the lines
myexiter=addlistener(System.AppDomain.CurrentDomain,'ProcessExit',...
#(a,b)save('listexit.mat'));
after line 2, but also this .NET-Event is not working.
If you're registering shutdown activities within M-code, they're only going to work on a graceful shutdown of the process. The taskkill /f command will do a "forceful" shutdown, which I think will terminate the process immediately. The Matlab interpreter won't get a chance to run whatever cleanup code is still pending. I think Ctrl-C on a console application (which the compiled sigtest.m will be running as) will have the same effect. Same applies to the .NET-Event: if you forcefully kill the process, that callback never gets a chance to run.
If you want on-exit code, or any other cleanup stuff, to run, you need to find a way for the program to find out when it should exit and initiate a more graceful shutdown itself. For example, in your sigtest example, you could check stdin at the end of every pass through the loop, see if the user has typed 'quit', and if so call exit(). Then your onCleanup stuff should run.
In a GUI compiled Matlab application, this is more straightforward; you have GUI controls to exit the application. I don't know what the canonical way is to make a console compiled Matlab application responsive to user exit requests, or if there even is a good one. You might want to make this a GUI app if you think the user might want to request a graceful abort of its operation.
I decided to write a program in RUBY in which the following things should be done:
1 - this program must run a specific program (for example utorrent) at a specific time (for example 1 pm).
2 - this program must turn off my computer at another specific time.
I don't have any idea about the algorithm and manner of writing such program.
One of the easiest ways to do this is to simply send kill signals to the processes, requesting the app shut down normally (Linux), or in Windows use taskkill.
To shutdown a machine in Windows, you can use shutdown /s /f which forcibly closes any programs that are running, and turns the computer off.
No matter which way you do it, you'll basically be running the enter link description heresystem() command in Ruby, which runs command line commands. To make your app portable, you simply look up how to do these tasks in each target OS, and you're done.
Two more alternatives that work the same as your Ruby proposal, but which are not as easily portable:
Write a batch file in Windows that calls taskkill, or a bash script on Linux. Unless the program in question provides a specific way to shut it down via its own command-line parameters, this should work for any/all applications.
You can also use Task Scheduler in Windows, or cron in Linux to do the same thing.
How to reload a crashed process on Windows? Of course, I can run a custom monitoring Win service process. But, for example, Firefox: it doesn't seem to install such a thing, but still it can restart itself when it crashes.
On Vista and above, you can use the RegisterApplicationRestart API to automatically restart when it crashes or hangs.
Before Vista, you need to have a top level exception filter which will do the restart, but be aware that running code inside of a compromised process isn't entirely secure or reliable.
Firefox constantly saves its state to the hard disk, every time you open a tab or click a link, or perform some other action. It also saves a flag saying it shut down safely.
On startup, it reads this all back, and is able to "restore" based on that info.
Structured exception handling (SEH) allows you to catch program crashes and to do something when it happens.
See: __try and __except
SEH can be very dangerous though and could lead to your program hanging instead. Please see this article for more information.
If you write your program as an NT service then you can set the first, second and subsequent failure actions to "Restart the service".
For Windows 2008 server and Windows Vista and Windows 7 you can use the Win32 API RegisterApplicationRestart
Please see my answer here for more information about dealing with different types of program crashes.
If I recall correctly Windows implements at least some subset of POSIX and so "must" have the signal interface (things like SIGKILL, SIGSEGV, SIGQUIT etc.).
I've never done this but on linux, but you could try setting the unexpected termination trap with signal() (signal.h).
From quick scan of docs it seems that very few things can be done while handling signal, it may be possible that even starting a new process is on forbidden list.
Now that I've thought about it, I'd probably go with master/worker pattern, very simple parent thread that does nothing but spawns the worker (that does all the UI / other things). If it does not set a specific "I'm gonna die now" bit but still dies (parent process always gets message / notification that spawned process died) then master respawns the worker. The main theme is keep master very simple and hard to die due to own bugs.