Handle a signal: Difference between revisions
imported>Nmz (Lua →{{header|Lua}}) |
|||
(96 intermediate revisions by 48 users not shown) | |||
Line 1: | Line 1: | ||
{{task|Concurrency}} |
{{task|Concurrency}} |
||
{{requires|Signal handling}} |
|||
Most general purpose operating systems provide interrupt facilities, sometimes called signals. Unhandled signals generally terminate a program in a disorderly manner. Signal handlers are created so that the program behaves in a well-defined manner upon receipt of a signal. |
|||
[[Category:Signal handling]] |
|||
{{omit from|Erlang|Does not handle signals.}} |
|||
{{omit from|Batch File|"Pure" Batch files cannot really handle signals.}} |
|||
{{omit from|GUISS}} |
|||
{{omit from|M4}} |
|||
{{omit from|ML/I}} |
|||
{{omit from|Mathematica}} |
|||
{{omit from|PARI/GP}} |
|||
{{omit from|Retro}} |
|||
{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} |
|||
{{omit from|Unlambda|Does not handle signals.}} |
|||
{{omit from|XSLT}} |
|||
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: |
|||
For this task you will provide a program that displays a single integer on each line of output at the rate of one integer in each half second. Upon receipt of the SigInt signal (often created by the user typing ctrl-C) the program will cease printing integers to its output, print the number of seconds the program has run, and then the program will terminate. |
|||
Provide a program that displays an integer on each line of output at the rate of about one per half second. |
|||
<!-- some systems have difficulty with 1/2 second and that's not the point of this subject anyway DG--> |
|||
Upon receipt of the SIGINT signal (often generated by the user typing ctrl-C <!-- on unix see stty -a . on windows SIGBREAK DG -->( 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. <!-- outputting the number if seconds is also unduly complicated for this topic . Hope nobody minds these comments and I didn't really want to change the task since there were so many examples already written. see the Perl example for a more extensive use of signals. PS See discussion. If you find these edits inappropriate let me know DG--> |
|||
<br><br> |
|||
=={{header|Ada}}== |
=={{header|Ada}}== |
||
'''Signal Handler''' |
'''Signal Handler''' |
||
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. |
|||
<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 21: | Line 42: | ||
end Handler; |
end Handler; |
||
end Sigint_Handler;</ |
end Sigint_Handler;</syntaxhighlight> |
||
< |
<syntaxhighlight lang="ada">package body Sigint_Handler is |
||
------------- |
------------- |
||
Line 50: | Line 71: | ||
end Handler; |
end Handler; |
||
end Sigint_Handler;</ |
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. |
||
< |
<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 88: | Line 109: | ||
null; |
null; |
||
end Signals;</ |
end Signals;</syntaxhighlight> |
||
{{out}} |
|||
'''Sample Output''' |
|||
<pre> |
<pre> |
||
1 |
1 |
||
Line 101: | Line 122: | ||
Program execution took 4.348057086 seconds |
Program execution took 4.348057086 seconds |
||
</pre> |
</pre> |
||
=={{header|AutoHotkey}}== |
|||
<syntaxhighlight lang="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</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
6 |
|||
Task took 3.526 Seconds</pre> |
|||
=={{header|BaCon}}== |
|||
<syntaxhighlight lang="freebasic">' 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</syntaxhighlight> |
|||
{{out}} |
|||
<pre>$ ./handle-signal |
|||
1 |
|||
2 |
|||
3 |
|||
^CRunning for 1.766000 seconds</pre> |
|||
=={{header|BBC BASIC}}== |
=={{header|BBC BASIC}}== |
||
{{works with|BBC BASIC for Windows}} |
{{works with|BBC BASIC for Windows}} |
||
This program runs only in console mode; |
This program runs only in console mode; |
||
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 136: | Line 207: | ||
WHEN CTRL_C_EVENT: CtrlC% = TRUE : = 1 |
WHEN CTRL_C_EVENT: CtrlC% = TRUE : = 1 |
||
ENDCASE |
ENDCASE |
||
= 0</ |
= 0</syntaxhighlight> |
||
{{out}} |
|||
Output: |
|||
<pre> |
<pre> |
||
C:\>bbcsigint |
C:\>bbcsigint |
||
Line 155: | 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.) |
||
< |
<syntaxhighlight lang="c">#include <stdio.h> |
||
#include <stdlib.h> // for exit() |
#include <stdlib.h> // for exit() |
||
#include <signal.h> |
#include <signal.h> |
||
Line 187: | 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; |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
|||
Sample Output |
|||
<pre> |
<pre> |
||
1 |
1 |
||
Line 200: | 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. |
||
< |
<syntaxhighlight lang="csharp">using System; //DateTime, Console, Environment classes |
||
class Program |
class Program |
||
{ |
{ |
||
Line 222: | Line 293: | ||
Environment.Exit(0); |
Environment.Exit(0); |
||
} |
} |
||
}</ |
}</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}}== |
|||
<tt>(= (- Java verbosity) Clojure)</tt> |
|||
<syntaxhighlight lang="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))</syntaxhighlight> |
|||
=={{header|COBOL}}== |
|||
Works with GnuCOBOL 2.0 |
|||
<syntaxhighlight lang="cobol"> |
|||
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. |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
prompt$ cobc -x -j signals.cob |
|||
+0000000001 |
|||
+0000000002 |
|||
+0000000003 |
|||
+0000000004 |
|||
+0000000005 |
|||
^CProgram ran for +00000000000000000002 seconds |
|||
prompt$ |
|||
</pre> |
|||
=={{header|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 [https://en.wikipedia.org/wiki/Unix_signal#POSIX_signals]. |
|||
Tested on SBCL 1.2.7 and ECL 13.5.1. |
|||
<syntaxhighlight lang="lisp"> |
|||
(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))) |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
6 |
|||
7 |
|||
8 |
|||
9 |
|||
10 |
|||
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> |
|||
=={{header|D}}== |
|||
{{trans|C}} |
|||
<syntaxhighlight lang="d">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); |
|||
}</syntaxhighlight> |
|||
{{out}} |
|||
<pre>1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
6 |
|||
7 |
|||
8 |
|||
9 |
|||
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 229: | 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. |
||
< |
<syntaxhighlight lang="forth">-28 constant SIGINT |
||
: numbers ( n -- n' ) |
: numbers ( n -- n' ) |
||
Line 243: | Line 596: | ||
<# # # # # # # [char] . hold #s #> type ." seconds" ; |
<# # # # # # # [char] . hold #s #> type ." seconds" ; |
||
main bye</ |
main bye</syntaxhighlight> |
||
=={{header| |
=={{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 |
|||
printfn "Program has run for %.0f seconds" span.TotalSeconds |
|||
) |
|||
loop 1 |
|||
logical(atomic_logical_kind) :: interrupt_received[*] |
|||
main()</lang> |
|||
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</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> |
|||
=={{header|Gambas}}== |
|||
<syntaxhighlight lang="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</syntaxhighlight> |
|||
Output: |
|||
<pre> |
|||
Press [Ctrl] + \ to stop |
|||
29 |
|||
86 |
|||
67 |
|||
56 |
|||
46 |
|||
90 |
|||
0 |
|||
27 |
|||
94 |
|||
87 |
|||
40 |
|||
^\Program stopped after 5.5 seconds |
|||
</pre> |
|||
=={{header|Go}}== |
=={{header|Go}}== |
||
< |
<syntaxhighlight lang="go">package main |
||
import ( |
import ( |
||
Line 274: | Line 744: | ||
func main() { |
func main() { |
||
start := time.Now() |
start := time.Now() |
||
k := time. |
k := time.Tick(time.Second / 2) |
||
sc := make(chan os.Signal, 1) |
sc := make(chan os.Signal, 1) |
||
signal.Notify(sc, os.Interrupt) |
signal.Notify(sc, os.Interrupt) |
||
Line 281: | Line 751: | ||
// channel operations is possible |
// channel operations is possible |
||
select { |
select { |
||
case <-k |
case <-k: |
||
fmt.Println(n) |
fmt.Println(n) |
||
n++ |
n++ |
||
Line 290: | Line 760: | ||
} |
} |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
Line 302: | Line 772: | ||
=={{header|Haskell}}== |
=={{header|Haskell}}== |
||
< |
<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 316: | Line 786: | ||
loop i = do print i |
loop i = do print i |
||
threadDelay 500000 {- µs -} |
threadDelay 500000 {- µs -} |
||
loop (i + 1)</ |
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: |
||
< |
<syntaxhighlight lang="hicest">seconds = TIME() |
||
DO i = 1, 1E100 ! "forever" |
DO i = 1, 1E100 ! "forever" |
||
Line 331: | Line 801: | ||
WRITE(Messagebox, Name) seconds |
WRITE(Messagebox, Name) seconds |
||
ALARM(999) ! quit immediately |
ALARM(999) ! quit immediately |
||
END</ |
END</syntaxhighlight> |
||
==Icon and {{header|Unicon}}== |
|||
The following works in Unicon. I don't know if it works in Icon. |
|||
<syntaxhighlight lang="unicon">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</syntaxhighlight> |
|||
Sample run: |
|||
<pre> |
|||
->signal |
|||
1 |
|||
2 |
|||
3 |
|||
4 |
|||
^C |
|||
2 seconds |
|||
-> |
|||
</pre> |
|||
=={{header|Java}}== |
=={{header|Java}}== |
||
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 |
||
< |
<syntaxhighlight lang="java">import sun.misc.Signal; |
||
import sun.misc.SignalHandler; |
import sun.misc.SignalHandler; |
||
Line 355: | 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. |
||
< |
<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 374: | Line 873: | ||
} |
} |
||
} |
} |
||
</syntaxhighlight> |
|||
</lang> |
|||
{{out}} |
|||
<pre> |
|||
node hsignal.js |
|||
1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
6 |
|||
7 |
|||
8 |
|||
9 |
|||
4.5 seconds elapsed |
|||
</pre> |
|||
=={{header|JavaScript}}== |
|||
Based on NodeJS interpreter/engine |
|||
<syntaxhighlight lang="javascript">(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() |
|||
}); |
|||
})(); |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
node hsignal.js |
|||
1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
6 |
|||
7 |
|||
8 |
|||
9 |
|||
4.5 seconds elapsed |
|||
</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}}== |
|||
<syntaxhighlight lang="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.") |
|||
</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}} |
|||
<pre> |
|||
1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
6 |
|||
7 |
|||
8 |
|||
9 |
|||
10 |
|||
11 |
|||
6.020844 seconds (32.06 k allocations: 1.658 MiB) |
|||
Done. |
|||
</pre> |
|||
=={{header|Kotlin}}== |
|||
<syntaxhighlight lang="scala">// 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) |
|||
} |
|||
}</syntaxhighlight> |
|||
Sample output: |
|||
<pre> |
|||
0 |
|||
1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
6 |
|||
7 |
|||
8 |
|||
9 |
|||
10 |
|||
^C |
|||
The program has run for 5.087 seconds |
|||
</pre> |
|||
=={{ |
=={{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 408: | 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 |
||
</ |
</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}}== |
|||
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}} |
|||
<syntaxhighlight lang="matlab">function sigintHandle |
|||
k = 1; |
|||
tic |
|||
catchObj = onCleanup(@toc); |
|||
while true |
|||
pause(0.5) |
|||
fprintf('%d\n', k) |
|||
k = k+1; |
|||
end |
|||
end</syntaxhighlight> |
|||
{{out}} |
|||
<pre>>> sigintCleanup |
|||
1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
6 |
|||
Elapsed time is 3.348772 seconds. |
|||
??? Operation terminated by user during ==> sigintHandle at 6</pre> |
|||
{{works with|MATLAB|6.1 (R12.1) and earlier}} |
|||
{{untested|MATLAB}} |
|||
<syntaxhighlight lang="matlab">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</syntaxhighlight> |
|||
=={{header|NewLISP}}== |
|||
<syntaxhighlight lang="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))</syntaxhighlight> |
|||
=={{header|Nim}}== |
|||
<syntaxhighlight lang="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</syntaxhighlight> |
|||
Or if you prefer an exception to be thrown on SIGINT: |
|||
<syntaxhighlight lang="nim">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."</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. |
||
< |
<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 428: | Line 1,197: | ||
loop (n + 1) |
loop (n + 1) |
||
in |
in |
||
loop 1;;</ |
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) |
|||
Perl's (in fact Unix's) <tt>sleep</tt> doesn't handle non-integral arguments correctly on some platforms, so this program uses the select syscall for timeout. |
|||
<lang |
<syntaxhighlight lang="perl"> |
||
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 |
$SIG{INT} = sub |
||
{print |
{print " Running for ", time - $start, " seconds.\n"; }; |
||
$SIG{ALRM} = sub |
|||
exit;}; |
|||
{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"); |
|||
}</syntaxhighlight> |
|||
^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.. |
|||
for (my $n = 0 ;; select(undef, undef, undef, .5)) |
|||
{print ++$n, "\n";}</lang> |
|||
This example does the required task: |
This example does the required task: |
||
< |
<syntaxhighlight lang="perl">use 5.010; |
||
use AnyEvent; |
use AnyEvent; |
||
my $start = AE::time; |
my $start = AE::time; |
||
Line 451: | 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";</ |
say " interrupted after ", AE::time - $start, " seconds";</syntaxhighlight> |
||
{{out}} |
|||
Sample output: |
|||
<pre> |
<pre> |
||
0 |
0 |
||
Line 467: | Line 1,281: | ||
10 |
10 |
||
^C interrupted after 5.23734092712402 seconds |
^C interrupted after 5.23734092712402 seconds |
||
</pre> |
|||
=={{header|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 |
|||
<!--<syntaxhighlight lang="phix">(notonline)--> |
|||
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> |
|||
<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> |
|||
<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> |
|||
<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> |
|||
<span style="color: #004080;">integer</span> <span style="color: #000000;">i</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span> |
|||
<span style="color: #008080;">while</span> <span style="color: #000000;">1</span> <span style="color: #008080;">do</span> |
|||
<span style="color: #7060A8;">sleep</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0.5</span><span style="color: #0000FF;">)</span> |
|||
<span style="color: #0000FF;">?</span><span style="color: #000000;">i</span> |
|||
<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> |
|||
<span style="color: #000000;">i</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span> |
|||
<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}} |
|||
<pre> |
|||
Press Ctrl C |
|||
1 |
|||
2 |
|||
3 |
|||
The program has run for 1.53 seconds |
|||
</pre> |
</pre> |
||
=={{header|PHP}}== |
=={{header|PHP}}== |
||
{{trans|Perl}} |
{{trans|Perl}} |
||
< |
<syntaxhighlight lang="php"><?php |
||
declare(ticks = 1); |
declare(ticks = 1); |
||
$start = microtime( |
$start = microtime(true); |
||
function mySigHandler() { |
function mySigHandler() { |
||
global $start; |
global $start; |
||
$elapsed = microtime( |
$elapsed = microtime(true) - $start; |
||
echo "Ran for $elapsed seconds.\n"; |
echo "Ran for $elapsed seconds.\n"; |
||
exit(); |
exit(); |
||
Line 487: | 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"; |
||
?></ |
?></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 |
||
< |
<syntaxhighlight lang="picolisp">#!/usr/bin/picolisp /usr/lib/picolisp/lib.l |
||
(push '*Bye '(println (*/ (usec) 1000000)) '(prinl)) |
(push '*Bye '(println (*/ (usec) 1000000)) '(prinl)) |
||
Line 498: | Line 1,338: | ||
(loop |
(loop |
||
(println (inc 'Cnt)) |
(println (inc 'Cnt)) |
||
(wait 500) ) )</ |
(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 517: | Line 1,357: | ||
end; |
end; |
||
end handler; |
end handler; |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header|PowerShell}}== |
|||
<syntaxhighlight lang="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 |
|||
} |
|||
</syntaxhighlight> |
|||
{{Out}} |
|||
<pre> |
|||
PS F:\> . .\signal.ps1 |
|||
Type CTRL-C to Terminate... |
|||
1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
Total time in seconds 2 |
|||
</pre> |
|||
=={{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() |
||
< |
<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 541: | 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</ |
EndIf</syntaxhighlight> |
||
<pre>0 |
<pre>0 |
||
1 |
1 |
||
Line 551: | Line 1,426: | ||
=={{header|Python}}== |
=={{header|Python}}== |
||
Simple version |
|||
<syntaxhighlight lang="python">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()</syntaxhighlight> |
|||
The following example should work on all platforms. |
The following example should work on all platforms. |
||
< |
<syntaxhighlight lang="python">import time |
||
def intrptWIN(): |
def intrptWIN(): |
||
Line 569: | Line 1,460: | ||
intrptWIN() |
intrptWIN() |
||
tdelt = time.time() - t1 |
tdelt = time.time() - t1 |
||
print 'Program has run for %5.3f seconds.' % tdelt</ |
print 'Program has run for %5.3f seconds.' % tdelt</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. |
|||
signal mechanism. However the pause() mechanism is not implemented |
|||
on Windows versions. |
However the pause() mechanism is not implemented on Windows versions. |
||
< |
<syntaxhighlight lang="python">import signal, time, threading |
||
done = False |
done = False |
||
n = 0 |
n = 0 |
||
Line 602: | Line 1,493: | ||
intrptUNIX() |
intrptUNIX() |
||
tdelt = time.time() - t1 |
tdelt = time.time() - t1 |
||
print 'Program has run for %5.3f seconds.' % tdelt</ |
print 'Program has run for %5.3f seconds.' % tdelt</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: |
|||
<lang python>import time, signal |
|||
<syntaxhighlight lang="python">import time, signal |
|||
class WeAreDoneException(Exception): |
class WeAreDoneException(Exception): |
||
Line 627: | Line 1,519: | ||
tdelt = time.time() - t1 |
tdelt = time.time() - t1 |
||
print 'Program has run for %5.3f seconds.' % tdelt</ |
print 'Program has run for %5.3f seconds.' % tdelt</syntaxhighlight> |
||
=={{header|Racket}}== |
|||
<syntaxhighlight lang="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))) |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<syntaxhighlight lang="racket"> |
|||
0 |
|||
1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
6 |
|||
7 |
|||
Total time: 3.965 |
|||
</syntaxhighlight> |
|||
=={{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}}== |
||
REXX has no |
REXX has no '''sleep''' function that is built into the language. |
||
<br>Some operating systems that REXX runs under have a '''SLEEP''' or equivalent function. |
|||
<br><br>But, there's more than one way to skin a cat. (No offense to cat lovers.) |
|||
<lang>/*REXX program displays integers until a Ctrl─C is pressed, then show*/ |
|||
/* the number of seconds that have elapsed since start of pgm execution.*/ |
|||
Some operating systems that REXX runs under have a '''SLEEP''' or equivalent BIF. |
|||
call time 'E' /*reset the REXX elapsed timer. */ |
|||
signal on halt /*HALT is signaled via a Ctrl─C.*/ |
|||
<br>But, there's more than one way to skin a cat. (No offense to cat lovers.) |
|||
do j=1 /*start with 1 and go ye forth. */ |
|||
<syntaxhighlight lang="rexx">/*REXX program displays integers until a Ctrl─C is pressed, then shows the number of */ |
|||
say right(j,20) /*display integer right-justified*/ |
|||
/*────────────────────────────────── seconds that have elapsed since start of execution.*/ |
|||
t=time('E') /*get the elapsed time in seconds*/ |
|||
call time 'Reset' /*reset the REXX elapsed timer. */ |
|||
signal on halt /*HALT: signaled via a Ctrl─C in DOS.*/ |
|||
u>t+.5 then iterate j /* ◄═══ means we passed ½ second.*/ |
|||
end /*forever*/ |
|||
end /*j*/ |
|||
do j=1 /*start with unity and go ye forth. */ |
|||
say 'Program control should never ever get here, said Captain Dunsel.' |
|||
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.' |
|||
/*──────────────────────────────────HALT subroutine─────────────────────*/ |
|||
/*stick a fork in it, we're all done. */</syntaxhighlight> |
|||
halt: say 'program HALTed, it ran for' format(time("E"),,2) 'seconds.' |
|||
/*stick a fork in it, we're done.*/</lang> |
|||
'''output''' |
'''output''' |
||
<pre> |
|||
<pre style="overflow:scroll"> |
|||
1 |
1 |
||
2 |
2 |
||
Line 677: | Line 1,620: | ||
21 |
21 |
||
22 |
22 |
||
^C ◄■■■■■■■■■■■■■ this where (and when) the user pressed the Crtl-C buttons. |
|||
^C |
|||
program HALTed, it ran for 11.53 seconds. |
program HALTed, it ran for 11.53 seconds. |
||
</pre> |
</pre> |
||
Note: some REXX interpreters don't show the |
Note: some REXX interpreters don't show the |
||
<b> |
|||
<pre> |
<pre> |
||
^C |
^C |
||
</pre> |
</pre> |
||
</b> |
|||
when <big> Ctrl-C </big> is pressed. |
|||
<br><br> |
|||
=={{header|Ruby}}== |
=={{header|Ruby}}== |
||
< |
<syntaxhighlight lang="ruby">t1 = Time.now |
||
catch :done do |
catch :done do |
||
Line 702: | Line 1,649: | ||
tdelt = Time.now - t1 |
tdelt = Time.now - t1 |
||
puts 'Program has run for %5.3f seconds.' % tdelt</ |
puts 'Program has run for %5.3f seconds.' % tdelt</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}}== |
|||
{{libheader|Scala}} |
|||
<syntaxhighlight lang="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) |
|||
} |
|||
}</syntaxhighlight> |
|||
=={{header|Sidef}}== |
|||
<syntaxhighlight lang="ruby">var start = Time.sec |
|||
Sig.INT { |
|||
say "Ran for #{Time.sec - start} seconds." |
|||
Sys.exit |
|||
} |
|||
{ |i| |
|||
say i |
|||
Sys.sleep(0.5) |
|||
} * Inf</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1 |
|||
2 |
|||
3 |
|||
4 |
|||
^CRan for 2 seconds. |
|||
</pre> |
|||
=={{header|Smalltalk}}== |
=={{header|Smalltalk}}== |
||
{{works with|Smalltalk/X}} |
{{works with|Smalltalk/X}}<syntaxhighlight lang="smalltalk">|n| |
||
<lang smalltalk> |n| |
|||
n := 0. |
|||
UserInterrupt |
|||
catch:[ |
|||
[true] whileTrue:[ |
|||
n := n + 1. |
|||
n printCR. |
|||
Delay waitForSeconds: 0.5. |
|||
] |
|||
]</syntaxhighlight> |
|||
or: |
|||
<syntaxhighlight lang="smalltalk">[ ... do something... ] on: UserInterrupt do: [:exInfo | ...handler... ]</syntaxhighlight> |
|||
n := 0. |
|||
UserInterrupt |
|||
catch:[ |
|||
[true] whileTrue:[ |
|||
n := n + 1. |
|||
n printCR. |
|||
Delay waitForSeconds: 0.5. |
|||
] |
|||
]</lang> |
|||
attaching an OS-signal (unix signal) to an exception or signal instance: |
attaching an OS-signal (unix signal) to an exception or signal instance: |
||
< |
<syntaxhighlight lang="smalltalk">|mySignal| |
||
mySignal := Signal new mayProceed: false. |
mySignal := Signal new mayProceed: false. |
||
OperatingSytem operatingSystemSignal: ( |
OperatingSytem operatingSystemSignal: (OperatingSystem signalNamed:'SIGHUP') install: mySignal. |
||
[ |
[ |
||
.. do something... |
.. do something... |
||
] on: mySignal do:[ |
] on: mySignal do:[ |
||
... handle SIGHUP gracefully... |
... handle SIGHUP gracefully... |
||
]</ |
]</syntaxhighlight> |
||
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 ;-). |
|||
=={{header|Swift}}== |
|||
{{trans|C}} |
|||
<syntaxhighlight lang="swift">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") |
|||
</syntaxhighlight> |
|||
=={{header|Tcl}}== |
=={{header|Tcl}}== |
||
Core Tcl does not have signal handling. |
|||
Core Tcl does not have signal handling. However the [[SMW::off]][[:Category:Expect|Expect]][[Category:Expect]][[SMW::on]]{{#set:Uses library=Expect}}<!--{{libheader|Expect}}--> and [[SMW::off]][[:Category:TclX|TclX]][[Category:TclX]][[SMW::on]]{{#set:Uses library=TclX}}<!--{{libheader|TclX}}--> extension packages do. |
|||
However the [[SMW::off]][[:Category:Expect|Expect]][[Category:Expect]][[SMW::on]]{{#set:Uses library=Expect}}<!--{{libheader|Expect}}--> and [[SMW::off]][[:Category:TclX|TclX]][[Category:TclX]][[SMW::on]]{{#set:Uses library=TclX}}<!--{{libheader|TclX}}--> extension packages do. |
|||
Using Expect: |
Using Expect: |
||
< |
<syntaxhighlight lang="tcl">package require Expect |
||
proc sigint_handler {} { |
proc sigint_handler {} { |
||
Line 747: | Line 1,829: | ||
puts [incr n] |
puts [incr n] |
||
after 500 |
after 500 |
||
}</ |
}</syntaxhighlight> |
||
Similarly, with TclX: |
Similarly, with TclX: |
||
< |
<syntaxhighlight lang="tcl">package require Tclx |
||
proc sigint_handler {} { |
proc sigint_handler {} { |
||
Line 765: | Line 1,847: | ||
puts [incr n] |
puts [incr n] |
||
after 500 |
after 500 |
||
}</ |
}</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: |
|||
<lang tcl>package require Tclx |
|||
<syntaxhighlight lang="tcl">package require Tclx |
|||
signal error sigint |
signal error sigint |
||
Line 787: | Line 1,870: | ||
puts "infinite loop interrupted, but not on SIGINT: $::errorInfo" |
puts "infinite loop interrupted, but not on SIGINT: $::errorInfo" |
||
} |
} |
||
}</ |
}</syntaxhighlight> |
||
With Tcl 8.6, that would be written as: |
With Tcl 8.6, that would be written as: |
||
< |
<syntaxhighlight lang="tcl">package require Tclx |
||
signal error sigint |
signal error sigint |
||
Line 804: | 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" |
||
}</ |
}</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|TXR}}== |
|||
<syntaxhighlight lang="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))))))</syntaxhighlight> |
|||
{{out|Run}} |
|||
<pre>$ 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</pre> |
|||
<code>range</code> generates a range of integers as a lazy list, |
|||
which is infinite if the endpoint argument is omitted. |
|||
We walk this infinite list using <code>each</code> like any other list. |
|||
=={{header|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. |
|||
<syntaxhighlight lang="bash">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</syntaxhighlight> |
|||
{{works with|bash}} |
|||
Note that the following solution only works on systems |
|||
that support a version of sleep that can handle non-integers. |
|||
<syntaxhighlight lang="bash"> |
|||
#!/bin/bash |
|||
trap 'echo "Run for $((s/2)) seconds"; exit' 2 |
|||
s=1 |
|||
while true |
|||
do |
|||
echo $s |
|||
sleep .5 |
|||
let s++ |
|||
done |
|||
</syntaxhighlight> |
|||
{{out}} |
|||
<pre> |
|||
1 |
|||
2 |
|||
3 |
|||
4 |
|||
5 |
|||
^CRun for 2 seconds |
|||
</pre> |
|||
{{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: |
|||
<syntaxhighlight lang="bash">#!/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</syntaxhighlight> |
|||
{{works with|zsh}} |
|||
<syntaxhighlight lang="bash">TRAPINT(){ print $n; exit } |
|||
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}}== |
|||
<syntaxhighlight lang="vfp"> |
|||
*!* 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 |
|||
</syntaxhighlight> |
|||
=={{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}}== |
=={{header|X86 Assembly}}== |
||
{{works with|NASM|Linux}}<br> |
{{works with|NASM|Linux}}<br> |
||
Now, I realize linking to C libraries is somewhat cheating |
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, |
|||
<lang asm> |
|||
definition of the timespec structure among other things. |
|||
<syntaxhighlight lang="asm"> |
|||
%define sys_signal 48 |
%define sys_signal 48 |
||
%define SIGINT 2 |
%define SIGINT 2 |
||
Line 864: | Line 2,161: | ||
start_time resd 1 |
start_time resd 1 |
||
end_time resd 1 |
end_time resd 1 |
||
</syntaxhighlight> |
|||
</lang> |
|||
=={{header| |
=={{header|zkl}}== |
||
SigInt is the only signal zkl brings out. |
|||
<syntaxhighlight lang="zkl">var t=Time.Clock.time; |
|||
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. |
|||
try{ n:=0; while(1){(n+=1).println(); Atomic.sleep(0.5)} } |
|||
catch{ println("ran for ",Time.Clock.time-t," seconds"); System.exit() }</syntaxhighlight> |
|||
<lang bash>c="1" |
|||
{{out}} |
|||
# Trap signals for SIGQUIT (3), SIGABRT (6) and SIGTERM (15) |
|||
<pre> |
|||
trap "echo -n 'We ran for ';echo -n `expr $c /2`; echo " seconds"; exit" 3 6 15 |
|||
1 |
|||
while [ "$c" -ne 0 ]; do # infinite loop |
|||
2 |
|||
# wait 0.5 # We need a helper program for the half second interval |
|||
3 |
|||
c=`expr $c + 1` |
|||
4 |
|||
done</lang> |
|||
5 |
|||
6 |
|||
{{works with|zsh}} |
|||
^C |
|||
<lang bash>TRAPINT(){ print $n; exit } |
|||
ran for 2 seconds |
|||
for (( n = 0; ; n++)) sleep 1</lang> |
|||
</pre> |
|||
{{omit from|M4}} |
|||
{{omit from|ML/I}} |
|||
{{omit from|JavaScript}} |
|||
{{omit from|PARI/GP}} |
|||
{{omit from|Mathematica}} |
|||
{{omit from|Retro}} |
|||
{{omit from|TI-83 BASIC}} {{omit from|TI-89 BASIC}} |
|||
{{omit from|Unlambda|Does not handle signals.}} |
Latest revision as of 07:25, 28 December 2023
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
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++
#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
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
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
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.
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
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
<?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
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
|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
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
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
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
TRAPINT(){ print $n; exit }
for (( n = 0; ; n++)) sleep 1
Visual Basic .NET
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
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
- Programming Tasks
- Concurrency
- Signal handling
- Erlang/Omit
- Batch File/Omit
- GUISS/Omit
- M4/Omit
- ML/I/Omit
- Mathematica/Omit
- PARI/GP/Omit
- Retro/Omit
- TI-83 BASIC/Omit
- TI-89 BASIC/Omit
- Unlambda/Omit
- XSLT/Omit
- Ada
- AutoHotkey
- BaCon
- BBC BASIC
- C
- POSIX
- C sharp
- C++
- Clojure
- COBOL
- Common Lisp
- Crystal
- D
- Erlang
- F Sharp
- Forth
- Fortran
- FreeBASIC
- Gambas
- Go
- Haskell
- HicEst
- Unicon
- Java
- JavaScript
- Jsish
- Julia
- Kotlin
- Liberty BASIC
- Lua
- MATLAB
- MATLAB examples needing attention
- Examples needing attention
- NewLISP
- Nim
- OCaml
- Perl
- Phix
- PHP
- PicoLisp
- PL/I
- PowerShell
- PureBasic
- Python
- Racket
- Raku
- REXX
- Ruby
- Rust
- Scala
- Sidef
- Smalltalk
- Swift
- Tcl
- Expect
- TclX
- TXR
- UNIX Shell
- Visual Basic .NET
- Visual FoxPro
- Wren
- X86 Assembly
- Zkl