Handle a signal

From Rosetta Code
Revision as of 07:39, 24 December 2008 by rosettacode>Spoon! (how about this, using a timer from threads? alarm() only accepts integer seconds)
Task
Handle a signal
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

Works with: GNU 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


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 timer mechanisms using the SIGALM signal are not implemented on Windows versions. The following code is untested. <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>