Handle a signal

From Rosetta Code
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. <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

C

Works with: POSIX

Standard C's sleep() only provides one-second resolution, so the POSIX usleep() function is used here. (POSIX is not needed for the actual signal handling part.) <lang C>#include <stdio.h>

  1. include <stdlib.h> // for exit()
  2. include <signal.h>
  3. include <time.h> // for clock()
  4. include <unistd.h> // for POSIX usleep()

static clock_t startTime;

void handleSigint() {

   clock_t endTime = clock();
   double td = (endTime - startTime) / (double)CLOCKS_PER_SEC;
   printf("Program has run for %5.3f seconds\n", td);
   exit(0);

}

int main() {

   startTime = clock();
   signal(SIGINT, handleSigint);
   int i=0;
   for (;;) {

usleep(500000); printf("%d\n", ++i);

   }
   return 0;

}</lang>

Sample Output

1
2
3
Program has run for 1.953 seconds

C#

Signals in C# are called events, and are handled by attaching event handler functions to the event, which are called when the event is triggered.

<lang csharp>using System; //DateTime, Console, Environment classes class Program {

   static DateTime start;
   static void Main(string[] args)
   {
       start = DateTime.Now;
       //Add event handler for Ctrl+C command
       Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);
       int counter = 0;
       while (true)
       {
           Console.WriteLine(++counter);
           System.Threading.Thread.Sleep(500);
       }
   }
   static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)
   {
       var end = DateTime.Now;
       Console.WriteLine("This program ran for {0:000.000} seconds.", (end - start).TotalMilliseconds / 1000);
       Environment.Exit(0);
   }

}</lang>

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.

<lang forth>-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</lang>

F#

<lang fsharp>open System

let rec loop n = Console.WriteLine( n:int )

                Threading.Thread.Sleep( 500 )
                loop (n + 1)

let main() =

  let start = DateTime.Now
  Console.CancelKeyPress.Add(
     fun _ -> let span = DateTime.Now - start
              printfn "Program has run for %.0f seconds" span.TotalSeconds
            )
  loop 1

main()</lang>

Go

Although not using a single go statement, this program deals with three goroutines: main, the runtime, and a "ticker." Both the runtime signal source and the ticker object conveniently use channels, so both can be handled in a single select statement that waits for either event. <lang go>package main

import (

   "fmt"
   "time"
   "os/signal"
   "syscall"

)

func main() {

   start := time.Nanoseconds()
   k := time.NewTicker(5e8) // .5 second
   for n := 1; ; {
       // not busy waiting, this blocks until one of the two
       // channel operations is possible
       select {
       case <-k.C:
           fmt.Println(n)
           n++
       // all types of signals are received on this channel
       case s := <-signal.Incoming:
           if us, ok := s.(signal.UnixSignal); ok && us == syscall.SIGINT {
               fmt.Printf("\nRan for %f seconds.\n",
                   float64(time.Nanoseconds()-start)*1e-9)
               return
           }
           // if the signal wasn't SIGINT, ignore it.
       }
   }

}</lang> Output:

1
2
3
^C
Ran for 1.804877 seconds.

Haskell

<lang haskell>import Prelude hiding (catch) import Control.Exception (catch, throwIO, AsyncException(UserInterrupt)) import Data.Time.Clock (getCurrentTime, diffUTCTime) import Control.Concurrent (threadDelay)

main = do t0 <- getCurrentTime

         catch (loop 0)
               (\e -> if e == UserInterrupt
                        then do t1 <- getCurrentTime
                                putStrLn ("\nTime: " ++ show (diffUTCTime t1 t0))
                        else throwIO e)

loop i = do print i

           threadDelay 500000 {- µs -}
           loop (i + 1)</lang>

HicEst

Subroutines "F2" to "F9" can be called any time by the F2...F9 keys or by a mouse click on the toolbar buttons "F2" to "F9". These buttons appear as soon as a SUBROUTINE "F2" to "F9" statement is compiled: <lang HicEst>seconds = TIME()

DO i = 1, 1E100  ! "forever"

 SYSTEM(WAIT = 500) ! milli seconds
 WRITE(Name) i

