Handle a signal: Difference between revisions
(added ruby) |
No edit summary |
||
Line 7: | Line 7: | ||
===Signal Handler=== |
===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 signal handlers must be defined at the library level. The following package defines a simple signal handler for the SigInt signal. |
||
<ada> |
<lang ada> |
||
with Ada.Interrupts; use Ada.Interrupts; |
with Ada.Interrupts; use Ada.Interrupts; |
||
with Ada.Interrupts.Names; use Ada.Interrupts.Names; |
with Ada.Interrupts.Names; use Ada.Interrupts.Names; |
||
Line 22: | Line 22: | ||
end Sigint_Handler; |
end Sigint_Handler; |
||
</ |
</lang> |
||
<ada> |
<lang ada> |
||
package body Sigint_Handler is |
package body Sigint_Handler is |
||
Line 53: | Line 53: | ||
end Sigint_Handler; |
end Sigint_Handler; |
||
</ |
</lang> |
||
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. |
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> |
<lang ada> |
||
with Ada.Calendar; use Ada.Calendar; |
with Ada.Calendar; use Ada.Calendar; |
||
with Ada.Text_Io; use Ada.Text_Io; |
with Ada.Text_Io; use Ada.Text_Io; |
||
Line 93: | Line 93: | ||
end Signals; |
end Signals; |
||
</ |
</lang> |
||
===Sample Output=== |
===Sample Output=== |
||
<pre> |
<pre> |
||
Line 130: | Line 130: | ||
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'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; |
<lang perl>my $start = time; |
||
$SIG{INT} = sub |
$SIG{INT} = sub |
||
Line 137: | Line 137: | ||
for (my $n = 0 ;; sleep 2) |
for (my $n = 0 ;; sleep 2) |
||
{print ++$n, "\n";}</ |
{print ++$n, "\n";}</lang> |
||
=={{header|Python}}== |
=={{header|Python}}== |
||
The following example should work on all platforms. |
The following example should work on all platforms. |
||
<python>import time |
<lang python>import time |
||
def intrptWIN(): |
def intrptWIN(): |
||
Line 158: | Line 158: | ||
intrptWIN() |
intrptWIN() |
||
tdelt = time.time() - t1 |
tdelt = time.time() - t1 |
||
print 'Program has run for %5.3f seconds.' % tdelt</ |
print 'Program has run for %5.3f seconds.' % tdelt</lang> |
||
There is a signal module in the standard distribution that accomodates the UNIX type |
There is a signal module in the standard distribution that accomodates the UNIX type |
||
signal mechanism. However the pause() mechanism is not implemented |
signal mechanism. However the pause() mechanism is not implemented |
||
on Windows versions. |
on Windows versions. |
||
<python>import signal, time, threading |
<lang python>import signal, time, threading |
||
done = False |
done = False |
||
n = 0 |
n = 0 |
||
Line 191: | Line 191: | ||
intrptUNIX() |
intrptUNIX() |
||
tdelt = time.time() - t1 |
tdelt = time.time() - t1 |
||
print 'Program has run for %5.3f seconds.' % tdelt</ |
print 'Program has run for %5.3f seconds.' % tdelt</lang> |
||
How about this one? It should work on all platforms; and it does show how to install a signal handler: |
How about this one? It should work on all platforms; and it does show how to install a signal handler: |
||
<python>import time, signal |
<lang python>import time, signal |
||
class WeAreDoneException(Exception): |
class WeAreDoneException(Exception): |
||
Line 216: | Line 216: | ||
tdelt = time.time() - t1 |
tdelt = time.time() - t1 |
||
print 'Program has run for %5.3f seconds.' % tdelt</ |
print 'Program has run for %5.3f seconds.' % tdelt</lang> |
||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
<ruby>t1 = Time.now |
<lang ruby>t1 = Time.now |
||
catch :done do |
catch :done do |
||
Line 235: | Line 235: | ||
tdelt = Time.now - t1 |
tdelt = Time.now - t1 |
||
puts 'Program has run for %5.3f seconds.' % tdelt</ |
puts 'Program has run for %5.3f seconds.' % tdelt</lang> |
Revision as of 15:36, 3 February 2009
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. <lang 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; </lang> <lang 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; </lang> 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. <lang 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; </lang>
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.
<lang perl>my $start = time;
$SIG{INT} = sub
{print 'Ran for ', time - $start, " seconds.\n"; exit;};
for (my $n = 0 ;; sleep 2)
{print ++$n, "\n";}</lang>
Python
The following example should work on all platforms. <lang 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</lang>
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. <lang 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</lang>
How about this one? It should work on all platforms; and it does show how to install a signal handler: <lang 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</lang>
Ruby
<lang ruby>t1 = Time.now
catch :done do
Signal.trap('INT') do Signal.trap('INT', 'DEFAULT') # reset to default throw :done end n = 0 loop do sleep(0.5) n += 1 puts n end
end
tdelt = Time.now - t1 puts 'Program has run for %5.3f seconds.' % tdelt</lang>