Program termination

From Rosetta Code
(Redirected from Program Termination)
Program termination
You are encouraged to solve this task according to the task description, using any language you may know.


Show the syntax for a complete stoppage of a program inside a   conditional.

This includes all threads/processes which are part of your program.

Explain the cleanup (or lack thereof) caused by the termination (allocated memory, database connections, open files, object finalizers/destructors, run-on-exit hooks, etc.).

Unless otherwise described, no special cleanup outside that provided by the operating system is provided.


I problem

6502 Assembly

Commodore 64, etc.

This mostly depends on the hardware, but typically home computers would boot in BASIC and JSR to the starting address on the disk. This means that the return address for BASIC is on top of the stack, and an RTS instruction will exit the program and return to BASIC, provided that execution is not inside one of the disk's subroutines.

;assuming this is not a subroutine and runs inline.
cmp TestValue ;a label for a memory address that contains some value we want to test the accumulator against
beq continue
     rts      ;unlike the Z80 there is no conditional return so we have to branch around the return instruction.

Nintendo Entertainment System

There is no firmware or BASIC to return to, so the easiest way to do this is to "trap" the program counter with a branch back to itself. This isn't a complete termination since NMI code will still run, unless you disable the screen. In order to display a static "THE END" screen that doesn't take user input, which is what many games did once the game was beaten, you can do this:

sei       ;disable IRQs 
jmp halt  ;trap the program counter

Of course, this depends on your game using a software abstraction of its screen data that gets written to the hardware ports during vBlank; since execution in the main program has halted the ports aren't getting any new data and instead the last thing written to their user ram counterparts is just getting written to the hardware ports over and over again.

While the NES was used as an example, this same logic should apply to other ROM-cartridge-based game consoles as well.

AArch64 Assembly

Works with: as version Raspberry Pi 3B version Buster 64 bits
/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program ending64.s   */

/* Constantes file                         */
/* for this file see task include a file in language AArch64 assembly*/
.include "../"

/* Initialized data                        */
/*  code section                           */
.global main 
main:                       // entry of program
                            // end program OK 
    mov x0,0                // return code
    b 100f
                            // if error detected end program no ok
    mov x0,1                // return code
100:                        // standard end of the program
    mov x8,EXIT             // request to exit program
    svc 0                   // perform the system call Linux
/*        File Include fonctions                        */
/* for this file see task include a file in language AArch64 assembly */
.include "../"


PROC Main()
    IF Rand(0)=10 THEN
      PrintE("Terminate program by Break() procedure")
  PrintE("This is a dead code")

Screenshot from Atari 8-bit computer

Terminate program by Break() procedure

Error: 128


Ada programs execute in one or more tasks. All tasks created during the execution of a program depend in a hierarchical manner on the task that create them, except for the environment task which executes the "main" procedure for the program. Each task will abort (terminate abnormally) if the task upon which it depends is aborted. This approach to task termination is not recommended because it does not allow tasks to terminate in a known state.

However, this Rosetta Code task requires a simple stoppage of the program including all tasks. The simple way to achieve this is to abort the environment task.

with Ada.Task_Identification;  use Ada.Task_Identification;

procedure Main is
   -- Create as many task objects as your program needs
   -- whatever logic is required in your Main procedure
   if some_condition then
      Abort_Task (Current_Task);
   end if;
end Main;

Aborting a task with Abort_Task is equivalent to abort statement, which is not used here because the environment task object is anonymous. The semantics of abort is as follows:

  • Abort is deferred until certain unbreakable actions are accomplished. These are protected actions on shared objects, initialization, assignment, and finalization of controlled objects, waiting for dependent tasks to be aborted;
  • Local objects of the task are finalized;
  • The tasks dependent on the aborted task are aborted.
  • The state of external files will depend on the OS

The above is a preemptive way to abort tasks, which is not recommended to use, unless you firmly know what you are doing. A standard approach to such termination is either (or a combination of):

  • to provide an entry in each task created by the environment task which, when called by the task upon which it depends, causes the called task to terminate in a known state;
  • to provide "terminate" alternative open in each of such tasks.

In both cases the task objects are made local or otherwise destroyed upon completion of the main task. Note that destruction of a task always waits for its termination. If the task refuses to terminate it deadlocks.

With the first approach:

procedure Main is
   -- Create as many task objects as your program needs
   -- whatever logic is required in your Main procedure
   if some_condition then
      -- for each task created by the Main procedure
      -- end the Main procedure
      return;  -- actually, this is not needed
   end if;
end Main;

A task might look like:

task body Some_Task is
         -- Some alternatives
      or accept Stop do
            -- Some cleanup while holding the caller is here
         end Stop;
            -- A cleanup asynchronous to the caller is here
         exit; -- We are through
      end select
   end loop;
end Some_Task;

With the second approach one simply returns from Main and all tasks are terminated by selecting the terminate alternative. Such tasks might look like:

task body Some_Task is
         -- Some alternatives
      or terminate; -- We are through
      end select
   end loop;
end Some_Task;


f1(integer a)
    if (a) {


    return 0;


The label "stop" appears at the start of the standard-postlude and can be invoked to terminate any program.

IF problem = 1 THEN

The standard-postlude closes any opens files and basically wraps up execution.


The program can be stopped by a false assertion.

if anErrorOccured then assert( false );


Contrary to what was stated in the previous entry here, AppleScript's "User canceled." error (number -128) stops the script execution immediately and does not cause a dialog to appear. (There may have been dialog at some point in the past owing to a bug in one of the earlier systems.) However, the error can be trapped if required and a specified action taken.

If the script's running as an applet, the applet will quit as soon as the script stops — unless it's a stay-open applet, in which case it will be necessary to use a quit command instead of, or immediately before, the error command.

The memory used belongs to the application running the script and is reclaimed automatically.

 if (someCondition) then error number -128

In a stay-open applet:

on idle -- A stay-open applet's 'idle' handler is called periodically while the applet remains open.
    -- Some code, including:
    if (someCondition) then
        quit -- Quit the applet when the script stops executing.
        error number -128 -- Stop executing the script. (Not necessary on recent systems.)
    end if

    return 10 -- Number of seconds to the next call of this handler if the applet's still open. 
end idle


#!/usr/local/bin/apl --script --

⍝⍝ GNU APL script
⍝⍝ Usage: errout.apl <code>
⍝⍝ $ echo $?   ## to see exit code
args  2⎕ARG~'--script' '--'  ⍝⍝ strip off script args we don't need

err  ⍎⊃args[1]

  'Error! exiting.'
  ')off 1'         ⍝⍝ NOTE: exit code arg was added to )OFF in SVN r1499 Nov 2021
  'No error, continuing...'

