View source with raw comments or as raw
    1/*  Part of SWI-Prolog
    2
    3    Author:        Jan Wielemaker
    4    E-mail:        J.Wielemaker@vu.nl
    5    WWW:           http://www.swi-prolog.org
    6    Copyright (c)  2002-2023, University of Amsterdam
    7                              VU University Amsterdam
    8                              CWI, Amsterdam
    9                              SWI-Prolog Solutions b.v.
   10    All rights reserved.
   11
   12    Redistribution and use in source and binary forms, with or without
   13    modification, are permitted provided that the following conditions
   14    are met:
   15
   16    1. Redistributions of source code must retain the above copyright
   17       notice, this list of conditions and the following disclaimer.
   18
   19    2. Redistributions in binary form must reproduce the above copyright
   20       notice, this list of conditions and the following disclaimer in
   21       the documentation and/or other materials provided with the
   22       distribution.
   23
   24    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   25    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   26    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
   27    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
   28    COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
   29    INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
   30    BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   31    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   32    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   33    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   34    ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   35    POSSIBILITY OF SUCH DAMAGE.
   36*/
   37
   38:- module(time,
   39          [ alarm/3,                    % +Time, :Callable, -Id
   40            alarm/4,                    % +Time, :Callable, -Id, +Options
   41            alarm_at/3,                 % +Time, :Callable, -Id
   42            alarm_at/4,                 % +Time, :Callable, -Id, +Options
   43            remove_alarm/1,             % +Id
   44            install_alarm/1,            % +Id
   45            install_alarm/2,            % +Id, +Time
   46            uninstall_alarm/1,          % +Id
   47            current_alarm/4,            % ?At, ?:Goal, ?Id, ?Status
   48            call_with_time_limit/2,     % +Time, :Callable
   49            call_with_time_limit/3      % +Time, :Callable, +Context
   50          ]).   51:- autoload(library(lists),[member/2]).   52
   53:- set_prolog_flag(generate_debug_info, false).   54
   55:- meta_predicate
   56    call_with_time_limit(+, 0),
   57    call_with_time_limit(+, 0, +),
   58    alarm(+, 0, -),
   59    alarm(+, 0, -, +),
   60    alarm_at(+, 0, -, +),
   61    current_alarm(?, :, ?, ?).   62
   63:- predicate_options(alarm/4, 4,
   64                     [ remove(boolean),
   65                       install(boolean)
   66                     ]).

Time and alarm library

The library(time) provides timing and alarm functions. Alarms are thread-specific, i.e., creating an alarm causes the alarm goal to be called in the thread that created it. The predicate current_alarm/4 only reports alarms that are related to the calling thread. If a thread terminates, all remaining alarms are silently removed. Most applications use call_with_time_limit/2. */

 alarm(+Time, :Callable, -Id) is det
 alarm(+Time, :Callable, -Id, +Options) is det
Set up an alarm to be signaled Time seconds from now. If the alarm expires, Callable is called asynchronously. Callable can be used to raise an exception using throw/1 to abort some execution.

Options is a list of Name(Value) options. Currently defined options are:

remove(Bool)
If true (default false), remove the alarm-event (as remove_alarm/1) after it has been fired.
install(Bool)
If false (default true) do not install the alarm. It must be installed separately using install_alarm/1.
 alarm_at(+Time, :Callable, -Id) is det
 alarm_at(+Time, :Callable, -Id, +Options) is det
As alarm/3 and alarm/4, but schedule the alarm at an absolute point in time.
See also
- date_time_stamp/2.
 install_alarm(+Id) is det
 install_alarm(+Id, +RelTime) is det
Install an alarm allocated using alarm/4 with the install(false) option or de-activated using uninstall_alarm/1. With a given RelTime, the alarm is scheduled at the RelTime from now. Otherwise it is scheduled on the same (absolute) time on which is was created.
 uninstall_alarm(+Id) is det
De-activate an alarm. This does not invalidate Id, but ensures that the alarm will not fire. The alarm can be rescheduled to the original time using install_alarm/1 or to a new time using install_alarm/2.
 remove_alarm(+Id) is det
Remove an alarm. If it has not yet been fired, it never will.
 current_alarm(?Time, :Goal, ?Id, ?Status) is nondet
Enumerate the alarms in the schedule. Time is the absolute time the event is scheduled for (see also get_time/1). Goal is the goal to execute, Id is the identifier and Status is the scheduling status. It takes the value done if the alarm has been fired, next if the event is the next to be executed and scheduled otherwise.
  134:- use_foreign_library(foreign(time)).  135:- public time_debug/1.                 % set debugging
 call_with_time_limit(+Time, :Goal) is det
 call_with_time_limit(+Time, :Goal, +Context) is det
Call Goal, while watching out for a (wall-time) limit. If this limit is exceeded, the exception time_limit_exceeded is raised. call_with_time_limit/3 throws time_limit_exceeded(Context). Goal is called as in once/1.
throws
- time_limit_exceeded (call_with_time_limit/2) or time_limit_exceeded(Context) (call_with_time_limit/3).
  148call_with_time_limit(Time, Goal) :-
  149    call_with_time_limit(Time, Goal, '$no_ctx').
  150
  151call_with_time_limit(Time, Goal, Ctx) :-
  152    Time > 0,
  153    !,
  154    setup_call_cleanup(alarm(Time, time_limit_exceeded(Time, Ctx),
  155                             Id, [install(false)]),
  156                       run_alarm_goal(Id, Goal),
  157                       remove_alarm_notrace(Id)).
  158call_with_time_limit(_Time, _Goal, _Ctx) :-
  159    throw(time_limit_exceeded).
  160
  161run_alarm_goal(AlarmID, Goal) :-
  162    install_alarm(AlarmID),
  163    Goal,
  164    !.
  165
  166time_limit_exceeded(_Time, Ctx) :-
  167    (   Ctx == '$no_ctx'
  168    ->  throw(time_limit_exceeded)
  169    ;   throw(time_limit_exceeded(Ctx))
  170    ).
  171
  172current_alarm(Time, Goal, Id, Status) :-
  173    current_alarms(Time, Goal, Id, Status, List),
  174    member(alarm(Time, Goal, Id, Status), List).
  175
  176                 /*******************************
  177                 *        HANDLE MESSAGES       *
  178                 *******************************/
  179
  180:- multifile
  181    prolog:message/3.  182
  183prolog:message(time_limit_exceeded) -->
  184    [ 'Time limit exceeded' ].
  185prolog:message(time_limit_exceeded(Context)) -->
  186    [ 'Time limit exceeded: ~p'-[Context] ].
  187
  188                 /*******************************
  189                 *             ALARM            *
  190                 *******************************/
  191
  192:- multifile sandbox:safe_meta_predicate/1.  193
  194sandbox:safe_meta_predicate(time:call_with_time_limit/2)