Handle a signal: Difference between revisions

From Rosetta Code
Content added Content deleted
imported>Nmz
 
(22 intermediate revisions by 16 users not shown)
Line 29: Line 29:
Ada signal handlers must be defined at the library level.
Ada signal handlers must be defined at the library level.
The following package defines a simple signal handler for the SigInt signal.
The following package defines a simple signal handler for the SigInt signal.
<lang ada>with Ada.Interrupts; use Ada.Interrupts;
<syntaxhighlight lang="ada">with Ada.Interrupts; use Ada.Interrupts;
with Ada.Interrupts.Names; use Ada.Interrupts.Names;
with Ada.Interrupts.Names; use Ada.Interrupts.Names;


Line 42: Line 42:
end Handler;
end Handler;


end Sigint_Handler;</lang>
end Sigint_Handler;</syntaxhighlight>
<lang ada>package body Sigint_Handler is
<syntaxhighlight lang="ada">package body Sigint_Handler is


-------------
-------------
Line 71: Line 71:
end Handler;
end Handler;


end Sigint_Handler;</lang>
end Sigint_Handler;</syntaxhighlight>
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.
<lang ada>with Ada.Calendar; use Ada.Calendar;
<syntaxhighlight lang="ada">with Ada.Calendar; use Ada.Calendar;
with Ada.Text_Io; use Ada.Text_Io;
with Ada.Text_Io; use Ada.Text_Io;
with Sigint_Handler; use Sigint_Handler;
with Sigint_Handler; use Sigint_Handler;
Line 109: Line 109:
null;
null;
end Signals;</lang>
end Signals;</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 124: Line 124:


=={{header|AutoHotkey}}==
=={{header|AutoHotkey}}==
<lang AutoHotkey>Start:=A_TickCount
<syntaxhighlight lang="autohotkey">Start:=A_TickCount
counter=0
counter=0
SetTimer, timer, 500
SetTimer, timer, 500
Line 138: Line 138:
Send, % "Task took " (A_TickCount-Start)/1000 " Seconds"
Send, % "Task took " (A_TickCount-Start)/1000 " Seconds"
ExitApp
ExitApp
return</lang>
return</syntaxhighlight>
{{out}}
{{out}}
<pre>1
<pre>1
Line 149: Line 149:


=={{header|BaCon}}==
=={{header|BaCon}}==
<lang freebasic>' Handle signal
<syntaxhighlight lang="freebasic">' Handle signal
SUB Finished
SUB Finished
SIGNAL SIG_DFL, SIGINT : ' Restore SIGINT to default
SIGNAL SIG_DFL, SIGINT : ' Restore SIGINT to default
Line 162: Line 162:
PRINT iter
PRINT iter
iter = iter + 1
iter = iter + 1
WEND</lang>
WEND</syntaxhighlight>


{{out}}
{{out}}
Line 175: Line 175:
This program runs only in console mode;
This program runs only in console mode;
it must be compiled and then run as an EXE.
it must be compiled and then run as an EXE.
<lang bbcbasic> REM!Exefile C:\bbcsigint.exe,encrypt,console
<syntaxhighlight lang="bbcbasic"> REM!Exefile C:\bbcsigint.exe,encrypt,console
INSTALL @lib$+"CALLBACK"
INSTALL @lib$+"CALLBACK"
CTRL_C_EVENT = 0
CTRL_C_EVENT = 0
Line 207: Line 207:
WHEN CTRL_C_EVENT: CtrlC% = TRUE : = 1
WHEN CTRL_C_EVENT: CtrlC% = TRUE : = 1
ENDCASE
ENDCASE
= 0</lang>
= 0</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 226: Line 226:


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.)
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>
<syntaxhighlight lang="c">#include <stdio.h>
#include <stdlib.h> // for exit()
#include <stdlib.h> // for exit()
#include <signal.h>
#include <signal.h>
Line 258: Line 258:
printf("Program has run for %5.3f seconds\n", td);
printf("Program has run for %5.3f seconds\n", td);
return 0;
return 0;
}</lang>
}</syntaxhighlight>


{{out}}
{{out}}
Line 271: Line 271:
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.
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
<syntaxhighlight lang="csharp">using System; //DateTime, Console, Environment classes
class Program
class Program
{
{
Line 293: Line 293:
Environment.Exit(0);
Environment.Exit(0);
}
}
}</lang>
}</syntaxhighlight>

=={{header|C++}}==
{{trans|C}}
<syntaxhighlight lang="cpp">#include <chrono>
#include <csignal>
#include <ctime>
#include <iostream>
#include <thread>

volatile sig_atomic_t gotint = 0;

void handler(int signum) {
// Set a flag for handling the signal, as other methods like printf are not safe here
gotint = 1;
}

int main() {
using namespace std;

signal(SIGINT, handler);

int i = 0;
clock_t startTime = clock();
while (true) {
if (gotint) break;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
if (gotint) break;
cout << ++i << endl;
}
clock_t endTime = clock();

double dt = (endTime - startTime) / (double)CLOCKS_PER_SEC;
cout << "Program has run for " << dt << " seconds" << endl;

return 0;
}</syntaxhighlight>


=={{header|Clojure}}==
=={{header|Clojure}}==
Line 299: Line 335:
<tt>(= (- Java verbosity) Clojure)</tt>
<tt>(= (- Java verbosity) Clojure)</tt>