~/GNUAPL$ workspaces/errout.apl 0
No error, continuing...

~/GNUAPL$ echo $?
~/GNUAPL$ workspaces/errout.apl 1
Error! exiting.

~/GNUAPL$ echo $?

ARM Assembly

Works with: as version Raspberry Pi
/* ARM assembly Raspberry PI  */
/*  program ending.s   */

/* Constantes               */
.equ EXIT,   1                          @ Linux syscall

/* Initialized data */

/*  code section */
.global main 
main:                                   @ entry of program
    push {fp,lr}                        @ saves registers

    @ end program OK 
    mov r0, #0                          @ return code
    b 100f
    @ if error detected end program no ok
    mov r0, #1                          @ return code
100:                                    @ standard end of the program
    pop {fp,lr}                         @restaur  registers
    mov r7, #EXIT                       @ request to exit program
    swi 0                               @ perform the system call Linux


problem: true
if problem -> exit


If (problem)


Then Endif is entirely unnecessary, but it is good form.

If problem Then


An "exit"-statement aborts the current script, optionally returning a status-code:

if(problem)exit 1

Before exiting, the END-block(s) are processed.
An "exit" in an END-block causes an immediate exit:

# usage:  awk -f exittest.awk input.txt
BEGIN  { print "# Exit-Test" }

#/s.*t/ { print "!", NR, $0; next }           #1: List all matches
 /s.*t/ { print "!", NR, $0; problem=1; exit} #2: Abort after first match
        { print " ", NR, $0}

END     { if(problem) {print "!! Problem !!"; exit 2} }
END     { print "# Lines read:", NR }

To compare, un/comment one of the lines #1 or #2:

This is file input.txt
you can use it
to provide your 
program with some data
to process.

with line #1 "next" active

# Exit-Test
! 1 This is file input.txt
! 2 you can use it
  3 to provide your 
! 4 program with some data
  5 to process.
# Lines read: 5

with line #2 "exit" active

# Exit-Test
! 1 This is file input.txt
!! Problem !!


The following example will force exit from any number of nested calls and loops:



Works with: QuickBasic version 4.5
if problem = 1 then
end if

Applesoft BASIC



No special cleanup routines are compiled in by default, but any functions registered via POSIX atexit and/or on_exit will be honoured. END can include a status code to be passed back to the invoking process.



if not more then end



Locomotive Basic



The keywords STOP and END are aliases. They do the same thing. Any expression resulting in a non-zero value is evaluated as "True".

If 1 Then Stop
If 1 Then End

ZX Spectrum Basic

The ZX Spectrum has a STOP command, rather than an END command:

10 LET a = 1: LET b = 1
20 IF a = b THEN GO TO 9995
9995 STOP

Batch File

if condition exit

In Windows batch files this doesn't need to exit the program but instead can also just exit a subroutine. exit /b can also be used alternatively if a return value if desired.


      IF condition% THEN QUIT

Only QUIT fully terminates the program. END and STOP stop execution and return control to the immediate-mode prompt; END closes all open files, but STOP does not.



The @ instruction ends the program. Some interpreters revert changes to the code (made by p) while others do not.


•Exit immediately terminates the running BQN process. If the argument is a valid return code (on Unix, an integer), it is returned; otherwise, the default return code (the one returned when the end of the program is reached) is used.

We can use a block to create a conditional exit. Here we exit if the script is given zero command line arguments:

  0=≠•args ? •Exit 0;
  •Show "has args"


From infinite loops (such as the read-eval-print loop that Bracmat enters when run in interactive mode) the program can only exit cleanly by evaluating a closing parenthesis followed by an affirmative y, Y, j or J. Thus, at the Bracmat prompt you type the closing parenthesis, a y and then press enter. From within Bracmat code, you force an exit by evaluating get'(")y",MEM). If Bracmat is linked to another program (e.g. as a Java Native Interface library), it is better to turn off the possibility to exit Bracmat, as that normally would cause the main program to crash. There is a C preprocessor macro that disables exiting.

If there are no infinite loops in Bracmat code, the Bracmat program will ultimately terminate in a natural way.


#include <stdlib.h>
/* More "natural" way of ending the program: finish all work and return
   from main() */