ENDDO

SUBROUTINE F2  ! call by either the F2 key, or by a toolbar-F2 click

  seconds = TIME() - seconds
  WRITE(Messagebox, Name) seconds
  ALARM(999)        ! quit immediately

END</lang>

OCaml

OCaml's Unix.sleep doesn't handle non-integral arguments, so this program prints a number every second.

<lang ocaml>#load "unix.cma";; (* for sleep and gettimeofday; not needed for the signals stuff per se *)

let start = Unix.gettimeofday ();;

Sys.set_signal Sys.sigint

 (Sys.Signal_handle (fun _signum ->
                       Printf.printf "Ran for %f seconds.\n"
                         (Unix.gettimeofday () -. start);
                       exit 0));;

let rec loop n =

 Printf.printf "%d\n%!" n;
 Unix.sleep 1;
 loop (n + 1)

in

 loop 1;;</lang>

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>

This example does the required task: <lang perl>use 5.010; use AnyEvent; my $start = AE::time; my $exit = AE::cv; my $int = AE::signal 'INT', $exit; my $n; my $num = AE::timer 0, 0.5, sub { say $n++ }; $exit->recv; say " interrupted after ", AE::time - $start, " seconds";</lang>

Sample output:

0
1
2
3
4
5
6
7
8
9
10
^C interrupted after 5.23734092712402 seconds

PHP

Translation of: Perl

<lang php><?php declare(ticks = 1);

$start = microtime(YES);

function mySigHandler() {

 global $start;
 $elapsed = microtime(YES) - $start;
 echo "Ran for $elapsed seconds.\n";
 exit();

}

pcntl_signal(SIGINT, 'mySigHandler');

for ($n = 0; ; usleep(500000)) // 0.5 seconds

  echo ++$n, "\n";

?></lang>

PicoLisp

Put the following into a file, set it to executable, and run it <lang PicoLisp>#!/usr/bin/picolisp /usr/lib/picolisp/lib.l

