src/Pure/Concurrent/event_timer.ML
author wenzelm
Thu, 30 May 2013 17:10:13 +0200
changeset 52244 cb15da7bd550
parent 52050 b40ed9dcf903
child 52537 4b5941730bd8
permissions -rw-r--r--
misc tuning;
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
52050
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
     1
(*  Title:      Pure/Concurrent/event_timer.ML
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
     2
    Author:     Makarius
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
     3
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
     4
Initiate event after given point in time.
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
     5
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
     6
Note: events are run as synchronized action within a dedicated thread
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
     7
and should finish quickly without further ado.
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
     8
*)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
     9
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    10
signature EVENT_TIMER =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    11
sig
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    12
  type event = unit -> unit
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    13
  eqtype request
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    14
  val request: Time.time -> event -> request
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    15
  val cancel: request -> bool
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    16
  val shutdown: unit -> unit
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    17
end;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    18
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    19
structure Event_Timer: EVENT_TIMER =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    20
struct
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    21
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    22
(* type event *)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    23
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    24
type event = unit -> unit;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    25
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    26
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    27
(* type request *)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    28
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    29
val request_counter = Synchronized.counter ();
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    30
datatype request = Request of int;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    31
fun new_request () = Request (request_counter ());
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    32
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    33
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    34
(* type requests *)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    35
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    36
structure Requests = Table(type key = Time.time val ord = Time.compare);
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    37
type requests = (request * event) list Requests.table;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    38
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    39
fun add_request time entry (requests: requests) =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    40
  Requests.cons_list (time, entry) requests;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    41
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    42
fun del_request req (requests: requests) =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    43
  let
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    44
    val old_request =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    45
      requests |> Requests.get_first (fn (key, entries) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    46
        entries |> get_first (fn entry => if fst entry = req then SOME (key, entry) else NONE));
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    47
  in
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    48
    (case old_request of
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    49
      NONE => (false, requests)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    50
    | SOME old => (true, Requests.remove_list (eq_fst op =) old requests))
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    51
  end;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    52
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    53
fun next_request_time (requests: requests) =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    54
  Option.map fst (Requests.min requests);
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    55
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    56
fun next_request_event t0 (requests: requests) =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    57
  (case Requests.min requests of
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    58
    NONE => NONE
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    59
  | SOME (time, entries) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    60
      if Time.< (t0, time) then NONE
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    61
      else
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    62
        let
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    63
          val (rest, (_, event)) = split_last entries;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    64
          val requests' =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    65
            if null rest then Requests.delete time requests
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    66
            else Requests.update (time, rest) requests;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    67
        in SOME (event, requests') end);
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    68
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    69
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    70
(* global state *)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    71
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    72
type state = requests * Thread.thread option;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    73
val init_state: state = (Requests.empty, NONE);
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    74
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    75
val state = Synchronized.var "Event_Timer.state" init_state;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    76
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    77
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    78
(* manager thread *)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    79
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    80
val manager_timeout = seconds 0.3;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    81
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    82
fun manager_loop () =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    83
  let
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    84
    val success =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    85
      Synchronized.timed_access state
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    86
        (fn (requests, _) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    87
          (case next_request_time requests of
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    88
            NONE => SOME (Time.+ (Time.now (), manager_timeout))
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    89
          | some => some))
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    90
        (fn (requests, manager) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    91
          (case next_request_event (Time.now ()) requests of
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    92
            NONE => NONE
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    93
          | SOME (event, requests') => (Exn.capture event (); SOME ((), (requests', manager)))));
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    94
    val finished =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    95
      is_none success andalso
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    96
        Synchronized.change_result state (fn (requests, manager) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    97
          if Requests.is_empty requests then (true, init_state)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    98
          else (false, (requests, manager)));
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    99
  in if finished then () else manager_loop () end;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   100
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   101
fun manager_check manager =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   102
  if is_some manager andalso Thread.isActive (the manager) then manager
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   103
  else SOME (Simple_Thread.fork false manager_loop);
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   104
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   105
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   106
(* main operations *)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   107
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   108
fun request time event =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   109
  Synchronized.change_result state (fn (requests, manager) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   110
    let
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   111
      val req = new_request ();
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   112
      val requests' = add_request time (req, event) requests;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   113
    in (req, (requests', manager_check manager)) end);
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   114
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   115
fun cancel req =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   116
  Synchronized.change_result state (fn (requests, manager) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   117
    let
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   118
      val (cancelled, requests') = del_request req requests;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   119
    in (cancelled, (requests', manager)) end);
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   120
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   121
fun shutdown () =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   122
  Synchronized.guarded_access state (fn (requests, manager) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   123
    if not (Requests.is_empty requests)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   124
    then raise Fail "Cannot shutdown event timer: pending requests"
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   125
    else if is_none manager then SOME ((), init_state)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   126
    else NONE);
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   127
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   128
end;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   129