| author | wenzelm | 
| Tue, 05 Oct 2021 00:04:01 +0200 | |
| changeset 74460 | ffb15f7f26d5 | 
| parent 73367 | 77ef8bef0593 | 
| child 75380 | 2cb2606ce075 | 
| permissions | -rw-r--r-- | 
| 71692 | 1 | /* Title: Pure/Concurrent/isabelle_thread.scala | 
| 38636 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 2 | Author: Makarius | 
| 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 3 | |
| 71692 | 4 | Isabelle-specific thread management. | 
| 38636 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 5 | */ | 
| 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 6 | |
| 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 7 | package isabelle | 
| 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 8 | |
| 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 9 | |
| 72192 | 10 | import java.util.concurrent.{ThreadPoolExecutor, TimeUnit, LinkedBlockingQueue}
 | 
| 61563 | 11 | |
| 38636 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 12 | |
| 71692 | 13 | object Isabelle_Thread | 
| 38636 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 14 | {
 | 
| 71703 | 15 | /* self-thread */ | 
| 16 | ||
| 17 | def self: Isabelle_Thread = | |
| 18 |     Thread.currentThread match {
 | |
| 19 | case thread: Isabelle_Thread => thread | |
| 71717 | 20 |       case thread => error("Isabelle-specific thread required: " + thread)
 | 
| 71703 | 21 | } | 
| 22 | ||
| 71712 
c6b7f4da67b3
more robust kill: not always running on Isabelle_Thread (e.g. POSIX_Interrupt handler);
 wenzelm parents: 
71711diff
changeset | 23 | def check_self: Boolean = | 
| 
c6b7f4da67b3
more robust kill: not always running on Isabelle_Thread (e.g. POSIX_Interrupt handler);
 wenzelm parents: 
71711diff
changeset | 24 | Thread.currentThread.isInstanceOf[Isabelle_Thread] | 
| 
c6b7f4da67b3
more robust kill: not always running on Isabelle_Thread (e.g. POSIX_Interrupt handler);
 wenzelm parents: 
71711diff
changeset | 25 | |
| 71703 | 26 | |
| 71711 | 27 | /* create threads */ | 
| 71682 | 28 | |
| 29 | private val counter = Counter.make() | |
| 30 | ||
| 71683 | 31 | def make_name(name: String = "", base: String = "thread"): String = | 
| 72334 | 32 |   {
 | 
| 33 | val prefix = "Isabelle." | |
| 34 | val suffix = if (name.nonEmpty) name else base + counter() | |
| 35 | if (suffix.startsWith(prefix)) suffix else prefix + suffix | |
| 36 | } | |
| 71682 | 37 | |
| 71683 | 38 | def current_thread_group: ThreadGroup = Thread.currentThread.getThreadGroup | 
| 39 | ||
| 72148 | 40 | lazy val worker_thread_group: ThreadGroup = | 
| 41 | new ThreadGroup(current_thread_group, "Isabelle worker") | |
| 42 | ||
| 71711 | 43 | def create( | 
| 44 | main: Runnable, | |
| 45 | name: String = "", | |
| 46 | group: ThreadGroup = current_thread_group, | |
| 47 | pri: Int = Thread.NORM_PRIORITY, | |
| 48 | daemon: Boolean = false, | |
| 49 | inherit_locals: Boolean = false): Isabelle_Thread = | |
| 50 |   {
 | |
| 51 | new Isabelle_Thread(main, name = make_name(name = name), group = group, | |
| 52 | pri = pri, daemon = daemon, inherit_locals = inherit_locals) | |
| 53 | } | |
| 54 | ||
| 71685 | 55 | def fork( | 
| 56 | name: String = "", | |
| 57 | group: ThreadGroup = current_thread_group, | |
| 58 | pri: Int = Thread.NORM_PRIORITY, | |
| 59 | daemon: Boolean = false, | |
| 71690 | 60 | inherit_locals: Boolean = false, | 
| 71692 | 61 | uninterruptible: Boolean = false)(body: => Unit): Isabelle_Thread = | 
| 38636 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 62 |   {
 | 
| 71711 | 63 | val main: Runnable = | 
| 64 |       if (uninterruptible) { () => Isabelle_Thread.uninterruptible { body } }
 | |
| 65 |       else { () => body }
 | |
| 71685 | 66 | val thread = | 
| 71711 | 67 | create(main, name = name, group = group, pri = pri, | 
| 68 | daemon = daemon, inherit_locals = inherit_locals) | |
| 38636 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 69 | thread.start | 
| 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 70 | thread | 
| 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 71 | } | 
| 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 72 | |
| 71682 | 73 | |
| 71703 | 74 | /* thread pool */ | 
| 71682 | 75 | |
| 72192 | 76 | def max_threads(): Int = | 
| 77 |   {
 | |
| 78 |     val m = Value.Int.unapply(System.getProperty("isabelle.threads", "0")) getOrElse 0
 | |
| 79 | if (m > 0) m else (Runtime.getRuntime.availableProcessors max 1) min 8 | |
| 80 | } | |
| 81 | ||
| 71703 | 82 | lazy val pool: ThreadPoolExecutor = | 
| 83 |   {
 | |
| 72192 | 84 | val n = max_threads() | 
| 71703 | 85 | val executor = | 
| 86 | new ThreadPoolExecutor(n, n, 2500L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue[Runnable]) | |
| 72148 | 87 | executor.setThreadFactory( | 
| 88 | create(_, name = make_name(base = "worker"), group = worker_thread_group)) | |
| 71703 | 89 | executor | 
| 90 | } | |
| 71682 | 91 | |
| 71701 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 92 | |
| 71702 | 93 | /* interrupt handlers */ | 
| 94 | ||
| 95 | object Interrupt_Handler | |
| 96 |   {
 | |
| 97 | def apply(handle: Isabelle_Thread => Unit, name: String = "handler"): Interrupt_Handler = | |
| 98 | new Interrupt_Handler(handle, name) | |
| 99 | ||
| 100 | val interruptible: Interrupt_Handler = | |
| 101 | Interrupt_Handler(_.raise_interrupt, name = "interruptible") | |
| 71701 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 102 | |
| 71702 | 103 | val uninterruptible: Interrupt_Handler = | 
| 104 | Interrupt_Handler(_.postpone_interrupt, name = "uninterruptible") | |
| 105 | } | |
| 106 | ||
| 107 | class Interrupt_Handler private(handle: Isabelle_Thread => Unit, name: String) | |
| 108 | extends Function[Isabelle_Thread, Unit] | |
| 109 |   {
 | |
| 73340 | 110 | def apply(thread: Isabelle_Thread): Unit = handle(thread) | 
| 71702 | 111 | override def toString: String = name | 
| 112 | } | |
| 71701 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 113 | |
| 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 114 | def interrupt_handler[A](handler: Interrupt_Handler)(body: => A): A = | 
| 71710 | 115 | if (handler == null) body | 
| 116 | else self.interrupt_handler(handler)(body) | |
| 71701 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 117 | |
| 71702 | 118 | def interrupt_handler[A](handle: Isabelle_Thread => Unit)(body: => A): A = | 
| 119 | self.interrupt_handler(Interrupt_Handler(handle))(body) | |
| 120 | ||
| 121 | def interruptible[A](body: => A): A = | |
| 122 | interrupt_handler(Interrupt_Handler.interruptible)(body) | |
| 123 | ||
| 124 | def uninterruptible[A](body: => A): A = | |
| 125 | interrupt_handler(Interrupt_Handler.uninterruptible)(body) | |
| 71712 
c6b7f4da67b3
more robust kill: not always running on Isabelle_Thread (e.g. POSIX_Interrupt handler);
 wenzelm parents: 
71711diff
changeset | 126 | |
| 
c6b7f4da67b3
more robust kill: not always running on Isabelle_Thread (e.g. POSIX_Interrupt handler);
 wenzelm parents: 
71711diff
changeset | 127 | def try_uninterruptible[A](body: => A): A = | 
| 
c6b7f4da67b3
more robust kill: not always running on Isabelle_Thread (e.g. POSIX_Interrupt handler);
 wenzelm parents: 
71711diff
changeset | 128 | if (check_self) interrupt_handler(Interrupt_Handler.uninterruptible)(body) | 
| 
c6b7f4da67b3
more robust kill: not always running on Isabelle_Thread (e.g. POSIX_Interrupt handler);
 wenzelm parents: 
71711diff
changeset | 129 | else body | 
| 38636 
b7647ca7de5a
module for simplified thread operations (Scala version);
 wenzelm parents: diff
changeset | 130 | } | 
| 71681 | 131 | |
| 71711 | 132 | class Isabelle_Thread private(main: Runnable, name: String, group: ThreadGroup, | 
| 133 | pri: Int, daemon: Boolean, inherit_locals: Boolean) | |
| 71685 | 134 | extends Thread(group, null, name, 0L, inherit_locals) | 
| 71681 | 135 | {
 | 
| 136 | thread => | |
| 137 | ||
| 71685 | 138 | thread.setPriority(pri) | 
| 71681 | 139 | thread.setDaemon(daemon) | 
| 140 | ||
| 73340 | 141 | override def run: Unit = main.run() | 
| 71681 | 142 | |
| 71702 | 143 | def is_self: Boolean = Thread.currentThread == thread | 
| 144 | ||
| 71701 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 145 | |
| 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 146 | /* interrupt state */ | 
| 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 147 | |
| 71702 | 148 | // synchronized, with concurrent changes | 
| 149 | private var interrupt_postponed: Boolean = false | |
| 150 | ||
| 151 | def clear_interrupt: Boolean = synchronized | |
| 152 |   {
 | |
| 153 | val was_interrupted = isInterrupted || interrupt_postponed | |
| 154 | Exn.Interrupt.dispose() | |
| 155 | interrupt_postponed = false | |
| 156 | was_interrupted | |
| 157 | } | |
| 71681 | 158 | |
| 71701 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 159 | def raise_interrupt: Unit = synchronized | 
| 71681 | 160 |   {
 | 
| 71702 | 161 | interrupt_postponed = false | 
| 71701 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 162 | super.interrupt() | 
| 71681 | 163 | } | 
| 164 | ||
| 71701 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 165 | def postpone_interrupt: Unit = synchronized | 
| 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 166 |   {
 | 
| 71702 | 167 | interrupt_postponed = true | 
| 71701 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 168 | Exn.Interrupt.dispose() | 
| 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 169 | } | 
| 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 170 | |
| 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 171 | |
| 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 172 | /* interrupt handler */ | 
| 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 173 | |
| 71702 | 174 | // non-synchronized, only changed on self-thread | 
| 175 | @volatile private var handler = Isabelle_Thread.Interrupt_Handler.interruptible | |
| 71701 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 176 | |
| 73367 | 177 | override def interrupt(): Unit = handler(thread) | 
| 71701 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 178 | |
| 
ca926ef898eb
more general interrupt_handler, with some cascading;
 wenzelm parents: 
71694diff
changeset | 179 | def interrupt_handler[A](new_handler: Isabelle_Thread.Interrupt_Handler)(body: => A): A = | 
| 71710 | 180 | if (new_handler == null) body | 
| 181 |     else {
 | |
| 73120 
c3589f2dff31
more informative errors: simplify diagnosis of spurious failures reported by users;
 wenzelm parents: 
72334diff
changeset | 182 | require(is_self, "interrupt handler on other thread") | 
| 71682 | 183 | |
| 71710 | 184 | val old_handler = handler | 
| 185 | handler = new_handler | |
| 186 |       try {
 | |
| 73367 | 187 | if (clear_interrupt) interrupt() | 
| 71710 | 188 | body | 
| 189 | } | |
| 190 |       finally {
 | |
| 191 | handler = old_handler | |
| 73367 | 192 | if (clear_interrupt) interrupt() | 
| 71710 | 193 | } | 
| 71702 | 194 | } | 
| 71681 | 195 | } |