|
14 | 14 | (:import |
15 | 15 | clojure.lang.Var |
16 | 16 | java.lang.AutoCloseable |
| 17 | + java.time.Duration |
17 | 18 | java.util.concurrent.Callable |
18 | 19 | java.util.concurrent.CompletableFuture |
19 | 20 | java.util.concurrent.Executor |
|
32 | 33 |
|
33 | 34 | #?(:clj (set! *warn-on-reflection* true)) |
34 | 35 |
|
35 | | - |
36 | 36 | ;; --- Globals & Defaults (with CLJS Impl) |
37 | 37 |
|
38 | 38 | (declare #?(:clj scheduled-executor :cljs ->ScheduledExecutor)) |
|
223 | 223 | (^Thread newThread [_ ^Runnable runnable] |
224 | 224 | (func runnable))))) |
225 | 225 |
|
226 | | -#?(:clj (def ^{:no-doc true} counter (AtomicLong. 0))) |
| 226 | +#?(:clj (def ^{:no-doc true :dynamic true} |
| 227 | + *default-counter* |
| 228 | + (AtomicLong. 0))) |
| 229 | + |
| 230 | +#?(:clj |
| 231 | + (defn get-next |
| 232 | + "Get next value from atomic long counter" |
| 233 | + {:no-doc true} |
| 234 | + ([] (.getAndIncrement ^AtomicLong *default-counter*)) |
| 235 | + ([counter] (.getAndIncrement ^AtomicLong counter)))) |
227 | 236 |
|
228 | 237 | #?(:clj |
229 | 238 | (defn default-thread-factory |
|
232 | 241 | :or {daemon true |
233 | 242 | priority Thread/NORM_PRIORITY |
234 | 243 | name "promesa/thread/%s"}}] |
235 | | - (reify ThreadFactory |
236 | | - (newThread [this runnable] |
237 | | - (doto (Thread. ^Runnable runnable) |
238 | | - (.setPriority priority) |
239 | | - (.setDaemon ^Boolean daemon) |
240 | | - (.setName (format name (.getAndIncrement ^AtomicLong counter)))))))) |
| 244 | + (let [counter (AtomicLong. 0)] |
| 245 | + (reify ThreadFactory |
| 246 | + (newThread [this runnable] |
| 247 | + (doto (Thread. ^Runnable runnable) |
| 248 | + (.setPriority priority) |
| 249 | + (.setDaemon ^Boolean daemon) |
| 250 | + (.setName (format name (get-next counter))))))))) |
241 | 251 |
|
242 | 252 | #?(:clj |
243 | 253 | (defn default-forkjoin-thread-factory |
244 | 254 | ^ForkJoinPool$ForkJoinWorkerThreadFactory |
245 | 255 | [& {:keys [name daemon] :or {name "promesa/forkjoin/%s" daemon true}}] |
246 | | - (let [^AtomicLong counter (AtomicLong. 0)] |
| 256 | + (let [counter (AtomicLong. 0)] |
247 | 257 | (reify ForkJoinPool$ForkJoinWorkerThreadFactory |
248 | 258 | (newThread [_ pool] |
249 | 259 | (let [thread (.newThread ForkJoinPool/defaultForkJoinWorkerThreadFactory pool) |
250 | | - tname (format name (.getAndIncrement counter))] |
| 260 | + tname (format name (get-next counter))] |
251 | 261 | (.setName ^ForkJoinWorkerThread thread ^String tname) |
252 | 262 | (.setDaemon ^ForkJoinWorkerThread thread ^Boolean daemon) |
253 | 263 | thread)))))) |
254 | 264 |
|
255 | | -#?(:clj |
256 | | - (defn- opts->thread-factory |
257 | | - [{:keys [daemon priority] |
258 | | - :or {daemon true priority Thread/NORM_PRIORITY}}] |
259 | | - (fn->thread-factory |
260 | | - (fn [runnable] |
261 | | - (let [thread (Thread. ^Runnable runnable)] |
262 | | - (.setDaemon thread daemon) |
263 | | - (.setPriority thread priority) |
264 | | - thread))))) |
265 | | - |
266 | 265 | #?(:clj |
267 | 266 | (defn- resolve-thread-factory |
268 | 267 | {:no-doc true} |
|
591 | 590 | (cons (map first ss) (step-fn (map rest ss)))))))] |
592 | 591 | (pmap #(apply f %) (step-fn (cons coll colls))))))) |
593 | 592 |
|
| 593 | +#?(:clj |
| 594 | + (defmacro thread |
| 595 | + "A low-level, not-pooled thread constructor." |
| 596 | + [opts & body] |
| 597 | + (let [[opts body] (if (map? opts) |
| 598 | + [opts body] |
| 599 | + [nil (cons opts body)])] |
| 600 | + `(let [opts# ~opts |
| 601 | + thr# (Thread. (^:once fn* [] ~@body))] |
| 602 | + (.setName thr# (or (:name ~opts) (format "promesa/unnamed-thread/%s" (get-next)))) |
| 603 | + (.setDaemon thr# (:daemon? ~opts false)) |
| 604 | + (.setPriority thr# (:priority ~opts Thread/NORM_PRIORITY)) |
| 605 | + (.start thr#) |
| 606 | + thr#)))) |
| 607 | + |
| 608 | +#?(:clj |
| 609 | +(defn current-thread |
| 610 | + "Return the current thread." |
| 611 | + [] |
| 612 | + (Thread/currentThread))) |
594 | 613 |
|
| 614 | +#?(:clj |
| 615 | +(defn thread-interrupted? |
| 616 | + "Check if the thread has the interrupted flag set. |
| 617 | +
|
| 618 | + There are two special cases: |
| 619 | +
|
| 620 | + Using the `:current` keyword as argument will check the interrupted |
| 621 | + flag on the current thread. |
| 622 | +
|
| 623 | + Using the arity 0 (passing no arguments), then the current thread |
| 624 | + will be checked and **WARNING** the interrupted flag reset to |
| 625 | + `false`." |
| 626 | + ([] |
| 627 | + (Thread/interrupted)) |
| 628 | + ([thread] |
| 629 | + (if (= :current thread) |
| 630 | + (.isInterrupted (Thread/currentThread)) |
| 631 | + (.isInterrupted ^Thread thread))))) |
| 632 | + |
| 633 | +#?(:clj |
| 634 | +(defn thread-id |
| 635 | + "Retrieves the thread ID." |
| 636 | + ([] |
| 637 | + (.getId ^Thread (Thread/currentThread))) |
| 638 | + ([^Thread thread] |
| 639 | + (.getId thread)))) |
| 640 | + |
| 641 | +#?(:clj |
| 642 | +(defn interrupt-thread! |
| 643 | + [^Thread thread] |
| 644 | + (.interrupt thread))) |
| 645 | + |
| 646 | +#?(:clj |
| 647 | +(defn join! |
| 648 | + "Waits for the specified thread to terminate." |
| 649 | + ([^Thread thread] |
| 650 | + (.join thread)) |
| 651 | + ([^Thread thread duration] |
| 652 | + (if (instance? Duration duration) |
| 653 | + (.join thread ^Duration duration) |
| 654 | + (.join thread (long duration)))))) |
0 commit comments