<lang Clojure>(require 'clojure.repl)
<syntaxhighlight lang="clojure">(require 'clojure.repl)


(def start (System/nanoTime))
(def start (System/nanoTime))
Line 313: Line 349:
(doseq [i (range)]
(doseq [i (range)]
(prn i)
(prn i)
(Thread/sleep 500))</lang>
(Thread/sleep 500))</syntaxhighlight>


=={{header|COBOL}}==
=={{header|COBOL}}==
Works with GnuCOBOL 2.0
Works with GnuCOBOL 2.0
<lang cobol>
<syntaxhighlight lang="cobol">
identification division.
identification division.
program-id. signals.
program-id. signals.
Line 362: Line 398:
goback.
goback.
end program handle-sigint.
end program handle-sigint.
</syntaxhighlight>
</lang>


{{out}}
{{out}}
Line 380: Line 416:
The full list of signal number can be found on [https://en.wikipedia.org/wiki/Unix_signal#POSIX_signals].
The full list of signal number can be found on [https://en.wikipedia.org/wiki/Unix_signal#POSIX_signals].
Tested on SBCL 1.2.7 and ECL 13.5.1.
Tested on SBCL 1.2.7 and ECL 13.5.1.
<lang lisp>
<syntaxhighlight lang="lisp">
(ql:quickload :cffi)
(ql:quickload :cffi)


(defvar *SIGINT* 2)
(defconstant +SIGINT+ 2)


(defmacro set-signal-handler (signo &body body)
(defmacro set-signal-handler (signo &body body)
Line 395: Line 431:
(defvar *initial* (get-internal-real-time))
(defvar *initial* (get-internal-real-time))


(set-signal-handler *SIGINT*
(set-signal-handler +SIGINT+
(format t "Ran for ~a seconds~&" (/ (- (get-internal-real-time) *initial*) internal-time-units-per-second))
(format t "Ran for ~a seconds~&" (/ (- (get-internal-real-time) *initial*) internal-time-units-per-second))
(quit))
(quit))
Line 402: Line 438:
(loop do
(loop do
(format t "~a~&" (incf i))
(format t "~a~&" (incf i))
(sleep 0.5)
(sleep 0.5)))
</syntaxhighlight>
)
)

</lang>


{{out}}
{{out}}
Line 421: Line 454:
10
10
Ran for 4901/1000 seconds
Ran for 4901/1000 seconds
</pre>

=={{header|Crystal}}==
<syntaxhighlight lang="ruby">start = Time.utc
ch = Channel(Int32 | Symbol).new

spawn do
i = 0
loop do
sleep 1
ch.send(i += 1)
end
end

Signal::INT.trap do
Signal::INT.reset
ch.send(:kill)
end

loop do
x = ch.receive
break if x == :kill
puts x
end

elapsed = Time.utc - start
puts "Program has run for %5.3f seconds." % elapsed.total_seconds</syntaxhighlight>

<pre>
1
2
3
4
5
^CProgram has run for 5.093 seconds.
</pre>
</pre>


=={{header|D}}==
=={{header|D}}==
{{trans|C}}
{{trans|C}}
<lang D>import core.stdc.signal;
<syntaxhighlight lang="d">import core.stdc.signal;
import core.thread;
import core.thread;
import std.concurrency;
import std.concurrency;
Line 453: Line 521:
auto td = sw.peek();
auto td = sw.peek();
writeln("Program has run for ", td);
writeln("Program has run for ", td);
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>1
<pre>1
Line 465: Line 533:
9
9
Program has run for 5 secs, 4 ms, 357 ╬╝s, and 4 hnsecs</pre>
Program has run for 5 secs, 4 ms, 357 ╬╝s, and 4 hnsecs</pre>

=={{header|Erlang|escript}}==

<syntaxhighlight lang="erlang">#! /usr/bin/env escript

main([]) ->
erlang:unregister(erl_signal_server),
erlang:register(erl_signal_server, self()),
Start = seconds(),
os:set_signal(sigquit, handle),
Pid = spawn(fun() -> output_loop(1) end),
receive
{notify, sigquit} ->
erlang:exit(Pid, normal),
Seconds = seconds() - Start,
io:format("Program has run for ~b seconds~n", [Seconds])
end.

seconds() ->
calendar:datetime_to_gregorian_seconds({date(),time()}).

output_loop(N) ->
io:format("~b~n",[N]),
timer:sleep(500),
output_loop(N + 1).
</syntaxhighlight>

=={{header|F_Sharp|F#}}==
<syntaxhighlight 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()</syntaxhighlight>


=={{header|Forth}}==
=={{header|Forth}}==
Line 471: Line 582:
Normally Gforth handles most signals (e.g., the user interrupt SIGINT, or the segmentation violation SIGSEGV) by translating it into a Forth THROW.
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
<syntaxhighlight lang="forth">-28 constant SIGINT


: numbers ( n -- n' )
: numbers ( n -- n' )
Line 485: Line 596:
<# # # # # # # [char] . hold #s #> type ." seconds" ;
<# # # # # # # [char] . hold #s #> type ." seconds" ;


main bye</lang>
main bye</syntaxhighlight>


=={{header|F_Sharp|F#}}==
=={{header|Fortran}}==
{{Works with|gfortran}}
<lang fsharp>open System
Must be compiled with the <code>-fcoarray=single</code> flag to enable use of atomic operations.
<syntaxhighlight lang="fortran">program signal_handling
use, intrinsic :: iso_fortran_env, only: atomic_logical_kind
implicit none


interface
let rec loop n = Console.WriteLine( n:int )
integer(C_INT) function usleep(microseconds) bind(c)
Threading.Thread.Sleep( 500 )
use, intrinsic :: iso_c_binding, only: C_INT, C_INT32_T
loop (n + 1)
integer(C_INT32_T), value :: microseconds
end function usleep
end interface


integer, parameter :: half_second = 500000
let main() =
integer, parameter :: sigint = 2
let start = DateTime.Now
integer, parameter :: sigquit = 3
Console.CancelKeyPress.Add(

fun _ -> let span = DateTime.Now - start
logical(atomic_logical_kind) :: interrupt_received[*]
printfn "Program has run for %.0f seconds" span.TotalSeconds
integer :: half_seconds
)
logical :: interrupt_received_ref
loop 1

interrupt_received = .false.
half_seconds = 0

! "Install" the same signal handler for both SIGINT and SIGQUIT.
call signal(sigint, signal_handler)
call signal(sigquit, signal_handler)

! Indefinite loop (until one of the two signals are received).
do
if (usleep(half_second) == -1) &
print *, "Call to usleep interrupted."

call atomic_ref(interrupt_received_ref, interrupt_received)
if (interrupt_received_ref) then
print "(A,I0,A)", "Program ran for ", half_seconds / 2, " second(s)."
stop
end if

half_seconds = half_seconds + 1
print "(I0)", half_seconds
end do

contains

subroutine signal_handler(sig_num)
use, intrinsic :: iso_c_binding, only: C_INT
integer(C_INT), value, intent(in) :: sig_num
! Must be declared with attribute `value` to force pass-by-value semantics
! (what C uses by default).

select case (sig_num)
case (sigint)
print *, "Received SIGINT."
case (sigquit)
print *, "Received SIGQUIT."
end select

call atomic_define(interrupt_received, .true.)
end subroutine signal_handler

end program signal_handling</syntaxhighlight>

=={{header|FreeBASIC}}==
<syntaxhighlight lang="freebasic">Dim Shared As Double start
start = Timer

Dim As Integer n = 1
Dim As String s
Do
Print n
s = Inkey
If s = Chr(255) + "k" Then
Dim As Double elapsed = Timer- start + n * 0.5
Print Using "Program has run for & seconds."; elapsed
End
Else
Sleep 500, 1
n += 1
End If
Loop
</syntaxhighlight>


main()</lang>


=={{header|Gambas}}==
=={{header|Gambas}}==
<lang gambas>hTimer As Timer
<syntaxhighlight lang="gambas">hTimer As Timer
fTime As Float
fTime As Float


Line 535: Line 714:
fTime += 0.5
fTime += 0.5


End</lang>
End</syntaxhighlight>
Output:
Output:
<pre>
<pre>
Line 554: Line 733:


=={{header|Go}}==
=={{header|Go}}==
<lang go>package main
<syntaxhighlight lang="go">package main


import (
import (
Line 581: Line 760:
}
}
}
}
}</lang>
}</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 593: Line 772:
=={{header|Haskell}}==
=={{header|Haskell}}==


<lang haskell>import Prelude hiding (catch)
<syntaxhighlight lang="haskell">import Prelude hiding (catch)
import Control.Exception (catch, throwIO, AsyncException(UserInterrupt))
import Control.Exception (catch, throwIO, AsyncException(UserInterrupt))
import Data.Time.Clock (getCurrentTime, diffUTCTime)
import Data.Time.Clock (getCurrentTime, diffUTCTime)
Line 607: Line 786:
loop i = do print i
loop i = do print i
threadDelay 500000 {- µs -}
threadDelay 500000 {- µs -}
loop (i + 1)</lang>
loop (i + 1)</syntaxhighlight>


=={{header|HicEst}}==
=={{header|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:
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()
<syntaxhighlight lang="hicest">seconds = TIME()


DO i = 1, 1E100 ! "forever"
DO i = 1, 1E100 ! "forever"
Line 622: Line 801:
WRITE(Messagebox, Name) seconds
WRITE(Messagebox, Name) seconds
ALARM(999) ! quit immediately
ALARM(999) ! quit immediately
END</lang>
END</syntaxhighlight>


==Icon and {{header|Unicon}}==
==Icon and {{header|Unicon}}==
Line 628: Line 807:
The following works in Unicon. I don't know if it works in Icon.
The following works in Unicon. I don't know if it works in Icon.


<lang unicon>global startTime
<syntaxhighlight lang="unicon">global startTime


procedure main()
procedure main()
Line 638: Line 817:
procedure handler(s)
procedure handler(s)
stop("\n",&now-startTime," seconds")
stop("\n",&now-startTime," seconds")
end</lang>
end</syntaxhighlight>


Sample run:
Sample run:
Line 656: Line 835:
Use of sun.misc.SignalHandler allows one to specify which signal to catch, though is unsupported and potentially not available in all JVMs
Use of sun.misc.SignalHandler allows one to specify which signal to catch, though is unsupported and potentially not available in all JVMs


<lang java>import sun.misc.Signal;
<syntaxhighlight lang="java">import sun.misc.Signal;
import sun.misc.SignalHandler;
import sun.misc.SignalHandler;


Line 675: Line 854:
}
}
}
}
</syntaxhighlight>
</lang>


Or one can use a generic shutdown hook as follows, though a reference to the particular signal is not available.
Or one can use a generic shutdown hook as follows, though a reference to the particular signal is not available.


<lang java>public class ExampleSignalHandler {
<syntaxhighlight lang="java">public class ExampleSignalHandler {
public static void main(String... args) throws InterruptedException {
public static void main(String... args) throws InterruptedException {
final long start = System.nanoTime();
final long start = System.nanoTime();
Line 694: Line 873:
}
}
}
}
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 712: Line 891:
=={{header|JavaScript}}==
=={{header|JavaScript}}==
Based on NodeJS interpreter/engine
Based on NodeJS interpreter/engine
<lang javascript>(function(){
<syntaxhighlight lang="javascript">(function(){
var count=0
var count=0
secs=0
secs=0
Line 728: Line 907:
});
});
})();
})();
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<pre>
<pre>
Line 743: Line 922:
4.5 seconds elapsed
4.5 seconds elapsed
</pre>
</pre>

=={{header|Jsish}}==
<syntaxhighlight lang="javascript">/* Handle a signal, is jsish */

var gotime = strptime();
var looping = true;
var loops = 1;

function handler() {
printf("Elapsed time: %ds\n", (strptime() - gotime) / 1000);
looping = false;
}

Signal.callback(handler, 'SIGINT');
Signal.handle('SIGINT');

while (looping) {
puts(loops++);
Event.update(500);
}</syntaxhighlight>

''Event.update(500)'' causes the event loop to be monitored for 500 milliseconds, sleeping when there are no events to process for the given interval. 0 would return immediately.

{{out}}
<pre>prompt$ jsish
Jsish interactive: see 'help [cmd]'
# source('handle-signal.jsi');
1
2
3
4
5
^CElapsed time: 2s
# </pre>


=={{header|Julia}}==
=={{header|Julia}}==
<syntaxhighlight lang="julia">
ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 0)


function timeit()
<lang Julia>
ticks = 0
ccall(:jl_exit_on_sigint, Void, (Cint,), 0)
try
tic()
while true
ticks = 0
sleep(0.5)
try
ticks += 1
while true
sleep(0.5)
println(ticks)
ticks += 1
end
catch
println(ticks)
end
end
end
end
println()
toc()
</lang>
The tricky bit for this task is the <code>ccall</code>, which tells the <code>main()</code> running Julia to pass SIGINT on to Julia as an error. This call is not needed when running this code in Julia's REPL, which has the desired behavior by default.


@time timeit()
println("Done.")
</syntaxhighlight>
The tricky bit for this task is the <code>ccall</code>, which tells the <code>main()</code> running Julia to pass SIGINT on to Julia as an error. This call is not needed when running this code in Julia's REPL, which has the desired behavior by default.
{{out}}
{{out}}
<pre>
<pre>
Line 773: Line 988:
8
8
9
9
10
^C
11
elapsed time: 4.689995572 seconds
6.020844 seconds (32.06 k allocations: 1.658 MiB)
Done.
</pre>
</pre>


=={{header|Kotlin}}==
=={{header|Kotlin}}==
<lang scala>// version 1.1.3
<syntaxhighlight lang="scala">// version 1.1.3


import sun.misc.Signal
import sun.misc.Signal
Line 799: Line 1,016:
Thread.sleep(500)
Thread.sleep(500)
}
}
}</lang>
}</syntaxhighlight>


Sample output:
Sample output:
Line 818: Line 1,035:
</pre>
</pre>


=={{Header|Liberty BASIC}}==
=={{header|Liberty BASIC}}==
Liberty BASIC cannot react to a SigInt signal and truly kill itself. The best it can do is respond to Ctrl-C by exiting normally.
Liberty BASIC cannot react to a SigInt signal and truly kill itself. The best it can do is respond to Ctrl-C by exiting normally.
<syntaxhighlight lang="lb">
<lang lb>
nomainwin
nomainwin
WindowHeight=DisplayHeight
WindowHeight=DisplayHeight
Line 850: Line 1,067:
if sigCtrl=1 and Inkey$=chr$(3) then sigInt=1
if sigCtrl=1 and Inkey$=chr$(3) then sigInt=1
wait
wait
</lang>
</syntaxhighlight>
=={{header|Lua}}==
<syntaxhighlight lang="lua">
local start_date = os.time()


local loop = true
local Exit = function ()
print()
loop = false
end

local posix = require"posix"
posix.signal(posix.SIGINT, Exit)
posix.signal(posix.SIGQUIT, Exit)

local int = 0
while loop do
int = int+1
print(int)
posix.time.nanosleep{tv_sec=0,tv_nsec=500*1000*1000}
end