int main(int argc, char **argv)
  /* work work work */
  return 0;  /* the return value is the exit code. see below */

  /* On unix, exit code 0 indicates success, but other OSes may follow
     different conventions.  It may be more portable to use symbols
     EXIT_SUCCESS and EXIT_FAILURE; it all depends on what meaning
     of codes are agreed upon.

The atexit() function (also in stdlib.h) can be used to register functions to be run when the program exits. Registered functions will be called in the reverse order in which they were registered.

#include <stdlib.h>


Unlike exit(), abort() will not do any cleanup other than the normal OS one. Also, it may cause other actions like producing a core dump or starting a debugger.

To end not just the current process, but all processes in the same group, do



if (problem)


There are several ways to terminate a program. The following is mostly the same as in C:

#include <cstdlib>

void problem_occured()

The argument is the return value passed to the operating system. Returning 0 or the EXIT_SUCCESS signals successful termination to the calling process, EXIT_FAILURE signals failure. The meaning of any other value is implementation defined.

On calling std::exit, all functions registered with std::atexit are called, and the destructors of all objects at namespace scope, as well as of all static objects already constructed, are called. However the destructors of automatic objects (i.e. local variables) are not called (and of course, objects allocated with new will not be destructed as well, except if one of the called destructors destroys them). Due to this inconsistency calling std::exit is often not a good idea.

#include <cstdlib>

void problem_occured()

Unlike std::exit, std::abort will not do any cleanup other than the normal OS one. Also, it may cause other actions like producing a core dump or starting a debugger.

#include <exception>

void problem_occured()

The function std::terminate is what is automatically called when certain exception related failures happen. However it also can be called directly. By default it just calls abort, but unlike abort, its behaviour can be overridden with std::set_terminate (but it still must terminate the program in one way or anouther). Thererfore the amount of cleanup it does depends on whether it was overridden, and what the overridden function does.

Note that returning a value from main is mostly equivalent to calling std::exit with the returned value, except that automatic variables are correctly destructed. If one wants to return from an inner function, while still doing complete cleanup, a solution is to throw an exception caught in main (this will call the destructors of non-main local variables during stack unwinding), and to then return normally from main (which will destruct all automatic objects in main, and then do the cleanup like std::exit.


Translation of: Java

The call System.exit does not finalize any objects by default. This default is to keep the program thread-safe. From the javadocs for the method to change this default: "may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, resulting in erratic behavior or deadlock."

(if problem
   (. System exit integerErrorCode))
   ;conventionally, error code 0 is the code for "OK",
   ; while anything else is an actual problem
   ;optionally: (-> Runtime (. getRuntime) (. exit integerErrorCode))

You can use (-> Runtime (. getRuntime) (. addShutdownHook myThread)) to add threads which represent actions to be run when the program exits.

This one does not perform cleanup:

(if problem
   (-> Runtime (. getRuntime) (. halt integerErrorCode)))
   ; conventionally, error code 0 is the code for "OK",
   ; while anything else is an actual problem


Terminating the program will cause all open files to be closed and control to be returned to the operating system. There are 2 ways to do this: STOP RUN and GOBACK.

IF problem

GOBACK was added in COBOL 2002, and will terminate the program if it is reached in the main program.

IF problem

The ability to return a return code to the operating system is available for both of these statements as an extension in some compilers.

Common Lisp

Many Common Lisp implementations provide a function named quit or sometimes exit which will exit the Lisp system; its parameters and the package it is in vary, but here are some implementations' versions, with a Unix-style exit status argument, and a fallback:

(defun terminate (status)
  #+sbcl     (           sb-ext:quit      :unix-status status)    ; SBCL
  #+ccl      (              ccl:quit      status)                 ; Clozure CL
  #+clisp    (              ext:quit      status)                 ; GNU CLISP
  #+cmu      (             unix:unix-exit status)                 ; CMUCL
  #+ecl      (              ext:quit      status)                 ; ECL
  #+abcl     (              ext:quit      :status status)         ; Armed Bear CL
  #+allegro  (             excl:exit      status :quiet t)        ; Allegro CL
  #+gcl      (common-lisp-user::bye       status)                 ; GCL
  #+ecl      (              ext:quit      status)                 ; ECL
  (cl-user::quit))           ; Many implementations put QUIT in the sandbox CL-USER package.

There is no standard form because the Common Lisp standard does not assume the presence of an operating system outside of the Lisp environment to exit to.

What cleanup will be performed varies. Some implementations have at-exit hooks. SBCL will unwind the stack and execute any unwind-protects (like finally in other languages) it encounters, unless :recklessly-p t is specified.

Computer/zero Assembly

A STP instruction causes program execution to halt. The program counter is left pointing to the word after the STP, so this instruction can be used to stop the computer while the user enters some data before resuming execution.


The usual C functions are available, plus assert Errors and user defined Errors, and Exceptions.

import core.stdc.stdio, core.stdc.stdlib;

extern(C) void foo() nothrow {
    "foo at exit".puts;

extern(C) void bar() nothrow {
    "bar at exit".puts;

extern(C) void spam() nothrow {
    "spam at exit".puts;

int baz(in int x) pure nothrow
in {
    assert(x != 0);
} body {
    if (x < 0)
        return 10;
    if (x > 0)
        return 20;

    // x can't be 0.

    // In release mode this becomes a halt, and it's sometimes
    // necessary. If you remove this the compiler gives:
    // Error: function test.notInfinite no return exp;
    //    or assert(0); at end of function

// This generates an error, that is not meant to be caught.
// Objects are not guaranteed to be finalized.
int empty() pure nothrow {
    throw new Error(null);

static ~this() {
    // This module destructor is never called if
    // the program calls the exit function.
    import std.stdio;
    "Never called".writeln;

void main() {

    //abort(); // Also this is allowed. Will not call foo, bar, spam.
spam at exit
bar at exit
foo at exit

Simple exit with D Runtime cleanup

import core.runtime, std.c.stdlib;

static ~this() {
    // This module destructor is called if
    // the program calls the dexit function.
    import std.stdio;
    "Called on dexit".writeln;

void dexit(int rc) {
    // Calling dexit() should have the same effect with regard to cleanup as as reaching the end of the main program.

int main() {
    if(true) {
    return 0;
Called on dexit






System.Halt(1); // Optional exit code


[quit] true do?


Exit indicating successful completion:

if (true) {

Exit indicating some problem:

if (true) {
    interp.exitAtTop("because the task said so")

Both of these have the same effect with regard to cleanup as as reaching the end of the main program. [To do: Find out what effect that is.]

EDSAC order code

The 'stop' order is Z, so ZF will halt the machine completely. EDSAC programmers used also to use an infinite loop as a 'dynamic stop': since F is the order for an unconditional jump, Fn@ where = the current address - θ is equivalent to here: goto here.


if rcode != :ok, do: System.halt(1)
# or

Emacs Lisp

(when something

Functions in kill-emacs-hook are called. (Except prior to Emacs 24 that hook was not run when in -batch mode.) The underlying C library atexit() handlers are called.


^| I try to use the exit codes described at:
int EX_SOFTWARE = 70 # internal software error
logic hasProblem = true
if hasProblem do exit EX_SOFTWARE end
emal.exe Org\RosettaCode\ProgramTermination.emal
echo Exit Code is %errorlevel%
Exit Code is 70


% Implemented by Arjun Sunel
if problem ->
As soon as possible
% Implemented by Arjun Sunel
if problem ->


open System

if condition then
    Environment.Exit 1


USING: kernel system ;

t [ 0 exit ] when

When the exit word is called, first it runs the shutdown hooks, and then exits the Factor VM, passing along an exit code to the operating system. If an error occurs while running the shutdown hooks, the error is ignored and the exit code 255 is passed along.

You can add your own shutdown hooks like so:

USING: init io ;

[ "Exiting Factor..." print flush ] "message" add-shutdown-hook

They are name/quotation pairs that are added to the associative mapping at the shutdown-hooks symbol in the init vocabulary.

By default, shutdown-hooks conditionally includes some operating system resource destructors, such as shutdown-winsock.


debug @
if   QUIT  \ quit back to the interpreter
else BYE   \ exit forth environment completely (e.g. end of a Forth shell script)


In Fortran STOP stops the execution of the main process and its "children" (tested with OpenMP; if using POSIX threads, I think the stop behaves almost like C exit). Allocated memory or any other resource except opened file (which are closed) is not cleaned up.

IF (condition) STOP [message] 
! message is optional and is a character string.
! If present, the message is output to the standard output device.


In FreeBASIC, the 'End' statement exits the program immediately and optionally returns a value to the operating system. Typically, a return value of 0 (the default) indicates there was no error and some other value (such as 1) indicates termination was due to an error. Any open files will be closed automatically.

However, the use of this statement does not necessarily produce a clean exit. As FreeBASIC does not unwind the stack, local variables will not have their destructors (if any) called automatically - though global variables will.

Because of this, it is generally better if some way can be found of returning to the module-level code and then jumping to the end thereof to ensure that all variables have their destructors called as they fall out of scope.

Here is a very simple example of the use of the 'End' statement:

'FB 1.05.0 Win64 'endprog.bas'

Dim isError As Boolean = True
If isError Then
  End 1
End If

' The following code won't be executed
Print "Press any key to quit"

After running the program, the Windows console will look something like this:


c:\FreeBasic>echo exit code is %errorlevel%
exit code is 1


Quick and dirty. Terminates everything.

if condition then end


In a GUI environment

Public Sub Form_Open()
Dim siCount As Short

  If siCount > 1000 Then Break
  Inc siCount



In a CLI environment

Public Sub Main()
Dim siCount As Short

  If siCount > 1000 Then Break
  Inc siCount




Terminate with an error message and a non-zero status code if "Star Trek" is found in the input stream.

Star Trek=@err{found a Star Trek reference\n}@abort


if (problem) {
  exit gnuplot

The Gnuplot manual under "exit" notes that "any open output files may not be completed cleanly". (Does that mean output buffers not flushed?)


Operating system resources such as memory and file handles are generally released on exit automatically, but this is not specified in the language definition. Proceses started with os.StartProcess or exec.Run are not automatically terminated by any of the techniques below and will continue to run after the main program terminates.

Return statement

Basically, a return statement executed from anywhere in main() terminates the program.

func main() {
    if problem {

Deferred functions are run when the enclosing function returns, so in the example below, function paperwork is run. This is the idiomatic mechanism for doing any kind of necessary cleanup.

Other goroutines are terminated unceremoniously when main returns. Below, main returns without waiting for pcj to complete.

The tantalizingly named SetFinalizer mechanism is also not invoked on program termination. It is designed for resource reclamation in long-running processes, not for program termination.

Returns from functions other than main do not cause program termination. In particular, return from a goroutine simply terminates that one goroutine, and not the entire program.

package main

import (

const problem = true

func main() {
    fmt.Println("main program start")

    // this will get run on exit
    defer paperwork()

    // this will not run to completion
    go pcj()

    // this will not get run on exit
    rec := &requiresExternalCleanup{"external object"}
    runtime.SetFinalizer(rec, cleanup)

    if problem {
        fmt.Println("main program returning")

func paperwork() {
    fmt.Println("i's dotted, t's crossed")

func pcj() {
    fmt.Println("there's uncle Joe")
    fmt.Println("movin kinda slow")

type requiresExternalCleanup struct {
    id string

func cleanup(rec *requiresExternalCleanup) {
    fmt.Println(, "cleanup")
main program start
main program returning
there's uncle Joe
i's dotted, t's crossed


Runtime.Goexit terminates the goroutine that calls it. No other goroutine is affected. Goexit runs all deferred calls before terminating the goroutine.

Calling Goexit from the main goroutine terminates that goroutine without func main returning. Since func main has not returned, the program continues execution of other goroutines. If all other goroutines exit, the program crashes.


Os.Exit causes its argument to be returned to the operating system as a program exit code. Unlike the return statement and runtime.Goexit, os.Exit exits promptly and does not run deferred functions.

func main() {
    fmt.Println("main program start")

    // this will not get run on os.Exit
    defer func() {
        fmt.Println("deferred function")

    if problem {
        fmt.Println("main program exiting")
main program start
main program exiting


Panics have some similarities to exceptions in other languages, including that there is a recovery mechanism allowing program termination to be averted. When the program terminates from panic however, it prints the panic value and then a stack trace for all goroutines.

Like the return statement, panic runs deferred functions. It run functions deferred from the current function, but then proceeds to unwind the call stack of the goroutine, calling deferred functions at each level. It does this only in the goroutine where panic was called. Deferred functions in other goroutines are not run and if panicking goes unrecovered and the program terminates, all other goroutines are terminated abruptly.

func pcj() {
    fmt.Println("at the junction")
    defer func() {
        fmt.Println("deferred from pcj")

func main() {
    fmt.Println("main program start")
    defer func() {
        fmt.Println("deferred from main")
    go pcj()
    fmt.Println("main program done")
main program start
at the junction
deferred from pcj
panic: 10
(and the stack trace follows)


See Java for a more complete explanation.

Solution #1:

if (problem) System.exit(intExitCode)

Solution #1:

if (problem) Runtime.runtime.halt(intExitCode)




import Control.Monad
import System.Exit

when problem do
    exitWith ExitSuccess                    -- success
    exitWith (ExitFailure integerErrorCode) -- some failure with code
    exitSuccess                             -- success; in GHC 6.10+
    exitFailure                             -- generic failure

The above shows how to exit a thread. When the main thread exits, all other threads exit, and the return code in the exit call is the return code of the program. When any thread other than the main thread exits, only it is stopped, and if the exit code is not ExitSuccess, it is printed.


ALARM( 999 )

This closes windows, dialogs, files, DLLs, and frees allocated memory. Script editing is resumed on next start.

Icon and Unicon

exit(i)          # terminates the program setting an exit code of i
stop(x1,x2,..)   # terminates the program writing out x1,..; if any xi is a file writing switches to that file
runerr(i,x)      # terminates the program with run time error 'i' for value 'x'


Given condition, an integer which is zero if everything's OK (and we should NOT exit), or a non-zero exit code if there's a problem (and we should exit), then:

Tacit version:

2!:55^:] condition

Explicit version:

3 : 'if. 0~: condition do. 2!:55 condition end.'


The call System.exit does not finalize any objects by default. This default is to keep the program thread-safe. From the javadocs for the method to change this default: "may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, resulting in erratic behavior or deadlock."

   //conventionally, error code 0 is the code for "OK",
   // while anything else is an actual problem
   //optionally: Runtime.getRuntime().exit(integerErrorCode);

You can use Runtime.getRuntime().addShutdownHook(myThread); to add threads which represent actions to be run when the program exits.

This one does not perform cleanup:

   //conventionally, error code 0 is the code for "OK",
   // while anything else is an actual problem


Works with: SpiderMonkey

The quit() function exits the shell.

if (some_condition) 


[true] [quit] [] ifte.


The jq process will stop when it encounters a call to the function "error" (error/0) unless it occurs within the scope of a "try" command.


$ jq -n '"Hello", if 1 then error else 2 end'

Note that error/0 expects its input to be null (as above), in which case no error message is printed, or a string, in which case the string is printed as an error message, as illustrated below:

$ jq -n '"Hello" | if 1 then error else 2 end'
jq: error: Hello


Jsi supports assert, normally disabled, but will abort (regardless of control flow depth) with a message after cleanup.

Returning a code to operating system, regardless of control flow depth, is via exit(code) where numeric code is passed to the parent process (after internal cleanup).

Signal handlers can also be installed to trap external events and deal with the issue programmatically, via Signal.callback, Signal.handle, Signal.ignore along with other control methods. These interrupt handlers will fire regardless of control flow depth.

In jsish Ctrl-C will halt any running code and return to the shell. If no code is running, the shell exits on Ctrl-C.

assert(0 == 1);

if (problem) exit(1);


quit() # terminates program normally, with its child processes. See also exit(0).


Premature termination of a program in Kotlin would normally be achieved by calling Java's System.exit(status) method which calls Runtime.getRuntime().exit(status) under the hood and passes the value of 'status' to the operating system. By convention a non-zero code indicates that termination was triggered due to some problem. According to the Java documentation, prior to JVM termination:

1. All shutdown hooks, registered by the Runtime.addShutdownHook(hook) method, would be started in an unspecified order and allowed to run concurrently until they finish.

2. Uninvoked finalizers would then be invoked if this behavior had been enabled using the Runtime.runFinalizersOnExit(true) method. However, this method is currently deprecated because it may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, leading to erratic behavior or even deadlock.

// version 1.0.6

fun main(args: Array<String>) {
    val problem = true
    if (problem) System.exit(1) // non-zero code passed to OS to indicate a problem
    println("Program terminating normally")  // this line will not be executed

After the program has terminated, the exit status can be queried from the command line (Windows 10) as follows:

c:\kotlin-compiler-1.0.6>echo %errorlevel%


Lasso will stop processing when it encounters an "abort". By providing a "handle" block, possible cleanups can be executed before finishing execution.


handle => {
	stdoutnl('The end is here')

stdoutnl('Starting execution')


stdoutnl('Ending execution')
Starting execution
The end is here

It is also possible to provide a "handle" block that will only execute if there's an error.


handle_error => {
	stdoutnl('There was an error ' + error_msg)

stdoutnl('Starting execution')


stdoutnl('Ending execution')
Starting execution
There was an error Divide by zero

Liberty BASIC

If any files or devices are still open when execution is terminated, then Liberty BASIC will close them and present a dialog expressing this fact.

The STOP statement is functionally identical to END and is interchangable. Also, make sure that when a program is finished running that it terminates properly with an END statement. Otherwise the program's windows may all be closed, giving the illusion that it has stopped running, but it will still be resident in memory and may still consume processor resources.

The following is functional. Better practice is to instead jump to commands or subs to close known open files, windows etc, avoiding error messages as above.

if 2 =2 then end

Works with: UCB Logo
bye   ; exits to shell

throw "toplevel  ; exits to interactive prompt

pause      ; escapes to interactive prompt for debugging
continue   ; resumes after a PAUSE


if some_condition then 
    os.exit( number )

M2000 Interpreter

Set End send End to command line interpreter which end the program Threads also erased when the module where belong exit.

M2000 has two interpreters the CLI which used in M2000 console (it is in global namespace), and the program interpreter when we execute a module or a function (always they have a namespace by the name of module/function, and the position of the call in the flow).

Statement End in program interpreter is same as Exit

IF we didn't use Escape Off we can end the program using Esc key. We can use Break key to restart it. We can change Set End with Test to open dialog for step by step execution, slow and stop. From this dialog we can execute statements and we can see the code in color syntax as executed (including threads, excluding events from Gui)

Module Checkit {
      For i=1 to 200
      Thread {
            Print "Thread:"; num, "k=";k
      } as M
      Thread M Execute  {
            static num=M, k=1000*i
      Thread M interval 100+900*rnd
      next i
      Task.Main 20 {
            if random(10)=1 then Set End



Mathematica/Wolfram Language

If[problem, Abort[]];

Kernels stop all computation after "Abort[]" command. But the kernels are still operational, and all definitions are still available. Note that an Abort[] can be caught by a calling function using CheckAbort, in which case the computation will continue at that place.


This will completely quit the kernel. All definitions will be lost. Since this terminates the actual kernel process, this will also free all resources used by that kernel (especially memory). Note however that if the kernel is interactively used through a notebook, the notebook still remains operable.


if condition

There is no special way to stop a program. You can terminate it by calling return.

if condition

The quit function runs the MATLAB script finish.m, if it exists, and terminates MATLAB completely.


/* Basically, it's simply quit() */

