src/Pure/Concurrent/event_timer.ML
author wenzelm
Thu, 24 Jul 2014 11:46:40 +0200
changeset 57639 ba170c8ea578
parent 56768 06388a5cfb7c
child 59329 72278d083d3a
permissions -rw-r--r--
tuned;
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
  eqtype request
56768
06388a5cfb7c added Scala version of module Event_Timer;
wenzelm
parents: 52798
diff changeset
    13
  val request: Time.time -> (unit -> unit) -> request
52050
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    14
  val cancel: request -> bool
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    15
  val shutdown: unit -> unit
52798
9d3c9862d1dd recovered delay for Document.start_execution (see also 627fb639a2d9), which potentially improves throughput when many consecutive edits arrive;
wenzelm
parents: 52589
diff changeset
    16
  val future: Time.time -> unit future
52050
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 request *)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    23
52537
4b5941730bd8 more uniform Counter in ML and Scala;
wenzelm
parents: 52050
diff changeset
    24
val request_counter = Counter.make ();
52050
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    25
datatype request = Request of int;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    26
fun new_request () = Request (request_counter ());
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    27
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    28
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    29
(* type requests *)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    30
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    31
structure Requests = Table(type key = Time.time val ord = Time.compare);
56768
06388a5cfb7c added Scala version of module Event_Timer;
wenzelm
parents: 52798
diff changeset
    32
type requests = (request * (unit -> unit)) list Requests.table;
52050
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    33
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    34
fun add_request time entry (requests: requests) =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    35
  Requests.cons_list (time, entry) requests;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    36
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    37
fun del_request req (requests: requests) =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    38
  let
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    39
    val old_request =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    40
      requests |> Requests.get_first (fn (key, entries) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    41
        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
    42
  in
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    43
    (case old_request of
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    44
      NONE => (false, requests)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    45
    | SOME old => (true, Requests.remove_list (eq_fst op =) old requests))
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    46
  end;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    47
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    48
fun next_request_time (requests: requests) =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    49
  Option.map fst (Requests.min requests);
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    50
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    51
fun next_request_event t0 (requests: requests) =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    52
  (case Requests.min requests of
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    53
    NONE => NONE
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    54
  | SOME (time, entries) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    55
      if Time.< (t0, time) then NONE
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    56
      else
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    57
        let
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    58
          val (rest, (_, event)) = split_last entries;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    59
          val requests' =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    60
            if null rest then Requests.delete time requests
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    61
            else Requests.update (time, rest) requests;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    62
        in SOME (event, requests') end);
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    63
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    64
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    65
(* global state *)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    66
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    67
type state = requests * Thread.thread option;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    68
val init_state: state = (Requests.empty, NONE);
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    69
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    70
val state = Synchronized.var "Event_Timer.state" init_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
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    73
(* manager thread *)
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 manager_timeout = seconds 0.3;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    76
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    77
fun manager_loop () =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    78
  let
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    79
    val success =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    80
      Synchronized.timed_access state
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    81
        (fn (requests, _) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    82
          (case next_request_time requests of
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    83
            NONE => SOME (Time.+ (Time.now (), manager_timeout))
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    84
          | some => some))
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    85
        (fn (requests, manager) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    86
          (case next_request_event (Time.now ()) requests of
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    87
            NONE => NONE
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    88
          | SOME (event, requests') => (Exn.capture event (); SOME ((), (requests', manager)))));
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    89
    val finished =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    90
      is_none success andalso
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    91
        Synchronized.change_result state (fn (requests, manager) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    92
          if Requests.is_empty requests then (true, init_state)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    93
          else (false, (requests, manager)));
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    94
  in if finished then () else manager_loop () end;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    95
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    96
fun manager_check manager =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    97
  if is_some manager andalso Thread.isActive (the manager) then manager
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    98
  else SOME (Simple_Thread.fork false manager_loop);
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    99
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   100
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   101
(* main operations *)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   102
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   103
fun request time event =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   104
  Synchronized.change_result state (fn (requests, manager) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   105
    let
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   106
      val req = new_request ();
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   107
      val requests' = add_request time (req, event) requests;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   108
    in (req, (requests', manager_check manager)) end);
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   109
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   110
fun cancel req =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   111
  Synchronized.change_result state (fn (requests, manager) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   112
    let
52589
wenzelm
parents: 52537
diff changeset
   113
      val (canceled, requests') = del_request req requests;
wenzelm
parents: 52537
diff changeset
   114
    in (canceled, (requests', manager)) end);
52050
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   115
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   116
fun shutdown () =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   117
  Synchronized.guarded_access state (fn (requests, manager) =>
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   118
    if not (Requests.is_empty requests)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   119
    then raise Fail "Cannot shutdown event timer: pending requests"
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   120
    else if is_none manager then SOME ((), init_state)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   121
    else NONE);
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   122
52798
9d3c9862d1dd recovered delay for Document.start_execution (see also 627fb639a2d9), which potentially improves throughput when many consecutive edits arrive;
wenzelm
parents: 52589
diff changeset
   123
9d3c9862d1dd recovered delay for Document.start_execution (see also 627fb639a2d9), which potentially improves throughput when many consecutive edits arrive;
wenzelm
parents: 52589
diff changeset
   124
(* future *)
9d3c9862d1dd recovered delay for Document.start_execution (see also 627fb639a2d9), which potentially improves throughput when many consecutive edits arrive;
wenzelm
parents: 52589
diff changeset
   125
9d3c9862d1dd recovered delay for Document.start_execution (see also 627fb639a2d9), which potentially improves throughput when many consecutive edits arrive;
wenzelm
parents: 52589
diff changeset
   126
val future = uninterruptible (fn _ => fn time =>
9d3c9862d1dd recovered delay for Document.start_execution (see also 627fb639a2d9), which potentially improves throughput when many consecutive edits arrive;
wenzelm
parents: 52589
diff changeset
   127
  let
9d3c9862d1dd recovered delay for Document.start_execution (see also 627fb639a2d9), which potentially improves throughput when many consecutive edits arrive;
wenzelm
parents: 52589
diff changeset
   128
    val req: request Single_Assignment.var = Single_Assignment.var "request";
9d3c9862d1dd recovered delay for Document.start_execution (see also 627fb639a2d9), which potentially improves throughput when many consecutive edits arrive;
wenzelm
parents: 52589
diff changeset
   129
    fun abort () = ignore (cancel (Single_Assignment.await req));
9d3c9862d1dd recovered delay for Document.start_execution (see also 627fb639a2d9), which potentially improves throughput when many consecutive edits arrive;
wenzelm
parents: 52589
diff changeset
   130
    val promise: unit future = Future.promise abort;
9d3c9862d1dd recovered delay for Document.start_execution (see also 627fb639a2d9), which potentially improves throughput when many consecutive edits arrive;
wenzelm
parents: 52589
diff changeset
   131
    val _ = Single_Assignment.assign req (request time (Future.fulfill promise));
9d3c9862d1dd recovered delay for Document.start_execution (see also 627fb639a2d9), which potentially improves throughput when many consecutive edits arrive;
wenzelm
parents: 52589
diff changeset
   132
  in promise end);
9d3c9862d1dd recovered delay for Document.start_execution (see also 627fb639a2d9), which potentially improves throughput when many consecutive edits arrive;
wenzelm
parents: 52589
diff changeset
   133
52050
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   134
end;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   135