print(os.time() - start_date)
</syntaxhighlight>
{{out}}
=={{header|MATLAB}}==
=={{header|MATLAB}}==
MATLAB versions 6.5 (R13) and newer can no longer catch CTRL+C with a try-catch block. The onCleanup() function was introduced in version 7.6 (R2008a), possibly specifically for this situation. However, the designated onCleanup() function will execute no matter how the function ends (task completion, CTRL+C, exception), and CTRL+C will still cause an exception to be thrown and displayed.
MATLAB versions 6.5 (R13) and newer can no longer catch CTRL+C with a try-catch block. The onCleanup() function was introduced in version 7.6 (R2008a), possibly specifically for this situation. However, the designated onCleanup() function will execute no matter how the function ends (task completion, CTRL+C, exception), and CTRL+C will still cause an exception to be thrown and displayed.
{{works with|MATLAB|7.6 (R2008a) and later}}
{{works with|MATLAB|7.6 (R2008a) and later}}
<lang MATLAB>function sigintHandle
<syntaxhighlight lang="matlab">function sigintHandle
k = 1;
k = 1;
tic
tic
Line 864: Line 1,104:
k = k+1;
k = k+1;
end
end
end</lang>
end</syntaxhighlight>
{{out}}
{{out}}
<pre>>> sigintCleanup
<pre>>> sigintCleanup
Line 877: Line 1,117:
{{works with|MATLAB|6.1 (R12.1) and earlier}}
{{works with|MATLAB|6.1 (R12.1) and earlier}}
{{untested|MATLAB}}
{{untested|MATLAB}}
<lang MATLAB>function sigintHandle
<syntaxhighlight lang="matlab">function sigintHandle
k = 1;
k = 1;
tic
tic
Line 890: Line 1,130:
rethrow me
rethrow me
end
end
end</lang>
end</syntaxhighlight>


=={{header|NewLISP}}==
=={{header|NewLISP}}==
<lang NewLISP>; Mac OSX, BSDs or Linux only, not Windows
<syntaxhighlight lang="newlisp">; Mac OSX, BSDs or Linux only, not Windows
(setq start-time (now))
(setq start-time (now))


Line 904: Line 1,144:


(while (println (++ i))
(while (println (++ i))
(sleep 500))</lang>
(sleep 500))</syntaxhighlight>


=={{header|Nim}}==
=={{header|Nim}}==
<lang nim>import times, os, strutils
<syntaxhighlight lang="nim">import times, os, strutils


let t = epochTime()
let t = epochTime()
Line 917: Line 1,157:
setControlCHook(handler)
setControlCHook(handler)


for n in 1 .. <int64.high:
for n in 1 ..< int64.high:
sleep 500
sleep 500
echo n</lang>
echo n</syntaxhighlight>
Or if you prefer an exception to be thrown on SIGINT:
Or if you prefer an exception to be thrown on SIGINT:
<lang nim>import times, os, strutils
<syntaxhighlight lang="nim">import times, os, strutils


type EKeyboardInterrupt = object of Exception
type EKeyboardInterrupt = object of CatchableError


proc handler() {.noconv.} =
proc handler() {.noconv.} =
Line 933: Line 1,173:


try:
try:
for n in 1 .. <int64.high:
for n in 1 ..< int64.high:
sleep 500
sleep 500
echo n
echo n
except EKeyboardInterrupt:
except EKeyboardInterrupt:
echo "Program has run for ", formatFloat(epochTime() - t, precision = 0), " seconds."</lang>
echo "Program has run for ", formatFloat(epochTime() - t, precision = 0), " seconds."</syntaxhighlight>


=={{header|OCaml}}==
=={{header|OCaml}}==
OCaml's <tt>Unix.sleep</tt> doesn't handle non-integral arguments, so this program prints a number every second.
OCaml's <tt>Unix.sleep</tt> 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 *)
<syntaxhighlight lang="ocaml">#load "unix.cma";; (* for sleep and gettimeofday; not needed for the signals stuff per se *)


let start = Unix.gettimeofday ();;
let start = Unix.gettimeofday ();;
Line 957: Line 1,197:
loop (n + 1)
loop (n + 1)
in
in
loop 1;;</lang>
loop 1;;</syntaxhighlight>


=={{header|Perl}}==
=={{header|Perl}}==
Before version 5.8 <tt>sleep</tt> requires an integer argument, so we'll spin (There exist more obtuse methods)
Before version 5.8 <tt>sleep</tt> requires an integer argument, so we'll spin (There exist more obtuse methods)


<lang perl>
<syntaxhighlight lang="perl">
my $start = time; # seconds since epohc
my $start = time; # seconds since epohc
my $arlm=5; # every 5 seconds show how we're doing
my $arlm=5; # every 5 seconds show how we're doing
Line 983: Line 1,223:


print ( ++$i," \n");
print ( ++$i," \n");
}
}</syntaxhighlight>
^C to inerrupt, ^\ to quit, takes a break at 5 seconds
^C to inerrupt, ^\ to quit, takes a break at 5 seconds
1
1
Line 1,017: Line 1,257:


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


{{out}}
{{out}}
Line 1,042: Line 1,282:
^C interrupted after 5.23734092712402 seconds
^C interrupted after 5.23734092712402 seconds
</pre>
</pre>

=={{header|Perl 6}}==
We note with glee that the task does not require us to print <em>consecutive</em> integers, so we'll print Fibonacci numbers instead. <tt>:-)</tt>
<lang perl6>signal(SIGINT).tap: {
note "Took { now - INIT now } seconds.";
exit;
}

for 0, 1, *+* ... * {
sleep 0.5;
.say;
}</lang>
{{out}}
<pre>0
1
1
2
3
5
8
13
21
34
55
89
^CTook 6.3437449 seconds.
Aborted</pre>


=={{header|Phix}}==
=={{header|Phix}}==
See builtins\pbreak.e for the low-level (inline assembly) cross platform signal handler,
See builtins\pbreak.e for the low-level (inline assembly) cross platform signal handler,
and implementation of the standard hll allow_break() and check_break() routines
and implementation of the standard hll allow_break() and check_break() routines
<!--<syntaxhighlight lang="phix">(notonline)-->
<lang Phix>allow_break(false) -- by default Ctrl C terminates the program
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span>
puts(1,"Press Ctrl C\n")
<span style="color: #7060A8;">allow_break</span><span style="color: #0000FF;">(</span><span style="color: #004600;">false</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- by default Ctrl C terminates the program</span>
atom t = time()
<span style="color: #7060A8;">puts</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Press Ctrl C\n"</span><span style="color: #0000FF;">)</span>
integer i = 1
<span style="color: #004080;">atom</span> <span style="color: #000000;">t</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()</span>
while 1 do
<span style="color: #004080;">integer</span> <span style="color: #000000;">i</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
sleep(0.5)
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
?i
<span style="color: #7060A8;">sleep</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0.5</span><span style="color: #0000FF;">)</span>
if check_break() then exit end if
<span style="color: #0000FF;">?</span><span style="color: #000000;">i</span>
i += 1
<span style="color: #008080;">if</span> <span style="color: #7060A8;">check_break</span><span style="color: #0000FF;">()</span> <span style="color: #008080;">then</span> <span style="color: #008080;">exit</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end while
<span style="color: #000000;">i</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
printf(1,"The program has run for %3.2f seconds\n",{time()-t})</lang>
<span style="color: #008080;">end</span> <span style="color: #008080;">while</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"The program has run for %3.2f seconds\n"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t</span><span style="color: #0000FF;">})</span>
<!--</syntaxhighlight>-->
{{out}}
{{out}}
<pre>
<pre>
Line 1,095: Line 1,311:
=={{header|PHP}}==
=={{header|PHP}}==
{{trans|Perl}}
{{trans|Perl}}
<lang php><?php
<syntaxhighlight lang="php"><?php
declare(ticks = 1);
declare(ticks = 1);


$start = microtime(YES);
$start = microtime(true);


function mySigHandler() {
function mySigHandler() {
global $start;
global $start;
$elapsed = microtime(YES) - $start;
$elapsed = microtime(true) - $start;
echo "Ran for $elapsed seconds.\n";
echo "Ran for $elapsed seconds.\n";
exit();
exit();
Line 1,111: Line 1,327:
for ($n = 0; ; usleep(500000)) // 0.5 seconds
for ($n = 0; ; usleep(500000)) // 0.5 seconds
echo ++$n, "\n";
echo ++$n, "\n";
?></lang>
?></syntaxhighlight>


=={{header|PicoLisp}}==
=={{header|PicoLisp}}==
Put the following into a file, set it to executable, and run it
Put the following into a file, set it to executable, and run it
<lang PicoLisp>#!/usr/bin/picolisp /usr/lib/picolisp/lib.l
<syntaxhighlight lang="picolisp">#!/usr/bin/picolisp /usr/lib/picolisp/lib.l


(push '*Bye '(println (*/ (usec) 1000000)) '(prinl))
(push '*Bye '(println (*/ (usec) 1000000)) '(prinl))
Line 1,122: Line 1,338:
(loop
(loop
(println (inc 'Cnt))
(println (inc 'Cnt))
(wait 500) ) )</lang>
(wait 500) ) )</syntaxhighlight>


=={{header|PL/I}}==
=={{header|PL/I}}==
<lang>
<syntaxhighlight lang="text">
handler: procedure options (main);
handler: procedure options (main);
declare i fixed binary (31);
declare i fixed binary (31);
Line 1,141: Line 1,357:
end;
end;
end handler;
end handler;
</syntaxhighlight>
</lang>


=={{header|PowerShell}}==
=={{header|PowerShell}}==
<lang powershell>
<syntaxhighlight lang="powershell">
$Start_Time = (Get-date).second
$Start_Time = (Get-date).second
Write-Host "Type CTRL-C to Terminate..."
Write-Host "Type CTRL-C to Terminate..."
Line 1,163: Line 1,379:
Write-Host "Total time in seconds"$Time_Diff
Write-Host "Total time in seconds"$Time_Diff
}
}
</syntaxhighlight>
</lang>


{{Out}}
{{Out}}
Line 1,179: Line 1,395:
=={{header|PureBasic}}==
=={{header|PureBasic}}==
This code is for Windows only due to the usage of SetConsoleCtrlHandler()
This code is for Windows only due to the usage of SetConsoleCtrlHandler()
<lang PureBasic>CompilerIf #PB_Compiler_OS<>#PB_OS_Windows
<syntaxhighlight lang="purebasic">CompilerIf #PB_Compiler_OS<>#PB_OS_Windows
CompilerError "This code is Windows only"
CompilerError "This code is Windows only"
CompilerEndIf
CompilerEndIf
Line 1,200: Line 1,416:
PrintN("Program has run for "+StrF((T1-T0)/1000,3)+" seconds.")
PrintN("Program has run for "+StrF((T1-T0)/1000,3)+" seconds.")
Print ("Press ENTER to exit."):Input(): i=0
Print ("Press ENTER to exit."):Input(): i=0
EndIf</lang>
EndIf</syntaxhighlight>
<pre>0
<pre>0
1
1
Line 1,211: Line 1,427:
=={{header|Python}}==
=={{header|Python}}==
Simple version
Simple version
<lang python>import time
<syntaxhighlight lang="python">import time


def counter():
def counter():
Line 1,225: Line 1,441:
break
break


counter()</lang>
counter()</syntaxhighlight>
The following example should work on all platforms.
The following example should work on all platforms.
<lang python>import time
<syntaxhighlight lang="python">import time


def intrptWIN():
def intrptWIN():
Line 1,244: Line 1,460:
intrptWIN()
intrptWIN()
tdelt = time.time() - t1
tdelt = time.time() - t1
print 'Program has run for %5.3f seconds.' % tdelt</lang>
print 'Program has run for %5.3f seconds.' % tdelt</syntaxhighlight>


There is a signal module in the standard distribution
There is a signal module in the standard distribution
that accomodates the UNIX type signal mechanism.
that accomodates the UNIX type signal mechanism.
However the pause() mechanism is not implemented on Windows versions.
However the pause() mechanism is not implemented on Windows versions.
<lang python>import signal, time, threading
<syntaxhighlight lang="python">import signal, time, threading
done = False
done = False
n = 0
n = 0
Line 1,277: Line 1,493:
intrptUNIX()
intrptUNIX()
tdelt = time.time() - t1
tdelt = time.time() - t1
print 'Program has run for %5.3f seconds.' % tdelt</lang>
print 'Program has run for %5.3f seconds.' % tdelt</syntaxhighlight>


How about this one? It should work on all platforms;
How about this one? It should work on all platforms;
and it does show how to install a signal handler:
and it does show how to install a signal handler:
<lang python>import time, signal
<syntaxhighlight lang="python">import time, signal


class WeAreDoneException(Exception):
class WeAreDoneException(Exception):
Line 1,303: Line 1,519:


tdelt = time.time() - t1
tdelt = time.time() - t1
print 'Program has run for %5.3f seconds.' % tdelt</lang>
print 'Program has run for %5.3f seconds.' % tdelt</syntaxhighlight>


=={{header|Racket}}==
=={{header|Racket}}==
<lang racket>
<syntaxhighlight lang="racket">
#lang racket
#lang racket
(define now current-milliseconds)
(define now current-milliseconds)
Line 1,317: Line 1,533:
(displayln i)
(displayln i)
(sleep 0.5)))
(sleep 0.5)))
</syntaxhighlight>
</lang>
{{out}}
{{out}}
<lang racket>
<syntaxhighlight lang="racket">
0
0
1
1
Line 1,329: Line 1,545:
7
7
Total time: 3.965
Total time: 3.965
</syntaxhighlight>
</lang>