block([ans], loop, if (ans: read("Really quit ? (y, n)")) = 'y
                   then quit()
                   elseif ans = 'n then (print("Nice choice!"), 'done)
                   else (print("I dont' understand..."), go(loop)));


ИП0	x=0	04	С/П	...

Condition of termination is Р0 = 0.


Nanoquery supports both an exit statement and an exit function. The following lines are identical:


A value passed to the exit() function will be returned to the operating system after the program is halted.


Neko installs abnormal run down handlers, or can call the C ABI exit routine, which returns a status code to the operating system.

 Program termination, in Neko

var sys_exit = $loader.loadprim("std@sys_exit", 1)

var return_code = 42
if true sys_exit(return_code)

$print("Control flow does not make it this far")
prompt$ nekoc program-termination.neko
prompt$ neko program-termination.n
prompt$ echo $?


using System.Environment
    when (problem) Exit(1)


NetRexx's exit statement invokes Java's System.exit() so job termination is handled in the same way as any other Java program. (See Java above.)

/* NetRexx */
options replace format comments java crossref symbols nobinary

extremePrejudice = (1 == 1)
if extremePrejudice then do
  exit extremePrejudice



if problem1:
  quit QuitFailure

if problem2:
  quit "There is a problem", QuitFailure


  IF problem THEN


