Handle a signal: Difference between revisions
Underscore (talk | contribs) (Added Perl.) |
|||
Line 127: | Line 127: | ||
main bye |
main bye |
||
=={{header|Perl}}== |
|||
Perl's <tt>sleep</tt> doesn't handle non-integral arguments correctly on some platforms, so this program prints a number every two seconds. |
|||
<perl>my $start = time; |
|||
$SIG{INT} = sub |
|||
{print 'Ran for ', time - $start, " seconds.\n"; |
|||
exit;}; |
|||
for (my $n = 0 ;; sleep 2) |
|||
{print ++$n, "\n";}</perl> |
|||
=={{header|Python}}== |
=={{header|Python}}== |
Revision as of 23:41, 31 December 2008
You are encouraged to solve this task according to the task description, using any language you may know.
Most general purpose operating systems provide interrupt facilities, sometimes called signals. Unhandled signals generally terminate a program in a disorderly manner. Signal handlers are created so that the program behaves in a well-defined manner upon receipt of a signal.
For this task you will provide a program that displays a single integer on each line of output at the rate of one integer in each half second. Upon receipt of the SigInt signal (often created by the user typing ctrl-C) the program will cease printing integers to its output, print the number of seconds the program has run, and then the program will terminate.
Ada
Signal Handler
Ada signal handlers must be defined at the library level. The following package defines a simple signal handler for the SigInt signal. <ada> with Ada.Interrupts; use Ada.Interrupts; with Ada.Interrupts.Names; use Ada.Interrupts.Names;
package Sigint_Handler is
protected Handler is entry Wait; procedure Handle; pragma Interrupt_Handler(Handle); pragma Attach_Handler(Handle, Sigint); private Call_Count : Natural := 0; end Handler;
end Sigint_Handler; </ada> <ada> package body Sigint_Handler is
------------- -- Handler -- -------------
protected body Handler is
---------- -- Wait -- ----------
entry Wait when Call_Count > 0 is begin Call_Count := Call_Count - 1; end Wait;
------------ -- Handle -- ------------
procedure Handle is begin Call_Count := Call_Count + 1; end Handle;
end Handler;
end Sigint_Handler; </ada> A signal may be received at any time in a program. Ada signal handling requires a task to suspend on an entry call for the handler which is executed only when the signal has been received. The following program uses the interrupt handler defined above to deal with receipt of SigInt. <ada> with Ada.Calendar; use Ada.Calendar; with Ada.Text_Io; use Ada.Text_Io; with Sigint_Handler; use Sigint_Handler;
procedure Signals is
task Counter is entry Stop; end Counter; task body Counter is Current_Count : Natural := 0; begin loop select accept Stop; exit; or delay 0.5; end select; Current_Count := Current_Count + 1; Put_Line(Natural'Image(Current_Count)); end loop; end Counter; task Sig_Handler; task body Sig_Handler is Start_Time : Time := Clock; Sig_Time : Time; begin Handler.Wait; Sig_Time := Clock; Counter.Stop; Put_Line("Program execution took" & Duration'Image(Sig_Time - Start_Time) & " seconds"); end Sig_Handler;
begin
null;
end Signals; </ada>
Sample Output
1 2 3 4 5 6 7 8 Program execution took 4.348057086 seconds
Forth
Normally Gforth handles most signals (e.g., the user interrupt SIGINT, or the segmentation violation SIGSEGV) by translating it into a Forth THROW.
-28 constant SIGINT : numbers ( n -- n' ) begin dup . cr 1+ 500 ms again ; : main utime 0 begin ['] numbers catch SIGINT = until drop utime d- dnegate <# # # # # # # [char] . hold #s #> type ." seconds" ; main bye
Perl
Perl's sleep doesn't handle non-integral arguments correctly on some platforms, so this program prints a number every two seconds.
<perl>my $start = time;
$SIG{INT} = sub
{print 'Ran for ', time - $start, " seconds.\n"; exit;};
for (my $n = 0 ;; sleep 2)
{print ++$n, "\n";}</perl>
Python
The following example should work on all platforms. <python>import time
def intrptWIN():
procDone = False n = 0
while not procDone: try: time.sleep(0.5) n += 1 print n except KeyboardInterrupt, e: procDone = True
t1 = time.time() intrptWIN() tdelt = time.time() - t1 print 'Program has run for %5.3f seconds.' % tdelt</python>
There is a signal module in the standard distribution that accomodates the UNIX type signal mechanism. However the pause() mechanism is not implemented on Windows versions. <python>import signal, time, threading done = False n = 0
def counter():
global n, timer n += 1 print n timer = threading.Timer(0.5, counter) timer.start()
def sigIntHandler(signum, frame):
global done timer.cancel() done = True
def intrptUNIX():
global timer signal.signal(signal.SIGINT, sigIntHandler)
timer = threading.Timer(0.5, counter) timer.start() while not done: signal.pause()
t1 = time.time() intrptUNIX() tdelt = time.time() - t1 print 'Program has run for %5.3f seconds.' % tdelt</python>
How about this one? It should work on all platforms; and it does show how to install a signal handler: <python>import time, signal
class WeAreDoneException(Exception):
pass
def sigIntHandler(signum, frame):
signal.signal(signal.SIGINT, signal.SIG_DFL) # resets to default handler raise WeAreDoneException
t1 = time.time()
try:
signal.signal(signal.SIGINT, sigIntHandler) n = 0 while True: time.sleep(0.5) n += 1 print n
except WeAreDoneException:
pass
tdelt = time.time() - t1 print 'Program has run for %5.3f seconds.' % tdelt</python>