=={{header|Raku}}==
(formerly Perl 6)
We note with glee that the task does not require us to print <em>consecutive</em> integers, so we'll print Fibonacci numbers instead. <tt>:-)</tt>
<syntaxhighlight lang="raku" line>signal(SIGINT).tap: {
note "Took { now - INIT now } seconds.";
exit;
}

for 0, 1, *+* ... * {
sleep 0.5;
.say;
}</syntaxhighlight>
{{out}}
<pre>0
1
1
2
3
5
8
13
21
34
55
89
^CTook 6.3437449 seconds.
Aborted</pre>


=={{header|REXX}}==
=={{header|REXX}}==
Line 1,337: Line 1,581:


<br>But, there's more than one way to skin a cat. &nbsp; (No offense to cat lovers.)
<br>But, there's more than one way to skin a cat. &nbsp; (No offense to cat lovers.)
<lang rexx>/*REXX program displays integers until a Ctrl─C is pressed, then shows the number of */
<syntaxhighlight lang="rexx">/*REXX program displays integers until a Ctrl─C is pressed, then shows the number of */
/*────────────────────────────────── seconds that have elapsed since start of execution.*/
/*────────────────────────────────── seconds that have elapsed since start of execution.*/
call time 'Reset' /*reset the REXX elapsed timer. */
call time 'Reset' /*reset the REXX elapsed timer. */
Line 1,351: Line 1,595:


halt: say 'program HALTed, it ran for' format(time("ELapsed"),,2) 'seconds.'
halt: say 'program HALTed, it ran for' format(time("ELapsed"),,2) 'seconds.'
/*stick a fork in it, we're all done. */</lang>
/*stick a fork in it, we're all done. */</syntaxhighlight>
'''output'''
'''output'''
<pre>
<pre>
Line 1,389: Line 1,633:


=={{header|Ruby}}==
=={{header|Ruby}}==
<lang ruby>t1 = Time.now
<syntaxhighlight lang="ruby">t1 = Time.now


catch :done do
catch :done do
Line 1,405: Line 1,649:


tdelt = Time.now - t1
tdelt = Time.now - t1
puts 'Program has run for %5.3f seconds.' % tdelt</lang>
puts 'Program has run for %5.3f seconds.' % tdelt</syntaxhighlight>

=={{header|Rust}}==
<syntaxhighlight lang="rust">
#[cfg(unix)]
fn main() {
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::time::{Duration, Instant};

use libc::{sighandler_t, SIGINT};

// The time between ticks of our counter.
let duration = Duration::from_secs(1) / 2;

// "SIGINT received" global variable.
static mut GOT_SIGINT: AtomicBool = AtomicBool::new(false);

unsafe {
// Initially, "SIGINT received" is false.
GOT_SIGINT.store(false, Ordering::Release);
// Interrupt handler that handles the SIGINT signal
unsafe fn handle_sigint() {
// It is dangerous to perform any system calls in interrupts, so just set the atomic
// "SIGINT received" global to true when it arrives.
GOT_SIGINT.store(true, Ordering::Release);
}
// Make handle_sigint the signal handler for SIGINT.
libc::signal(SIGINT, handle_sigint as sighandler_t);
}

// Get the start time...
let start = Instant::now();

// Integer counter
let mut i = 0u32;

// Every `duration`...
loop {
thread::sleep(duration);

// Break if SIGINT was handled
if unsafe { GOT_SIGINT.load(Ordering::Acquire) } {
break;
}

// Otherwise, increment and display the integer and continue the loop.
i += 1;
println!("{}", i);
}

// Get the elapsed time.
let elapsed = start.elapsed();

// Print the difference and exit
println!("Program has run for {} seconds", elapsed.as_secs());
}

#[cfg(not(unix))]
fn main() {
println!("Not supported on this platform");
}

</syntaxhighlight>



=={{header|Scala}}==
=={{header|Scala}}==
{{libheader|Scala}}
{{libheader|Scala}}
<lang Scala>import sun.misc.Signal
<syntaxhighlight lang="scala">import sun.misc.Signal
import sun.misc.SignalHandler
import sun.misc.SignalHandler


Line 1,428: Line 1,736:
Thread.sleep(500)
Thread.sleep(500)
}
}
}</lang>
}</syntaxhighlight>


=={{header|Sidef}}==
=={{header|Sidef}}==
<lang ruby>var start = Time.sec;
<syntaxhighlight lang="ruby">var start = Time.sec

 
Sig.INT { |_|
Sig.INT {
Sys.say("Ran for #{Time.sec - start} seconds.");
say "Ran for #{Time.sec - start} seconds."
Sys.exit;
Sys.exit
}
}
 
{ |i|
Sys.say(i);
Sys.sleep(0.5);
} * Math.inf;</lang>


{ |i|
say i
Sys.sleep(0.5)
} * Inf</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>
Line 1,453: Line 1,760:


=={{header|Smalltalk}}==
=={{header|Smalltalk}}==
{{works with|Smalltalk/X}}<lang smalltalk>|n|
{{works with|Smalltalk/X}}<syntaxhighlight lang="smalltalk">|n|


n := 0.
n := 0.
Line 1,463: Line 1,770:
Delay waitForSeconds: 0.5.
Delay waitForSeconds: 0.5.
]
]
]</lang>
]</syntaxhighlight>
or:
or:
<lang smalltalk>[ ... do something... ] on: UserInterrupt do: [:exInfo | ...handler... ]</lang>
<syntaxhighlight lang="smalltalk">[ ... do something... ] on: UserInterrupt do: [:exInfo | ...handler... ]</syntaxhighlight>


attaching an OS-signal (unix signal) to an exception or signal instance:
attaching an OS-signal (unix signal) to an exception or signal instance:
<lang smalltalk>|mySignal|
<syntaxhighlight lang="smalltalk">|mySignal|
mySignal := Signal new mayProceed: false.
mySignal := Signal new mayProceed: false.
OperatingSytem operatingSystemSignal: (OperatingSystem signalNamed:'SIGHUP') install: mySignal.
OperatingSytem operatingSystemSignal: (OperatingSystem signalNamed:'SIGHUP') install: mySignal.
Line 1,475: Line 1,782:
] on: mySignal do:[
] on: mySignal do:[
... handle SIGHUP gracefully...
... handle SIGHUP gracefully...
]</lang>
]</syntaxhighlight>
As the runtime system already catches common unix signals
As the runtime system already catches common unix signals
and arranges for an OSError to be raised,
and arranges for an OSError to be raised,
Line 1,483: Line 1,790:
=={{header|Swift}}==
=={{header|Swift}}==
{{trans|C}}
{{trans|C}}
<lang swift>import Foundation
<syntaxhighlight lang="swift">import Foundation


let startTime = NSDate()
let startTime = NSDate()
Line 1,500: Line 1,807:
print("Program has run for \(endTime.timeIntervalSinceDate(startTime)) seconds")
print("Program has run for \(endTime.timeIntervalSinceDate(startTime)) seconds")


</syntaxhighlight>
</lang>


=={{header|Tcl}}==
=={{header|Tcl}}==
Line 1,507: Line 1,814:


Using Expect:
Using Expect:
<lang tcl>package require Expect
<syntaxhighlight lang="tcl">package require Expect


proc sigint_handler {} {
proc sigint_handler {} {
Line 1,522: Line 1,829:
puts [incr n]
puts [incr n]
after 500
after 500
}</lang>
}</syntaxhighlight>


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


proc sigint_handler {} {
proc sigint_handler {} {
Line 1,540: Line 1,847:
puts [incr n]
puts [incr n]
after 500
after 500
}</lang>
}</syntaxhighlight>


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


signal error sigint
signal error sigint
Line 1,563: Line 1,870:
puts "infinite loop interrupted, but not on SIGINT: $::errorInfo"
puts "infinite loop interrupted, but not on SIGINT: $::errorInfo"
}
}
}</lang>
}</syntaxhighlight>


With Tcl 8.6, that would be written as:
With Tcl 8.6, that would be written as:
<lang tcl>package require Tclx
<syntaxhighlight lang="tcl">package require Tclx