The code below, will terminate a program without any cleanup.

if(problem) {


if problem then
  exit integerErrorCode;
  (* conventionally, error code 0 is the code for "OK",
     while anything else is an actual problem *)

The at_exit function can be used to register functions to be run when the program exits. Registered functions will be called in the reverse order in which they were registered.


OS.exit returns to OS with return value as parameter.

import: os

some_condition ifTrue: [ 0 OS.exit ]


(shutdown 0) ; it can be any exit code instead of provided 0


if Problem then {Application.exit 0} end

All threads exit. All processes (local and remote) exit unless they were created with detach:true. Finalizers are not executed (unless enforced with {System.gcDo}).


if(stuff, quit)


Works with: Extended Pascal

Extended Pascal (ISO standard 10206) defines a (parameter-less) procedure halt. UCSD Pascal’s halt takes one integer argument (cf. Delphi).

if true then

All regular cleanup procedures apply, nothing special.


if ($problem) {
    exit integerErrorCode;
    # conventionally, error code 0 is the code for "OK"
    #  (you can also omit the argument in this case)
    # while anything else is an actual problem

The DESTROY() methods of all objects are called, in an unspecified order (see "Global Destruction" in perlobj.pod). This includes objects in global variables or with circular references which otherwise keep them alive during normal running.

END { } blocks are executed in reverse order of their creation (see perlmod.pod).

The underlying C library exit() runs its C level atexit() callbacks.

An exit without these cleanups can be done with POSIX::_exit() (as noted in perlfunc.pod under the normal exit()). This is the _exit() system call (which the C library generally provides in equivalent form on non-Unix/non-POSIX systems too).


To terminate the entire application:

if error_code!=NO_ERROR then
end if

To terminate just the current thread (no threads under pwa/p2js though):

if error_code!=NO_ERROR then
end if

Files will be closed automatically and memory will be freed, however any other cleanup should be invoked manually.
Most of my code has Abort() routines acting as wrappers for final-housekeeping-then-abort().


if 1 quit endif

See Phix commments.


if (problem)

The register_shutdown_function() function can be used to register functions to be run when the program exits.


% ...
if problem then
% ...


% ...
if problem then
% ...


Calling 'bye', optionally with a numeric code, terminates the program.

This will execute all pending 'finally' expressions, close all open files and/or pipes, flush standard output, and execute all expressions in the global variable '*Bye' before exiting.

(push '*Bye '(prinl "Goodbye world!"))
Goodbye world!


STOP; /* terminates the entire program */
      /* PL/I does any required cleanup, such as closing files. */
STOP THREAD (tiger); /* terminates only thread "tiger". */
SIGNAL FINISH; /* terminates the entire program.   */
               /* PL/I does any required cleanup,  */
               /* such as closing files.           */


if condition then


There are two ways which differ slightly:

condition {stop} if

will terminate a so-called stopped context which is a way of executing a block of code and catching errors that occur within. Any user program will always run in such a context and therefore be terminated upon calling stop

Neither the operand stack nor the dictionary stack are touched or cleaned up when calling stop. Anything pushed onto either stack will remain there afterwards.

condition {quit} if

will terminate the PostScript interpreter. This is definitely a way to stop the current program but since an interpreter can run multiple programs at the same time, this should rarely, if ever, be used.


if (somecondition) {

This ends the scope for any non-global variables defined in the script. No special cleanup is performed.


Terminate Prolog execution. Open files are closed. Exits the Interpreter.


Terminate Prolog execution but don't exit the Interpreter.



This will free any allocated memory, close files and free other resources (i.e. windows, gadgets, threads, space for variable, etc.) that were set aside during execution of any PureBasic commands in the program.

If problem = 1

It is possible to also access outside resources (i.e. via an OS API or linked library), and those items may or may not be cleaned up properly.


import sys
if problem:

The atexit module allows you to register functions to be run when the program exits.

As soon as possible

(Signals the underlying OS to abort the program. No cleanup is performed)

import os
if problem:


out! will cleanly exit Quackery and return control to the calling program. This is demonstrated in the Quackery shell. When 10 random returns 0 Quackery (which in this implementation is a function called from Python3) returns control to Python, which then terminates in the usual fashion and returns control to the zsh, from which we show this to be the case and then re-enter Quackery.

 [ return$ nest$ size 2 / ]bailby[ ] is out! ( --> )
/O>  [ 10 random dup
...    iff
...      [ echo cr ]
...    else
...      [ say "Bye-ee!" cr
...        drop out! ]
...    again ]
 $ echo "$SHELL"
 $ quackery

Welcome to Quackery

Enter "leave" to leave the shell.

Building extensions.



CBTJD: 2020/03/15
There are three commands that can be used to end a program in QB64:
1) END - The program will display "Press any key to continue..." and wait for a key press before closing the program.
2) STOP - The program will close immediately, but will not close any open files. STOP is ONLY used for debugging purposes and should not be used to exit programs!
3) SYSTEM - The ONLY proper command to immediately close a program in QB64 without a pause or interactive message as in the case with the END command.

