src/Pure/Concurrent/event_timer.ML
author wenzelm
Wed, 06 Apr 2016 17:16:30 +0200
changeset 62891 7a11ea5c9626
parent 62826 eb94e570c1a4
child 62923 3a122e1e352a
permissions -rw-r--r--
tuned signature;
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
59339
wenzelm
parents: 59337
diff changeset
    15
  val future: Time.time -> unit future
52050
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 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) =>
62826
eb94e570c1a4 prefer infix operations;
wenzelm
parents: 62239
diff changeset
    55
      if t0 < time then NONE
52050
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
59329
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    67
datatype status = Normal | Shutdown_Req | Shutdown_Ack;
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    68
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    69
datatype state =
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    70
  State of {requests: requests, status: status, manager: Thread.thread option};
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    71
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    72
fun make_state (requests, status, manager) =
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    73
  State {requests = requests, status = status, manager = manager};
52050
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    74
59329
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    75
val normal_state = make_state (Requests.empty, Normal, NONE);
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    76
val shutdown_ack_state = make_state (Requests.empty, Shutdown_Ack, NONE);
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    77
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    78
fun is_shutdown s (State {requests, status, manager}) =
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    79
  Requests.is_empty requests andalso status = s andalso is_none manager;
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    80
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    81
fun is_shutdown_req (State {requests, status, ...}) =
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    82
  Requests.is_empty requests andalso status = Shutdown_Req;
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    83
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    84
val state = Synchronized.var "Event_Timer.state" normal_state;
52050
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    85
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    86
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    87
(* manager thread *)
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    88
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
    89
fun manager_loop () =
59329
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    90
  if Synchronized.timed_access state
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    91
    (fn State {requests, ...} => next_request_time requests)
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    92
    (fn st as State {requests, status, manager} =>
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    93
      (case next_request_event (Time.now ()) requests of
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    94
        SOME (event, requests') =>
59337
wenzelm
parents: 59329
diff changeset
    95
          let
wenzelm
parents: 59329
diff changeset
    96
            val _ = Exn.capture event ();
wenzelm
parents: 59329
diff changeset
    97
            val state' = make_state (requests', status, manager);
wenzelm
parents: 59329
diff changeset
    98
          in SOME (true, state') end
59329
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
    99
      | NONE =>
59337
wenzelm
parents: 59329
diff changeset
   100
          if is_shutdown_req st
wenzelm
parents: 59329
diff changeset
   101
          then SOME (false, shutdown_ack_state)
59339
wenzelm
parents: 59337
diff changeset
   102
          else NONE)) <> SOME false
wenzelm
parents: 59337
diff changeset
   103
  then manager_loop () else ();
52050
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   104
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   105
fun manager_check manager =
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   106
  if is_some manager andalso Thread.isActive (the manager) then manager
60764
b610ba36e02c more explicit thread identification;
wenzelm
parents: 59468
diff changeset
   107
  else
61556
0d4ee4168e41 clarified modules;
wenzelm
parents: 60764
diff changeset
   108
    SOME (Standard_Thread.fork {name = "event_timer", stack_limit = NONE, interrupts = false}
60764
b610ba36e02c more explicit thread identification;
wenzelm
parents: 59468
diff changeset
   109
      manager_loop);
52050
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   110
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   111
fun shutdown () =
62891
7a11ea5c9626 tuned signature;
wenzelm
parents: 62826
diff changeset
   112
  Multithreading.uninterruptible (fn restore_attributes => fn () =>
62239
wenzelm
parents: 61556
diff changeset
   113
    if Synchronized.change_result state (fn st as State {requests, manager, ...} =>
59337
wenzelm
parents: 59329
diff changeset
   114
      if is_shutdown Normal st then (false, st)
wenzelm
parents: 59329
diff changeset
   115
      else if is_shutdown Shutdown_Ack st orelse is_shutdown_req st then
59329
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
   116
        raise Fail "Concurrent attempt to shutdown event timer"
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
   117
      else (true, make_state (requests, Shutdown_Req, manager_check manager)))
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
   118
    then
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
   119
      restore_attributes (fn () =>
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
   120
        Synchronized.guarded_access state
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
   121
          (fn st => if is_shutdown Shutdown_Ack st then SOME ((), normal_state) else NONE)) ()
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
   122
      handle exn =>
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
   123
        if Exn.is_interrupt exn then
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
   124
          Synchronized.change state (fn State {requests, manager, ...} =>
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
   125
            make_state (requests, Normal, manager))
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
   126
        else ()
72278d083d3a clarified Event_Timer.shutdown: manager thread remains until final shutdown in Session.finish;
wenzelm
parents: 56768
diff changeset
   127
    else ()) ();
52050
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   128
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
   129
59339
wenzelm
parents: 59337
diff changeset
   130
(* main operations *)
wenzelm
parents: 59337
diff changeset
   131
wenzelm
parents: 59337
diff changeset
   132
fun request time event =
wenzelm
parents: 59337
diff changeset
   133
  Synchronized.change_result state (fn State {requests, status, manager} =>
wenzelm
parents: 59337
diff changeset
   134
    let
wenzelm
parents: 59337
diff changeset
   135
      val req = new_request ();
wenzelm
parents: 59337
diff changeset
   136
      val requests' = add_request time (req, event) requests;
wenzelm
parents: 59337
diff changeset
   137
      val manager' = manager_check manager;
wenzelm
parents: 59337
diff changeset
   138
    in (req, make_state (requests', status, manager')) end);
wenzelm
parents: 59337
diff changeset
   139
wenzelm
parents: 59337
diff changeset
   140
fun cancel req =
wenzelm
parents: 59337
diff changeset
   141
  Synchronized.change_result state (fn State {requests, status, manager} =>
wenzelm
parents: 59337
diff changeset
   142
    let
wenzelm
parents: 59337
diff changeset
   143
      val (canceled, requests') = del_request req requests;
wenzelm
parents: 59337
diff changeset
   144
      val manager' = manager_check manager;
wenzelm
parents: 59337
diff changeset
   145
    in (canceled, make_state (requests', status, manager')) end);
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
   146
62891
7a11ea5c9626 tuned signature;
wenzelm
parents: 62826
diff changeset
   147
val future = Multithreading.uninterruptible (fn _ => fn time =>
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
   148
  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
   149
    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
   150
    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
   151
    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
   152
    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
   153
  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
   154
52050
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   155
end;
b40ed9dcf903 event timer as separate service thread;
wenzelm
parents:
diff changeset
   156