signal error sigint
signal error sigint
Line 1,581: Line 1,888:
} trap {POSIX SIG SIGINT} {} {
} trap {POSIX SIG SIGINT} {} {
puts "elapsed time: [expr {[clock seconds] - $start_time}] seconds"
puts "elapsed time: [expr {[clock seconds] - $start_time}] seconds"
}</lang>
}</syntaxhighlight>


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.
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.

=={{header|X86 Assembly}}==
{{works with|NASM|Linux}}<br>
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>



=={{header|TXR}}==
=={{header|TXR}}==


<lang txr>(set-sig-handler sig-int
<syntaxhighlight lang="txr">(set-sig-handler sig-int
(lambda (signum async-p)
(lambda (signum async-p)
(throwf 'error "caught signal ~s" signum)))
(throwf 'error "caught signal ~s" signum)))
Line 1,660: Line 1,905:
(let ((end-time (time)))
(let ((end-time (time)))
(format t "\n\n~a after ~s seconds of execution\n"
(format t "\n\n~a after ~s seconds of execution\n"
msg (- end-time start-time))))))</lang>
msg (- end-time start-time))))))</syntaxhighlight>


{{out|Run}}
{{out|Run}}
Line 1,690: Line 1,935:
that signals the shell every half a second.
that signals the shell every half a second.


<lang bash>c="1"
<syntaxhighlight lang="bash">c="1"
# Trap signals for SIGQUIT (3), SIGABRT (6) and SIGTERM (15)
# Trap signals for SIGQUIT (3), SIGABRT (6) and SIGTERM (15)
trap "echo -n 'We ran for ';echo -n `expr $c /2`; echo " seconds"; exit" 3 6 15
trap "echo -n 'We ran for ';echo -n `expr $c /2`; echo " seconds"; exit" 3 6 15
Line 1,696: Line 1,941:
# wait 0.5 # We need a helper program for the half second interval
# wait 0.5 # We need a helper program for the half second interval
c=`expr $c + 1`
c=`expr $c + 1`
done</lang>
done</syntaxhighlight>


{{works with|bash}}
{{works with|bash}}
Note that the following solution only works on systems
Note that the following solution only works on systems
that support a version of sleep that can handle non-integers.
that support a version of sleep that can handle non-integers.
<lang bash>
<syntaxhighlight lang="bash">
#!/bin/bash
#!/bin/bash
trap 'echo "Run for $((s/2)) seconds"; exit' 2
trap 'echo "Run for $((s/2)) seconds"; exit' 2
Line 1,712: Line 1,957:
let s++
let s++
done
done
</syntaxhighlight>
</lang>


{{out}}
{{out}}
Line 1,730: Line 1,975:
with a 5 tenths of a second timeout:
with a 5 tenths of a second timeout:


<lang bash>#!/bin/bash
<syntaxhighlight lang="bash">#!/bin/bash
trap 'echo "Run for $((s/2)) seconds"; exit' 2
trap 'echo "Run for $((s/2)) seconds"; exit' 2
s=1
s=1
Line 1,748: Line 1,993:
half_sec_sleep
half_sec_sleep
let s++
let s++
done</lang>
done</syntaxhighlight>


{{works with|zsh}}
{{works with|zsh}}
<lang bash>TRAPINT(){ print $n; exit }
<syntaxhighlight lang="bash">TRAPINT(){ print $n; exit }
for (( n = 0; ; n++)) sleep 1</lang>
for (( n = 0; ; n++)) sleep 1</syntaxhighlight>

=={{header|Visual Basic .NET}}==
{{trans|C#}}
<syntaxhighlight lang="vbnet">Module Module1
Dim startTime As Date

Sub Main()
startTime = Date.Now
' Add event handler for Cntrl+C command
AddHandler Console.CancelKeyPress, AddressOf Console_CancelKeyPress

Dim counter = 0
While True
counter += 1
Console.WriteLine(counter)
Threading.Thread.Sleep(500)
End While
End Sub

Sub Console_CancelKeyPress(sender As Object, e As ConsoleCancelEventArgs)
Dim stopTime = Date.Now
Console.WriteLine("This program ran for {0:000.000} seconds", (stopTime - startTime).TotalMilliseconds / 1000)
Environment.Exit(0)
End Sub

End Module</syntaxhighlight>


=={{header|Visual FoxPro}}==
=={{header|Visual FoxPro}}==
<lang vfp>
<syntaxhighlight lang="vfp">
*!* In VFP, Ctrl+C is normally used to copy text to the clipboard.
*!* In VFP, Ctrl+C is normally used to copy text to the clipboard.
*!* Esc is used to stop execution.
*!* Esc is used to stop execution.
Line 1,779: Line 2,050:
lLoop = .F.
lLoop = .F.
ENDPROC
ENDPROC
</syntaxhighlight>
</lang>

=={{header|Wren}}==
Note that Thread.sleep not only suspends the current fiber but also the System.clock method (possibly unintended). We therefore have to add back on the time slept.
<syntaxhighlight lang="wren">import "scheduler" for Scheduler
import "timer" for Timer
import "io" for Stdin

var start = System.clock
var stop = false

Scheduler.add {
var n = 0
while (true) {
System.print(n)
if (stop) {
var elapsed = System.clock - start + n * 0.5
System.print("Program has run for %(elapsed) seconds.")
return
}
Timer.sleep(500)
n = n + 1
}
}

Stdin.isRaw = true // enable control characters to go into stdin
while (true) {
var b = Stdin.readByte()
if (b == 3 || b == 28) break // quits on pressing either Ctrl-C os Ctrl-\
}
Stdin.isRaw = false
stop = true</syntaxhighlight>

{{out}}
Sample run:
<pre>
0
1
2
3
4
5
6
7
8
9
10
11
12
Program has run for 6.00173 seconds.
</pre>

=={{header|X86 Assembly}}==
{{works with|NASM|Linux}}<br>
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.
<syntaxhighlight 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
</syntaxhighlight>


=={{header|zkl}}==
=={{header|zkl}}==
SigInt is the only signal zkl brings out.
SigInt is the only signal zkl brings out.
<lang zkl>var t=Time.Clock.time;
<syntaxhighlight lang="zkl">var t=Time.Clock.time;
try{ n:=0; while(1){(n+=1).println(); Atomic.sleep(0.5)} }
try{ n:=0; while(1){(n+=1).println(); Atomic.sleep(0.5)} }
catch{ println("ran for ",Time.Clock.time-t," seconds"); System.exit() }</lang>
catch{ println("ran for ",Time.Clock.time-t," seconds"); System.exit() }</syntaxhighlight>
{{out}}
{{out}}
<pre>
<pre>

Latest revision as of 07:25, 28 December 2023

Task
Handle a signal
You are encouraged to solve this task according to the task description, using any language you may know.

Most operating systems provide interrupt facilities, sometimes called signals either generated by the user or as a result of program failure or reaching a limit like file space. 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.

Task

Provide a program that displays an integer on each line of output at the rate of about one per half second. Upon receipt of the SIGINT signal (often generated by the user typing ctrl-C ( or better yet, SIGQUIT ctrl-\ )) the program will cease outputting integers, output the number of seconds the program has run, and then the program will quit.

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.

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;
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;

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.

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;
Output:
 1
 2
 3
 4
 5
 6
 7
 8
Program execution took 4.348057086 seconds

AutoHotkey

Start:=A_TickCount
counter=0
SetTimer, timer, 500
return

timer:
Send % ++Counter "`n"
return

^c::
SetTimer, timer, off
SetFormat, float, 0.3
Send, % "Task took " (A_TickCount-Start)/1000 " Seconds"
ExitApp
return
Output:
1
2
3
4
5
6
Task took 3.526 Seconds

BaCon

' Handle signal
SUB Finished
    SIGNAL SIG_DFL, SIGINT    : ' Restore SIGINT to default
    PRINT "Running for", TIMER / 1000.0, "seconds" FORMAT "%s %f %s\n"
    STOP SIGINT               : ' Send another terminating SIGINT
ENDSUB

SIGNAL Finished, SIGINT
iter = 1
WHILE TRUE
    SLEEP 500
    PRINT iter
    iter = iter + 1
WEND
Output:
$ ./handle-signal
1
2
3
^CRunning for 1.766000 seconds

BBC BASIC

This program runs only in console mode; it must be compiled and then run as an EXE.

      REM!Exefile C:\bbcsigint.exe,encrypt,console
      INSTALL @lib$+"CALLBACK"
      CTRL_C_EVENT = 0
      
      SYS "GetStdHandle", -10 TO @hfile%(1)
      SYS "GetStdHandle", -11 TO @hfile%(2)
      *INPUT 13
      *OUTPUT 14
      ON ERROR PRINT REPORT$ : QUIT ERR
      
      CtrlC% = FALSE
      handler% = FN_callback(FNsigint(), 1)
      SYS FN_syscalls("SetConsoleCtrlHandler"), handler%, 1 TO !FN_systo(res%)
      IF res%=0 PRINT "Could not set SIGINT handler" : QUIT 1
      
      PRINT "Press Ctrl+C to test...."
      TIME = 0
      Time% = 50
      REPEAT
        WAIT 1
        IF TIME > Time% THEN
          PRINT Time%
          Time% += 50
        ENDIF
      UNTIL CtrlC%
      PRINT "Ctrl+C was pressed after "; TIME/100 " seconds."
      QUIT
      
      DEF FNsigint(T%)
      CASE T% OF
        WHEN CTRL_C_EVENT: CtrlC% = TRUE : = 1
      ENDCASE
      = 0
Output:
C:\>bbcsigint
Press Ctrl+C to test....
        50
       100
       150
       200
       250
Ctrl+C was pressed after 2.72 seconds.

C:\>

C

Library: 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.)

#include <stdio.h>
#include <stdlib.h>	// for exit()
#include <signal.h>
#include <time.h>	// for clock()
#include <unistd.h>	// for POSIX usleep()

volatile sig_atomic_t gotint = 0;

void handleSigint() {
    /*
     * Signal safety: It is not safe to call clock(), printf(),
     * or exit() inside a signal handler. Instead, we set a flag.
     */
    gotint = 1;
}
 
int main() {
    clock_t startTime = clock();
    signal(SIGINT, handleSigint);
    int i=0;
    for (;;) {
        if (gotint)
            break;
        usleep(500000);
        if (gotint)
            break;
	printf("%d\n", ++i);
    }
    clock_t endTime = clock();
    double td = (endTime - startTime) / (double)CLOCKS_PER_SEC;
    printf("Program has run for %5.3f seconds\n", td);
    return 0;
}
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.

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);
    }
}

C++

Translation of: C
#include <chrono>
#include <csignal>
#include <ctime>
#include <iostream>
#include <thread>

volatile sig_atomic_t gotint = 0;