INPUT "Press any key...", a$


if(problem) q(status=10)


Racket has an "exit" function that can be used to exit the Racket process, possibly returning a status code.

#lang racket
(when (something-bad-happened) (exit 1))

In addition, Racket has "custodians", which are objects that are used to manage a bunch of dynamically allocated resources (ie, open files, running threads). This makes it easy to run some code and conveniently kill it with all related resources when needed, without exiting from the whole process. It is common to use this facility in servers, where each handler invocation is wrapped in a new custodian that is shut down when its client interaction is done. For example:

#lang racket
(parameterize ([current-custodian (make-custodian)])
  (define (loop) (printf "looping\n") (sleep 1) (loop))
  (thread loop) ; start a thread under the new custodian
  (sleep 5)
  ;; kill it: this will kill the thread, and any other opened resources
  ;; like file ports, network connections, etc
  (custodian-shutdown-all (current-custodian)))


(formerly Perl 6)

if $problem { exit $error-code }

An exit runs all appropriate scope-leaving blocks such as LEAVE, KEEP, or UNDO, followed by all END blocks, followed by all destructors that do more than just reclaim memory, and so cannot be skipped because they may have side effects visible outside the process. If run from an embedded interpreter, all memory must also be reclaimed. (Raku does not yet have a thread-termination policy, but will need to before we're done.)


The quit word stops all evaluation, releases operating system resources and exits the interpreter.

if error? try [6 / 0] [quit]

A return value can be provided to the operating system:

if error? try [dangerous-operation] [quit/return -12]

Because of REBOL's tightly integrated REPL, you can also use q to do the same thing.

if error? try [something-silly] [q/return -12]

Since GUI programs are often developed from the REPL, a special halt word is provided to kill the GUI and return to the REPL. No cleanup is done and the GUI is still displayed (although halted). You can restart it with the do-events word.

view layout [button "stopme" [halt]]


problem? [ bye ] if


In REXX, the REXX interpreter takes care of the closing of any open files (or any I/O streams), as well as any memory management (cleanup).

/*REXX program showing five ways to perform a REXX program termination. */

  /*─────1st way────────────────────────────────────────────────────────*/

  /*─────2nd way────────────────────────────────────────────────────────*/
exit  (expression)     /*Note: the "expression" doesn't need parentheses*/
                       /*"expression"  is any REXX expression.          */

  /*─────3rd way────────────────────────────────────────────────────────*/
return                 /*which returns to this program's invoker.  If   */
                       /*this is the main body  (and not a subroutine), */
                       /*the REXX interpreter terminates the program.   */

  /*─────4th way────────────────────────────────────────────────────────*/
return (expression)    /* [See the note above concerning parentheses.]  */

  /*─────5th way────────────────────────────────────────────────────────*/
    /*   │   */        /*if there is no EXIT and program control "falls */
    /*   │   */        /*through" to the "bottom" (end) of the program, */
    /*   │   */        /*an   EXIT   is simulated and the program is    */
    /*   │   */        /*terminated.                                    */
    /*   ↓   */
    /* e-o-f */        /* e-o-f   =   end-of-file.                      */

Regina actually implies a RETURN when the end of the program is found at the end of a subroutine:

Parse Version v
Say v
Call sub
Say 'Back from sub'
REXX-Regina_3.9.1(MT) 5.00 5 Apr 2015
Back from sub


for n = 1 to 10
    see n + nl
    if n = 5 exit ok


There are 2 ways of terminating a program in RPL.


Here, nothing is cleaned up: local variables are still existing and a step-by-step execution is possible thanks to the SST instruction, typically for debugging. Once the bug found, a manual cleanup must be done through the KILL instruction. If a full termination with cleanup is desired, it must be written:


All currently running processes are then terminated, all local variables are discarded and control is given back to the user.


if problem

# or
if problem
  abort   # equivalent to exit(1)

You can use at_exit { ... } to register a block of code which will be run when the program exits. Registered handlers will be called in the reverse order in which they were registered.

if problem
  exit!   # default value 1

Exits the process immediately. No exit handlers are run. exit! is different from exit and it doesn't do an exception handling.


if whatever then end


Return statement

A return statement executed in the main() function will exit the program.

fn main() {
    println!("The program is running");
    println!("This line won't be printed");

Exit function

You can run std::process::exit from anywhere in the program in order to exit. This will work from the main function as well as any other function or file.

fn main() {
    if problem {
        std::process::exit(1); // 1 is the exit code


A panic in Rust will terminate the current thread. If the panic is in the main thread, the program will exit. If the panic is from another thread; that thread will terminate and the program, along with the other threads, will keep running.

fn main() {
    println!("The program is running");
    panic!("A runtime panic occured");
    println!("This line won't be printed");

Because of the panic, the last line will not run. If the panic happened in another thread, the program could keep running.

Panic Inside a Thread

use std::thread;

fn main() {
    println!("The program is running");

    thread::spawn(move|| {
        println!("This is the second thread");
        panic!("A runtime panic occured");

    println!("This line should be printed");

Now the panic will be contained inside the background thread and will not affect the rest of the program.


Library: Scala
if (problem) {
  // sys.exit returns type "Nothing"
  // conventionally, error code 0 is the code for "OK",
  // while anything else is an actual problem


Works with: Scheme version R6RS
(if problem
  (exit)) ; exit successfully


(if problem
  (exit #f)) ; exit unsuccessfully


(if problem
  (exit some-value)) ; converts "some-value" into an appropriate exit code for your system


When a program is stopped with exit(PROGRAM) allocated memory is freed and open files are closed,

$ include "seed7_05.s7i";

const proc: main is func
    # whatever logic is required in your main procedure
    if some_condition then
    end if;
  end func;


The exit all command halts execution. Open files, sockets, database connections, etc. are closed and allocated memory is freed.

if problemCondition then exit all


if (problem) {


IF terminallyIll THEN terminate_program;

»The procedure "terminate_program" terminates program execution. It closes SYSIN and SYSOUT.

  It is implementation-dependent with respect to whether or not other open files are also closed.« [Simula Standard 86]


problem ifTrue: [exit: 1].


Conditional transfer to the required END label causes immediate termination and normal cleanup. In this example, if condition succeeds (is true), the value of errlevel is assigned to the &code keyword as the exit status of the program, and the :s( ) goto transfers control to END.

        &code = condition errlevel :s(end)


The machine can be halted at any point using a 111 Stop instruction. Since the only conditional operation we have is 011 Test, which has the effect of skipping one word if the number in the accumulator is negative, we had better illustrate it using that.

00000000000000110000000000000000   Test
00000000000001110000000000000000   Stop

This code fragment stops the computer if the accumulator is positive or zero; if it is negative, the Stop instruction is skipped and execution continues from the next instruction.

Standard ML

No cleanup is performed.

if problem then
  OS.Process.exit OS.Process.failure
  (* valid status codes include OS.Process.success and OS.Process.failure *)

The OS.Process.atExit function can be used to register functions to be run when the program exits. Registered functions will be called in the reverse order in which they were registered.


The language runtime (in C) includes a mechanism for cleaning up open resources when the application quits, but access to this is not exposed at script level; extension packages just register with it automatically when required. At the script level, all that is needed to make the program terminate is the exit command:

if {$problem} {
    # Print a “friendly” message...
    puts stderr "some problem occurred"
    # Indicate to the caller of the program that there was a problem
    exit 1

Alternatively, in a top-level script but not an event handler:

if {$problem} {
    error "some problem occurred"


If 1

Return works as well, but if run from inside a subprogram (TI-83 BASIC's version of a function) it will return - hence the function's name - to the main program instead of stopping everything.

When a program is executed, the OS copies its data to another RAM area (0x9D95 on the monochrome calculators, and 0xA60B on the C Silver Edition) and pushes some information about it onto the OS stack. When the program terminates via a Return/Stop statement or error, both of those are removed.




You can either halt the program directly within the conditional...

    LET I = 0
10  IF I = 10 THEN END
    LET I = I + 1
    GOTO 10

...or allow it to fall through to the end of the program.

    LET I = 0
10  LET I = I + 1
    IF I < 10 THEN GOTO 10


(if errorCode
    (exit errorCode))


Every True BASIC program must end with an END statement.


IF (condition==1) STOP
-> execution stops and message:
IF (condition==2) ERROR/STOP "condition ",condition, " Execution STOP "

UNIX Shell

Works with: Bourne Shell

if [ "$a" -eq "$b" ]; then
  exit 239    # Unexpected error
exit 0    # Program terminated normally



Note: the argument to the e function is the return value of the program; however many implementation simply ignore it.

There are no objects to be cleaned up.


Standard Ursa supports the stop function, which immediately halts program execution.



'In case of problem this will terminate the program (without cleanup):
If problem then End
'As VBA is run within an application, such as Excel, a more rigorous way would be:
If problem then Application.Quit
'This will stop the application, but will prompt you to save work.


No matter how deep you're in, wscript.quit will get you out.

dim i, j
j = 0
    for i = 1 to 100
        while j < i
            if i = 3 then
            end if

Vedit macro language

if (#99 == 1) { Return }        // Exit current macro. Return to calling macro.
if (#99 == 2) { Break_Out() }   // Stop all macro execution and return to command mode.
if (#99 == 3) { Exit }          // Exit Vedit. Prompt for saving any changed files.
if (#99 == 4) { Exit(4) }       // As above, but return specified value (instead of 0) to OS
if (#99 == 5) { Xall }          // Exit Vedit. Save changed files without prompting.
if (#99 == 6) { Qall }          // Exit Vedit. Do not save any files.

Return or Break_Out() do not perform any cleanup. If needed, cleanup has to be done in the macro before exit. Special locked-in macro can be used to perform cleanup in case user presses Break key.

When exit from Vedit is done, all the cleanup is performed automatically. Note, however, that if Edit Restore is enabled or a project is open, the session state is saved. In this case, if your macro does not do cleanup, you may eventually run out of free text registers, and you have to do manual cleanup.

Visual Basic

While the example listed under BASIC will work unaltered, it is a terrible idea to use the End keyword in VB. Doing so will cause the immediate termination of the program without any clean up -- forms and other things are left loaded in memory.

When the app needs to end, for whatever reason, problem or not, it's always a good idea to unload the forms first.

Sub Main()
    If problem Then
        For n& = Forms.Count To 0 Step -1
            Unload Forms(n&)
        Exit Sub
    End If
End Sub

V (Vlang)

for num in 1..10 {
	if num == 5 {exit(1)}
Process started >>>
<<< Process finished (Exit code 1)


All Wren code runs within the context of a fiber. Fibers are similar to lightweight co-operatively scheduled threads except that they are managed entirely by Wren's VM and don't use OS thread resources.

A main fiber is created automatically when a script begins and further fibers can then be created as required.

To terminate a script from within a conditional, three options are available: Fiber.suspend, Fiber.abort or the return statement.

Fiber.suspend pauses the current fiber, stops the interpreter and returns control to the host application though the fiber can be resumed later. If called from a Wren CLI script, control simply returns to the operating system as there is no host application as such and therefore no possibility of resumption.

Fiber.abort generally means that a runtime error has occurred though you can still call it if you wish with either no error or a manufactured error. After aborting the current fiber, if the error is not caught, all invoking fibers up to the main one are also aborted and the VM is exited with an appropriate error message and stack trace. As far as I know, no special cleanup is provided by the VM itself.

In module level code (i.e. code which is outside a function or method), the return statement terminates the module and, if it's a single module script, the script itself without error.

The following example illustrates the use of Fiber.suspend in a Wren CLI script.

import "io" for Stdin, Stdout

System.write("Do you want to terminate the program y/n ?  ")
var yn = Stdin.readLine()
if (yn == "y" || yn == "Y") {
    System.print("OK, shutting down")
    Fiber.suspend() // return to OS
System.print("OK, carrying on")
$ wren_cli Program_termination.wren
Do you want to terminate the program y/n ?  y
OK, shutting down


XPL0 cleans up after itself. Its DOS Protected Mode Interface (DPMI) releases extended memory (since DOS can't do it). It restores any system vectors that were altered, such as the divide-by-zero exception vector. It also restores changes made to the 8254 system timer chip (or its equivalent).

The value following 'exit' is optional. It's passed to DOS and can be used by a controlling batch file in an IF ERRORLEVEL statement, and thus change the commands the batch file executes.

if Problem then exit 1;


end may not end your program immediately; if you have opened a window or called 'clear screen', yabasic assumes, that your user wants to study the output of your program after it has ended; therefore it issues the line '---Program done, press RETURN---' and waits for a key to be pressed. If you do not like this behaviour, consider using exit.

exit is similar to end, but it will terminate your program immediately, no matter what.

Z80 Assembly

Zilog Z80

This mostly depends on the hardware, but typically home computers would boot in BASIC and CALL the starting address on the disk. This means that the return address for BASIC is on top of the stack, and an RET will exit the program and return to BASIC, provided that execution is not inside one of the disk's subroutines. The example below is typical of a home computer such as the Amstrad CPC:

;assumes this runs inline
org &1000     ;program start
call GetInput ;unimplemented input get routine, returns key press in accumulator
cp 'Y'        ;compare to ascii capital Y
ret z         ;return to BASIC if equal
jp main       ;loop back to main

Game Boy

The Game Boy doesn't have BASIC to return to, and the HALT and STOP commands are a bit buggy. The easiest way to programmatically terminate the program is to trap the program counter, although it should be warned that doing so will drain the batteries more quickly than you may like.

jr forever


if (die) System.exit();
if (die) System.exit(1);
if (die) System.exit("dumping core");

The parameter to exit (string or number) determines how hard zkl exits. 0 runs the garbage collector to close any orphaned open files, etc. Any other number doesn't. Text will cause a core dump (if $zklDumpCore is set). The OS gets to clean up any mess.