(push '*Bye '(println (*/ (usec) 1000000)) '(prinl))

(let Cnt 0

  (loop
     (println (inc 'Cnt))
     (wait 500) ) )</lang>

PL/I

<lang> handler: procedure options (main);

  declare i fixed binary (31);
  declare (start_time, finish_time) float (18);
  on attention begin;
     finish_time = secs();
     put skip list ('elapsed time =', finish_time - start_time, 'secs');
     stop;
  end;
  start_time = secs();
  do i = 1 by 1;
     delay (500);
     put skip list (i);
  end;

end handler; </lang>

PureBasic

This code is for Windows only due to the usage of SetConsoleCtrlHandler() <lang PureBasic>CompilerIf #PB_Compiler_OS<>#PB_OS_Windows

 CompilerError "This code is Windows only"

CompilerEndIf

Global Quit, i, T0=ElapsedMilliseconds(), T1

Procedure CtrlC()

 T1=ElapsedMilliseconds()
 Quit=1
 While i: Delay(1): Wend 

EndProcedure

If OpenConsole()

 SetConsoleCtrlHandler_(@CtrlC(),#True)  
 While Not Quit
   PrintN(Str(i))
   i+1
   Delay(500)
 Wend
 PrintN("Program has run for "+StrF((T1-T0)/1000,3)+" seconds.")
 Print ("Press ENTER to exit."):Input(): i=0

EndIf</lang>

0
1
2
3
4
Program has run for 2.121 seconds.
Press ENTER to exit.

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>

REXX

REXX has no SLEEP function that is built into the language.
Some operating systems that REXX runs under have a SLEEP or equivalent function.

But, there's more than one way to skin a cat. (No offense to cat lovers.) <lang> /*REXX program to display integers until a ctrl-C is pressed, then */ /* then show the number of seconds elapsed. */

call time 'E' /*reset the REXX elapsed timer. */ signal on halt /*HALT is signaled via a ctrl-C. */

 do j=1                     /*start with integer 1 and increment.  */
 say right(j,20)            /*display the integer right-justified. */
 t=time('E')                /*get the elapsed time in seconds.     */
   do forever
   u=time('E')
   if u<t |,                /*u<t ?   --- means we passed midnight.*/
      u>t+.5 then iterate j /*u>t+.5  --- means we passed 1/2 sec. */
   end
 end

say 'Should never never never get here, said Captain Dunsel.'


                            /*(below) show time with 2 decimal digs*/

halt: say 'program HALTed, it ran for' format(time("E"),,2) 'seconds.' </lang> Output:

                   1
                   2
                   3
                   4
                   5
                   6
                   7
                   8
                   9
                  10
                  11
                  12
                  13
                  14
                  15
                  16
                  17
                  18
                  19
                  20
                  21
                  22
^C
program HALTed, it ran for 11.53 seconds.

Some REXX don't show the

^C


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>

Tcl

Core Tcl does not have signal handling. However the Expect and TclX extension packages do.

Using Expect: <lang tcl>package require Expect

proc sigint_handler {} {

   puts "elapsed time: [expr {[clock seconds] - $::start_time}] seconds"
   set ::looping false

}

trap sigint_handler SIGINT

set start_time [clock seconds] set n 0 set looping true while {$looping} {

   puts [incr n]
   after 500

}</lang>

Similarly, with TclX: <lang tcl>package require Tclx

proc sigint_handler {} {

   puts "elapsed time: [expr {[clock seconds] - $::start_time}] seconds"
   set ::looping false

}

signal trap sigint sigint_handler

set start_time [clock seconds] set n 0 set looping true while {$looping} {

   puts [incr n]
   after 500

}</lang>

With TclX, you don't have to trap signals, you can convert the signal into a catchable error: <lang tcl>package require Tclx

signal error sigint

set start_time [clock seconds] set n 0 proc infinite_loop {} {

   while 1 { 
       puts [incr n]
       after 500 
   } 

} if {[catch infinite_loop out] != 0} {

   lassign $::errorCode class name msg
   if {$class eq "POSIX" && $name eq "SIG" && $msg eq "SIGINT"} {
       puts "elapsed time: [expr {[clock seconds] - $start_time}] seconds"
   } else {
       puts "infinite loop interrupted, but not on SIGINT: $::errorInfo"
   }

}</lang> With Tcl 8.6, that would be written as: <lang tcl>package require Tclx

signal error sigint

set start_time [clock seconds] proc infinite_loop {} {

   while 1 {
       puts [incr n]
       after 500
   }

} try {

   infinite_loop

} trap {POSIX SIG SIGINT} {} {

   puts "elapsed time: [expr {[clock seconds] - $start_time}] seconds"

}</lang> Note also that from 8.5 onwards, Tcl also has other mechanisms for delivering interrupt-like things, such as interpreter resource limits which permit stopping an execution after a set amount of time and returning control to a supervisor module. However, this is not driven by user interrupts and is so only tangential to this task.

X86 Assembly

Works with: NASM version Linux


Now, I realize linking to C libraries is somewhat cheating. It is entirely possible to do this entirely in syscalls using sys_nanosleep/sys_write but that would require allot more work, definition of the timespec structure among other things. <lang asm> %define sys_signal 48 %define SIGINT 2 %define sys_time 13

extern usleep extern printf

section .text global _start

_sig_handler: mov ebx, end_time mov eax, sys_time int 0x80 mov eax, dword [start_time] mov ebx, dword [end_time] sub ebx, eax mov ax, 100 div ebx push ebx push p_time call printf push 0x1 mov eax, 1 push eax int 0x80 ret

_start: mov ebx, start_time mov eax, sys_time int 0x80 mov ecx, _sig_handler mov ebx, SIGINT mov eax, sys_signal int 0x80 xor edi, edi .looper: push 500000 call usleep push edi push p_cnt call printf inc edi jmp .looper

section .data p_time db "The program has run for %d seconds.",13,10,0 p_cnt db "%d",13,10,0

section .bss start_time resd 1 end_time resd 1 </lang>

Zsh

<lang zsh>TRAPINT(){ print $n; exit } for (( n = 0; ; n++)) sleep 1</lang>