void handler(int signum) {
	// Set a flag for handling the signal, as other methods like printf are not safe here
	gotint = 1;
}

int main() {
	using namespace std;

	signal(SIGINT, handler);

	int i = 0;
	clock_t startTime = clock();
	while (true) {
		if (gotint) break;
		std::this_thread::sleep_for(std::chrono::milliseconds(500));
		if (gotint) break;
		cout << ++i << endl;
	}
	clock_t endTime = clock();

	double dt = (endTime - startTime) / (double)CLOCKS_PER_SEC;
	cout << "Program has run for " << dt << " seconds" << endl;

	return 0;
}

Clojure

(= (- Java verbosity) Clojure)

(require 'clojure.repl)

(def start (System/nanoTime))

(defn shutdown [_]
  (println "Received INT after"
           (/ (- (System/nanoTime) start) 1e9)
           "seconds.")
  (System/exit 0))

(clojure.repl/set-break-handler! shutdown)

(doseq [i (range)]
  (prn i)
  (Thread/sleep 500))

COBOL

Works with GnuCOBOL 2.0

       identification division.
       program-id. signals.
       data division.
       working-storage section.
       01 signal-flag  pic 9 external.
          88 signalled value 1.
       01 half-seconds usage binary-long.
       01 start-time   usage binary-c-long.
       01 end-time     usage binary-c-long.
       01 handler      usage program-pointer.
       01 SIGINT       constant as 2.

       procedure division.
       call "gettimeofday" using start-time null
       set handler to entry "handle-sigint"
       call "signal" using by value SIGINT by value handler

       perform until exit
           if signalled then exit perform end-if
           call "CBL_OC_NANOSLEEP" using 500000000
           if signalled then exit perform end-if
           add 1 to half-seconds
           display half-seconds
       end-perform

       call "gettimeofday" using end-time null
       subtract start-time from end-time
       display "Program ran for " end-time " seconds"
       goback.
       end program signals.

       identification division.
       program-id. handle-sigint.
       data division.
       working-storage section.
       01 signal-flag  pic 9 external.

       linkage section.
       01 the-signal   usage binary-long.

       procedure division using by value the-signal returning omitted.
       move 1 to signal-flag
       goback.
       end program handle-sigint.
Output:
prompt$ cobc -x -j signals.cob
+0000000001
+0000000002
+0000000003
+0000000004
+0000000005
^CProgram ran for +00000000000000000002 seconds
prompt$

Common Lisp

Each Common Lisp implementation will handle signals differently, although a multi-implementation approach can be done using cffi. The full list of signal number can be found on [1]. Tested on SBCL 1.2.7 and ECL 13.5.1.

(ql:quickload :cffi)

(defconstant +SIGINT+ 2)

(defmacro set-signal-handler (signo &body body)
  (let ((handler (gensym "HANDLER")))
    `(progn
       (cffi:defcallback ,handler :void ((signo :int))
         (declare (ignore signo))
         ,@body)
       (cffi:foreign-funcall "signal" :int ,signo :pointer (cffi:callback ,handler)))))

(defvar *initial* (get-internal-real-time))

(set-signal-handler +SIGINT+
  (format t "Ran for ~a seconds~&" (/ (- (get-internal-real-time) *initial*) internal-time-units-per-second))
  (quit))

(let ((i 0))
  (loop do
    (format t "~a~&" (incf i))
    (sleep 0.5)))
Output:
1
2
3
4
5
6
7
8
9
10
Ran for 4901/1000 seconds

Crystal

start = Time.utc
ch = Channel(Int32 | Symbol).new

spawn do
  i = 0
  loop do
    sleep 1
    ch.send(i += 1)
  end
end

Signal::INT.trap do
  Signal::INT.reset
  ch.send(:kill)
end

loop do
  x = ch.receive
  break if x == :kill
  puts x
end

elapsed = Time.utc - start
puts "Program has run for %5.3f seconds." % elapsed.total_seconds
1
2
3
4
5
^CProgram has run for 5.093 seconds.

D

Translation of: C
import core.stdc.signal;
import core.thread;
import std.concurrency;
import std.datetime.stopwatch;
import std.stdio;

__gshared int gotint = 0;
extern(C) void handleSigint(int sig) nothrow @nogc @system {
    /*
     * Signal safety: It is not safe to call clock(), printf(),
     * or exit() inside a signal handler. Instead, we set a flag.
     */
    gotint = 1;
}

void main() {
    auto sw = StopWatch(AutoStart.yes);
    signal(SIGINT, &handleSigint);
    for (int i=0; !gotint;) {
        Thread.sleep(500_000.usecs);
        if (gotint) {
            break;
        }
        writeln(++i);
    }
    sw.stop();
    auto td = sw.peek();
    writeln("Program has run for ", td);
}
Output:
1
2
3
4
5
6
7
8
9
Program has run for 5 secs, 4 ms, 357 ╬╝s, and 4 hnsecs

Erlang

#! /usr/bin/env escript

main([]) ->
    erlang:unregister(erl_signal_server),
    erlang:register(erl_signal_server, self()),
    Start = seconds(),
    os:set_signal(sigquit, handle),
    Pid = spawn(fun() -> output_loop(1) end),
    receive
        {notify, sigquit} ->
            erlang:exit(Pid, normal),
            Seconds = seconds() - Start,
            io:format("Program has run for ~b seconds~n", [Seconds])
    end.

seconds() ->
    calendar:datetime_to_gregorian_seconds({date(),time()}).

output_loop(N) ->
    io:format("~b~n",[N]),
    timer:sleep(500),
    output_loop(N + 1).

F#

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()

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

Fortran

Works with: gfortran

Must be compiled with the -fcoarray=single flag to enable use of atomic operations.

program signal_handling
  use, intrinsic :: iso_fortran_env, only: atomic_logical_kind
  implicit none

  interface
    integer(C_INT) function usleep(microseconds) bind(c)
      use, intrinsic :: iso_c_binding, only: C_INT, C_INT32_T
      integer(C_INT32_T), value :: microseconds
    end function usleep
  end interface

  integer, parameter :: half_second = 500000
  integer, parameter :: sigint = 2
  integer, parameter :: sigquit = 3

  logical(atomic_logical_kind) :: interrupt_received[*]
  integer :: half_seconds
  logical :: interrupt_received_ref

  interrupt_received = .false.
  half_seconds = 0

  ! "Install" the same signal handler for both SIGINT and SIGQUIT.
  call signal(sigint, signal_handler)
  call signal(sigquit, signal_handler)

  ! Indefinite loop (until one of the two signals are received).
  do
    if (usleep(half_second) == -1) &
      print *, "Call to usleep interrupted."

    call atomic_ref(interrupt_received_ref, interrupt_received)
    if (interrupt_received_ref) then
      print "(A,I0,A)", "Program ran for ", half_seconds / 2, " second(s)."
      stop
    end if

    half_seconds = half_seconds + 1
    print "(I0)", half_seconds
  end do

contains

  subroutine signal_handler(sig_num)
    use, intrinsic :: iso_c_binding, only: C_INT
    integer(C_INT), value, intent(in) :: sig_num
    ! Must be declared with attribute `value` to force pass-by-value semantics
    ! (what C uses by default).

    select case (sig_num)
      case (sigint)
        print *, "Received SIGINT."
      case (sigquit)
        print *, "Received SIGQUIT."
    end select

    call atomic_define(interrupt_received, .true.)
  end subroutine signal_handler

end program signal_handling

FreeBASIC

Dim Shared As Double start
start = Timer

Dim As Integer n = 1
Dim As String s
Do	
    Print n
    s = Inkey
    If s = Chr(255) + "k" Then
        Dim As Double elapsed = Timer- start + n * 0.5
        Print Using "Program has run for & seconds."; elapsed
        End
    Else
        Sleep 500, 1
        n += 1
    End If
Loop


Gambas

hTimer As Timer
fTime As Float

Public Sub Application_Signal(x As Integer)

Print "Program stopped after " & fTime & " seconds"
Quit

End
 
Public Sub Main()
 
hTimer = New Timer As "IntTimer"

Print "Press [Ctrl] + " & Chr(92) & " to stop"

Signal[Signal.SIGQUIT].Catch
 
With hTimer
  .Delay = 500
  .Start
End With

End
 
Public Sub IntTimer_Timer()

Print Rand(0, 100)
fTime += 0.5

End

Output:

Press [Ctrl] + \ to stop
29
86
67
56
46
90
0
27
94
87
40
^\Program stopped after 5.5 seconds

Go

package main

import (
    "fmt"
    "os"
    "os/signal"
    "time"
)

func main() {
    start := time.Now()
    k := time.Tick(time.Second / 2)
    sc := make(chan os.Signal, 1)
    signal.Notify(sc, os.Interrupt)
    for n := 1; ; {
        // not busy waiting, this blocks until one of the two
        // channel operations is possible
        select {
        case <-k:
            fmt.Println(n)
            n++
        case <-sc:
            fmt.Printf("Ran for %f seconds.\n",
                time.Now().Sub(start).Seconds())
            return
        }
    }
}
Output:
1
2
3
^C
Ran for 1.804877 seconds.

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)

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:

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

Icon and Unicon

The following works in Unicon. I don't know if it works in Icon.

global startTime

procedure main()
    startTime := &now
    trap("SIGINT", handler)
    every write(seq()) do delay(500)
end

procedure handler(s)
    stop("\n",&now-startTime," seconds")
end

Sample run:

->signal
1
2
3
4
^C
2 seconds
->

Java

Use of sun.misc.SignalHandler allows one to specify which signal to catch, though is unsupported and potentially not available in all JVMs

import sun.misc.Signal;
import sun.misc.SignalHandler;

public class ExampleSignalHandler {
    public static void main(String... args) throws InterruptedException {
        final long start = System.nanoTime();
        Signal.handle(new Signal("INT"), new SignalHandler() {
            public void handle(Signal sig) {
                System.out.format("\nProgram execution took %f seconds\n", (System.nanoTime() - start) / 1e9f);
                System.exit(0);
            }
        });
        int counter = 0;
        while(true) {
            System.out.println(counter++);
            Thread.sleep(500);
        }
    }
}

Or one can use a generic shutdown hook as follows, though a reference to the particular signal is not available.

public class ExampleSignalHandler {
    public static void main(String... args) throws InterruptedException {
        final long start = System.nanoTime();
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            public void run() {
                System.out.format("\nProgram execution took %f seconds\n", (System.nanoTime() - start) / 1e9f);
            }
        }));
        int counter = 0;
        while(true) {
            System.out.println(counter++);
            Thread.sleep(500);
        }
    }
}
Output:
node hsignal.js
1
2
3
4
5
6
7
8
9
4.5 seconds elapsed

JavaScript

Based on NodeJS interpreter/engine

(function(){
    var count=0
        secs=0
    
    var i= setInterval( function (){
        count++
        secs+=0.5
        console.log(count)
    }, 500);
    
    process.on('SIGINT', function() {
        clearInterval(i)
        console.log(secs+' seconds elapsed');
        process.exit()
    });
})();
Output:
node hsignal.js
1
2
3
4
5
6
7
8
9
4.5 seconds elapsed

Jsish

/* Handle a signal, is jsish */

var gotime = strptime();
var looping = true;
var loops = 1;

function handler() {
    printf("Elapsed time: %ds\n", (strptime() - gotime) / 1000);
    looping = false;
}

Signal.callback(handler, 'SIGINT');
Signal.handle('SIGINT');

while (looping) {
    puts(loops++);
    Event.update(500);
}

Event.update(500) causes the event loop to be monitored for 500 milliseconds, sleeping when there are no events to process for the given interval. 0 would return immediately.

Output:
prompt$ jsish
Jsish interactive: see 'help [cmd]'
# source('handle-signal.jsi');
1
2
3
4
5
^CElapsed time: 2s
# 

Julia

ccall(:jl_exit_on_sigint, Cvoid, (Cint,), 0)

function timeit()
    ticks = 0
    try
        while true
            sleep(0.5)
            ticks += 1
            println(ticks)
        end
    catch
    end
end

@time timeit()
println("Done.")

The tricky bit for this task is the ccall, which tells the main() running Julia to pass SIGINT on to Julia as an error. This call is not needed when running this code in Julia's REPL, which has the desired behavior by default.

Output:
1
2
3
4
5
6
7
8
9
10
11
  6.020844 seconds (32.06 k allocations: 1.658 MiB)
Done.

Kotlin

// version 1.1.3

import sun.misc.Signal
import sun.misc.SignalHandler

fun main(args: Array<String>) {
    val startTime = System.currentTimeMillis()

    Signal.handle(Signal("INT"), object : SignalHandler {
        override fun handle(sig: Signal) {
            val elapsedTime = (System.currentTimeMillis() - startTime) / 1000.0
            println("\nThe program has run for $elapsedTime seconds")
            System.exit(0)
        }
    })

    var i = 0
    while(true) {  
        println(i++)      
        Thread.sleep(500)        
    }
}

Sample output:

0
1
2
3
4
5
6
7
8
9
10
^C
The program has run for 5.087 seconds

Liberty BASIC

Liberty BASIC cannot react to a SigInt signal and truly kill itself. The best it can do is respond to Ctrl-C by exiting normally.

nomainwin
WindowHeight=DisplayHeight
open "Handle a signal" for graphics as #1
#1 "trapclose [quit]"
#1 "down;setfocus;place 10 20"
#1 "\Press CTRL + C to stop."
#1 "when characterInput [keyPressed]"
start=time$("ms")
timer 500, [doPrint]
wait
[quit] close #1:end

[doPrint]
  if sigInt then
    timer 0
    #1 "\Seconds elapsed: ";(time$("ms")-start)/1000
   else
    i=i+1
    if i mod 20 = 0 then #1 "cls;place 10 20"
    #1 "\";i
  end if
  wait

[keyPressed]
  if len(Inkey$)>1 then
    if left$(Inkey$,1)=chr$(8) then sigCtrl=1 else sigCtrl=0
  end if
  if sigCtrl=1 and Inkey$=chr$(3) then sigInt=1
  wait

Lua

local start_date = os.time()

local loop = true
local Exit = function ()
	print()
	loop = false
end

local posix = require"posix"
posix.signal(posix.SIGINT, Exit)
posix.signal(posix.SIGQUIT, Exit)

local int = 0
while loop do
	int = int+1
	print(int)
	posix.time.nanosleep{tv_sec=0,tv_nsec=500*1000*1000}
end

print(os.time() - start_date)
Output:

MATLAB

MATLAB versions 6.5 (R13) and newer can no longer catch CTRL+C with a try-catch block. The onCleanup() function was introduced in version 7.6 (R2008a), possibly specifically for this situation. However, the designated onCleanup() function will execute no matter how the function ends (task completion, CTRL+C, exception), and CTRL+C will still cause an exception to be thrown and displayed.

Works with: MATLAB version 7.6 (R2008a) and later
function sigintHandle
    k = 1;
    tic
    catchObj = onCleanup(@toc);
    while true
        pause(0.5)
        fprintf('%d\n', k)
        k = k+1;
    end
end
Output:
>> sigintCleanup
1
2
3
4
5
6
Elapsed time is 3.348772 seconds.
??? Operation terminated by user during ==> sigintHandle at 6
Works with: MATLAB version 6.1 (R12.1) and earlier
This example is untested. Please check that it's correct, debug it as necessary, and remove this message.


function sigintHandle
    k = 1;
    tic
    try
        while true
            pause(0.5)
            fprintf('%d\n', k)
            k = k+1;
        end
    catch me
        toc
        rethrow me
    end
end

NewLISP

; Mac OSX, BSDs or Linux only, not Windows
(setq start-time (now))

(signal 2 (lambda()
            (println
             (format "Program has run for %d seconds"
                     (- (apply date-value (now))
                        (apply date-value start-time))))
            (exit 0)))

(while (println (++ i))
  (sleep 500))

Nim

import times, os, strutils

let t = epochTime()

proc handler() {.noconv.} =
  echo "Program has run for ", formatFloat(epochTime() - t, precision = 0), " seconds."
  quit 0

setControlCHook(handler)

for n in 1 ..< int64.high:
  sleep 500
  echo n

Or if you prefer an exception to be thrown on SIGINT:

import times, os, strutils

type EKeyboardInterrupt = object of CatchableError

proc handler() {.noconv.} =
  raise newException(EKeyboardInterrupt, "Keyboard Interrupt")

setControlCHook(handler)

let t = epochTime()

try:
  for n in 1 ..< int64.high:
    sleep 500
    echo n
except EKeyboardInterrupt:
  echo "Program has run for ", formatFloat(epochTime() - t, precision = 0), " seconds."

OCaml

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

#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;;

Perl

Before version 5.8 sleep requires an integer argument, so we'll spin (There exist more obtuse methods)

my $start = time;  # seconds since epohc
my $arlm=5;  # every 5 seconds show how we're doing
my $i;

$SIG{QUIT} = sub
   {print " Ran for ", time - $start, " seconds.\n"; die; };
$SIG{INT} = sub
   {print " Running for ", time - $start, " seconds.\n"; };
$SIG{ALRM} = sub
   {print " After $arlm  seconds i= $i. Executing for ",  time - $start, " seconds.\n";  alarm $arlm };


alarm $arlm;  # trigger ALaRM after we've run  for a while

print " ^C to inerrupt, ^\\ to quit, takes a break at $arlm seconds \n";

while ( 1 ) {
   for ( $w=11935000; $w--; $w>0 ){}; # spinning is bad, but hey it's only a demo

    print (  ++$i," \n");
            }
^C to inerrupt, ^\ to quit, takes a break at 5 seconds

1 2 ^C Running for 1 seconds. 3 4 ^C Running for 2 seconds. 5 6 7 ^C Running for 3 seconds. 8 9 10

After 5  seconds i= 10. Executing for 5 seconds.

11 12 13 14 15 16 17 18 19 20

After 5  seconds i= 20. Executing for 10 seconds.

21 22 ^\ Ran for 11 seconds. Died at 0.pl line 6..


This example does the required task:

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";
Output:
0
1
2
3
4
5
6
7
8
9
10
^C interrupted after 5.23734092712402 seconds

Phix

See builtins\pbreak.e for the low-level (inline assembly) cross platform signal handler, and implementation of the standard hll allow_break() and check_break() routines

without js
allow_break(false)   -- by default Ctrl C terminates the program
puts(1,"Press Ctrl C\n")
atom t = time()
integer i = 1
while 1 do
    sleep(0.5)
    ?i
    if check_break() then exit end if
    i += 1
end while
printf(1,"The program has run for %3.2f seconds\n",{time()-t})
Output:
Press Ctrl C
1
2
3
The program has run for 1.53 seconds

PHP

Translation of: Perl
<?php
declare(ticks = 1);

$start = microtime(true);

function mySigHandler() {
  global $start;
  $elapsed = microtime(true) - $start;
  echo "Ran for $elapsed seconds.\n";
  exit();
}

pcntl_signal(SIGINT, 'mySigHandler');

for ($n = 0; ; usleep(500000)) // 0.5 seconds
   echo ++$n, "\n";
?>

PicoLisp

Put the following into a file, set it to executable, and run it

#!/usr/bin/picolisp /usr/lib/picolisp/lib.l

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

(let Cnt 0
   (loop
      (println (inc 'Cnt))
      (wait 500) ) )

PL/I

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;

PowerShell

$Start_Time = (Get-date).second
Write-Host "Type CTRL-C to Terminate..."
$n = 1
Try
{
    While($true)
    {
        Write-Host $n
        $n ++
        Start-Sleep -m 500
    }
}
Finally
{
    $End_Time = (Get-date).second
    $Time_Diff = $End_Time - $Start_Time
    Write-Host "Total time in seconds"$Time_Diff
}
Output:
PS F:\> . .\signal.ps1
Type CTRL-C to Terminate...
1
2
3
4
5
Total time in seconds 2

PureBasic

This code is for Windows only due to the usage of SetConsoleCtrlHandler()

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
0
1
2
3
4
Program has run for 2.121 seconds.
Press ENTER to exit.

Python

Simple version

import time

def counter():
    n = 0
    t1 = time.time()
    while True:
        try:
            time.sleep(0.5)
            n += 1
            print n
        except KeyboardInterrupt, e:
            print 'Program has run for %5.3f seconds.' % (time.time() - t1)
            break

counter()

The following example should work on all platforms.

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

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.

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

How about this one? It should work on all platforms; and it does show how to install a signal handler:

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

Racket

#lang racket
(define now current-milliseconds)
(define start (now))
(with-handlers ([exn:break? 
                 (λ(x)
                   (define elapsed (/ (- (now) start) 1000.))
                   (displayln (~a "Total time: " elapsed)))])
  (for ([i (in-naturals)])
    (displayln i)
    (sleep 0.5)))
Output:
0
1
2
3
4
5
6
7
Total time: 3.965

Raku

(formerly Perl 6) We note with glee that the task does not require us to print consecutive integers, so we'll print Fibonacci numbers instead. :-)

signal(SIGINT).tap: {
    note "Took { now - INIT now } seconds.";
    exit;
}

for 0, 1, *+* ... * {
    sleep 0.5;
    .say;
}
Output:
0
1
1
2
3
5
8
13
21
34
55
89
^CTook 6.3437449 seconds.
Aborted

REXX

REXX has no   sleep   function that is built into the language.

Some operating systems that REXX runs under have a   SLEEP   or equivalent BIF.


But, there's more than one way to skin a cat.   (No offense to cat lovers.)

/*REXX program displays integers until a   Ctrl─C  is pressed, then shows the number of */
/*────────────────────────────────── seconds that have elapsed since start of execution.*/
call time 'Reset'                                /*reset the REXX elapsed timer.        */
signal on halt                                   /*HALT: signaled via a  Ctrl─C  in DOS.*/

   do j=1                                        /*start with  unity  and go ye forth.  */
   say right(j,20)                               /*display the integer right-justified. */
   t=time('E')                                   /*get the REXX elapsed time in seconds.*/
                do forever;   u=time('Elapsed')  /* "   "    "     "      "   "    "    */
                if u<t | u>t+.5  then iterate j  /* ◄═══ passed midnight or  ½  second. */
                end   /*forever*/
   end   /*j*/

halt: say  'program HALTed, it ran for'   format(time("ELapsed"),,2)     'seconds.'
                                                 /*stick a fork in it,  we're all done. */

output

                   1
                   2
                   3
                   4
                   5
                   6
                   7
                   8
                   9
                  10
                  11
                  12
                  13
                  14
                  15
                  16
                  17
                  18
                  19
                  20
                  21
                  22
^C                    ◄■■■■■■■■■■■■■ this where (and when) the user pressed the  Crtl-C  buttons.
program HALTed, it ran for 11.53 seconds.

Note: some REXX interpreters don't show the

^C

when   Ctrl-C   is pressed.

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

Rust

#[cfg(unix)]
fn main() {
    use std::sync::atomic::{AtomicBool, Ordering};
    use std::thread;
    use std::time::{Duration, Instant};

    use libc::{sighandler_t, SIGINT};

    // The time between ticks of our counter.
    let duration = Duration::from_secs(1) / 2;

    // "SIGINT received" global variable.
    static mut GOT_SIGINT: AtomicBool = AtomicBool::new(false);

    unsafe {
        // Initially, "SIGINT received" is false.
        GOT_SIGINT.store(false, Ordering::Release);
        // Interrupt handler that handles the SIGINT signal
        unsafe fn handle_sigint() {
            // It is dangerous to perform any system calls in interrupts, so just set the atomic
            // "SIGINT received" global to true when it arrives.
            GOT_SIGINT.store(true, Ordering::Release);
        }
        // Make handle_sigint the signal handler for SIGINT.
        libc::signal(SIGINT, handle_sigint as sighandler_t);
    }

    // Get the start time...
    let start = Instant::now();

    // Integer counter
    let mut i = 0u32;

    // Every `duration`...
    loop {
        thread::sleep(duration);

        // Break if SIGINT was handled
        if unsafe { GOT_SIGINT.load(Ordering::Acquire) } {
            break;
        }

        // Otherwise, increment and display the integer and continue the loop.
        i += 1;
        println!("{}", i);
    }

    // Get the elapsed time.
    let elapsed = start.elapsed();

    // Print the difference and exit
    println!("Program has run for {} seconds", elapsed.as_secs());
}

#[cfg(not(unix))]
fn main() {
    println!("Not supported on this platform");
}


Scala

Library: Scala
import sun.misc.Signal
import sun.misc.SignalHandler

object SignalHandl extends App {
  val start = System.nanoTime()
  var counter = 0

  Signal.handle(new Signal("INT"), new SignalHandler() {
    def handle(sig: Signal) {
      println(f"\nProgram execution took ${(System.nanoTime() - start) / 1e9f}%f seconds\n")
      exit(0)
    }
  })

  while (true) {
    counter += 1
    println(counter)
    Thread.sleep(500)
  }
}

Sidef

var start = Time.sec

Sig.INT {
    say "Ran for #{Time.sec - start} seconds."
    Sys.exit
}

{ |i|
    say i
    Sys.sleep(0.5)
} * Inf
Output:
1
2
3
4
^CRan for 2 seconds.

Smalltalk

Works with: Smalltalk/X
|n|

n := 0.
UserInterrupt 
     catch:[
         [true] whileTrue:[
             n := n + 1.
             n printCR.
             Delay waitForSeconds: 0.5.
         ]
     ]

or:

[ ... do something... ] on: UserInterrupt do: [:exInfo | ...handler... ]

attaching an OS-signal (unix signal) to an exception or signal instance:

|mySignal|
mySignal := Signal new mayProceed: false.
OperatingSytem operatingSystemSignal: (OperatingSystem signalNamed:'SIGHUP') install: mySignal.
[
   .. do something...
] on: mySignal do:[
   ... handle SIGHUP gracefully...
]

As the runtime system already catches common unix signals and arranges for an OSError to be raised, user code normally does not need to care for this (except for those who want to change that very runtime system behavior ;-).

Swift

Translation of: C
import Foundation

let startTime = NSDate()
var signalReceived: sig_atomic_t = 0

signal(SIGINT) { signal in signalReceived = 1 }

for var i = 0;; {
    if signalReceived == 1 { break }
    usleep(500_000)
    if signalReceived == 1 { break }
    print(++i)
}

let endTime = NSDate()
print("Program has run for \(endTime.timeIntervalSinceDate(startTime)) seconds")

Tcl

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

Using Expect:

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
}

Similarly, with TclX:

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
}

With TclX, you don't have to trap signals, you can convert the signal into a catchable error:

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"
    }
}

With Tcl 8.6, that would be written as:

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"
}

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.

TXR

(set-sig-handler sig-int
                 (lambda (signum async-p)
                   (throwf 'error "caught signal ~s" signum)))

(let ((start-time (time)))
  (catch (each ((num (range 1)))
           (format t "~s\n" num)
           (usleep 500000))
    (error (msg)
           (let ((end-time (time)))
             (format t "\n\n~a after ~s seconds of execution\n"
                     msg (- end-time start-time))))))
Run:
$ txr handle-a-signal.tl
1
2
3
4
5
6
7
8
9
10
11
12
^C

caught signal 2 after 6 seconds of execution

range generates a range of integers as a lazy list, which is infinite if the endpoint argument is omitted. We walk this infinite list using each like any other list.

UNIX Shell

The timing will drift with this example (because we need to consider processing time on top of the wait), but the task demonstrates signal handling. For a more accurate timer, we need to implement a signalling process that signals the shell every half a second.

c="1"
# Trap signals for SIGQUIT (3), SIGABRT (6) and SIGTERM (15)
trap "echo -n 'We ran for ';echo -n `expr $c /2`; echo " seconds"; exit" 3 6 15
while [ "$c" -ne 0 ]; do    # infinite loop
  # wait 0.5    # We need a helper program for the half second interval
  c=`expr $c + 1`
done
Works with: bash

Note that the following solution only works on systems that support a version of sleep that can handle non-integers.

#!/bin/bash
trap 'echo "Run for $((s/2)) seconds"; exit' 2
s=1

while true
do
  echo $s
  sleep .5
  let s++
done
Output:
1
2
3
4
5
^CRun for 2 seconds
Works with: bash

Here is a version of the above which assumes that there is a controlling tty device. It exploits the POSIX standard timeout feature of the tty line discipline. Instead of executing a sleep operation, we execute a terminal read with a 5 tenths of a second timeout:

#!/bin/bash
trap 'echo "Run for $((s/2)) seconds"; exit' 2
s=1

half_sec_sleep()
{
  local save_tty=$(stty -g)
  stty -icanon time 5 min 0
  read
  stty $save_tty
}


while true
do
  echo $s
  half_sec_sleep
  let s++
done
Works with: zsh
TRAPINT(){ print $n; exit }
for (( n = 0; ; n++)) sleep 1

Visual Basic .NET

Translation of: C#
Module Module1
    Dim startTime As Date

    Sub Main()
        startTime = Date.Now
        ' Add event handler for Cntrl+C command
        AddHandler Console.CancelKeyPress, AddressOf Console_CancelKeyPress

        Dim counter = 0
        While True
            counter += 1
            Console.WriteLine(counter)
            Threading.Thread.Sleep(500)
        End While
    End Sub

    Sub Console_CancelKeyPress(sender As Object, e As ConsoleCancelEventArgs)
        Dim stopTime = Date.Now
        Console.WriteLine("This program ran for {0:000.000} seconds", (stopTime - startTime).TotalMilliseconds / 1000)
        Environment.Exit(0)
    End Sub

End Module

Visual FoxPro

*!* In VFP, Ctrl+C is normally used to copy text to the clipboard.
*!* Esc is used to stop execution.
CLEAR
SET ESCAPE ON
ON ESCAPE DO StopLoop
CLEAR DLLS
DECLARE Sleep IN WIN32API INTEGER nMilliSeconds
lLoop = .T.
n = 0
? "Press Esc to Cancel..."
t1 = INT(SECONDS())
DO WHILE lLoop
	n = n + 1 
	? n
	Sleep(500)
ENDDO	
? "Elapsed time:", TRANSFORM(INT(SECONDS()) - t1) + " secs."
CLEAR DLLS
RETURN TO MASTER

PROCEDURE StopLoop
lLoop = .F.
ENDPROC

Wren

Note that Thread.sleep not only suspends the current fiber but also the System.clock method (possibly unintended). We therefore have to add back on the time slept.

import "scheduler" for Scheduler
import "timer" for Timer
import "io" for Stdin

var start = System.clock
var stop = false

Scheduler.add {
    var n = 0
    while (true) {
        System.print(n)
        if (stop) {
            var elapsed = System.clock - start + n * 0.5
            System.print("Program has run for %(elapsed) seconds.")
            return
        }
        Timer.sleep(500)
        n = n + 1
    }
}

Stdin.isRaw = true  // enable control characters to go into stdin
while (true) {
    var b = Stdin.readByte()
    if (b == 3 || b == 28) break  // quits on pressing either Ctrl-C os Ctrl-\
}
Stdin.isRaw = false
stop = true
Output:

Sample run:

0
1
2
3
4
5
6
7
8
9
10
11
12
Program has run for 6.00173 seconds.

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.

%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

zkl

SigInt is the only signal zkl brings out.

var t=Time.Clock.time;
try{ n:=0; while(1){(n+=1).println(); Atomic.sleep(0.5)} }
catch{ println("ran for ",Time.Clock.time-t," seconds"); System.exit() }
Output:
1
2
3
4
5
6
^C
ran for 2 seconds