1 /*
2  * Hunt - A refined core library for D programming language.
3  *
4  * Copyright (C) 2018-2019 HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.concurrency.Executors;
13 
14 import hunt.concurrency.AbstractExecutorService;
15 import hunt.concurrency.atomic.AtomicHelper;
16 import hunt.concurrency.Delayed;
17 import hunt.concurrency.Exceptions;
18 import hunt.concurrency.ExecutorService;
19 // import hunt.concurrency.ForkJoinPool;
20 import hunt.concurrency.Future;
21 import hunt.concurrency.LinkedBlockingQueue;
22 import hunt.concurrency.ScheduledExecutorService;
23 import hunt.concurrency.ScheduledThreadPoolExecutor;
24 import hunt.concurrency.ThreadFactory;
25 import hunt.concurrency.ThreadPoolExecutor;
26 
27 import hunt.collection.List;
28 import hunt.Exceptions;
29 import hunt.util.Common;
30 import hunt.util.DateTime;
31 
32 import core.thread;
33 import core.time;
34 import std.conv;
35 
36 // import static java.lang.ref.Reference.reachabilityFence;
37 // import java.security.AccessControlContext;
38 // import java.security.AccessControlException;
39 // import java.security.AccessController;
40 // import java.security.PrivilegedAction;
41 // import java.security.PrivilegedActionException;
42 // import java.security.PrivilegedExceptionAction;
43 // import hunt.collection.Collection;
44 // import java.util.List;
45 // import sun.security.util.SecurityConstants;
46 
47 /**
48  * Factory and utility methods for {@link Executor}, {@link
49  * ExecutorService}, {@link ScheduledExecutorService}, {@link
50  * ThreadFactory}, and {@link Callable} classes defined in this
51  * package. This class supports the following kinds of methods:
52  *
53  * <ul>
54  *   <li>Methods that create and return an {@link ExecutorService}
55  *       set up with commonly useful configuration settings.
56  *   <li>Methods that create and return a {@link ScheduledExecutorService}
57  *       set up with commonly useful configuration settings.
58  *   <li>Methods that create and return a "wrapped" ExecutorService, that
59  *       disables reconfiguration by making implementation-specific methods
60  *       inaccessible.
61  *   <li>Methods that create and return a {@link ThreadFactory}
62  *       that sets newly created threads to a known state.
63  *   <li>Methods that create and return a {@link Callable}
64  *       out of other closure-like forms, so they can be used
65  *       in execution methods requiring {@code Callable}.
66  * </ul>
67  *
68  * @author Doug Lea
69  */
70 class Executors {
71 
72     /**
73      * Creates a thread pool that reuses a fixed number of threads
74      * operating off a shared unbounded queue.  At any point, at most
75      * {@code nThreads} threads will be active processing tasks.
76      * If additional tasks are submitted when all threads are active,
77      * they will wait in the queue until a thread is available.
78      * If any thread terminates due to a failure during execution
79      * prior to shutdown, a new one will take its place if needed to
80      * execute subsequent tasks.  The threads in the pool will exist
81      * until it is explicitly {@link ExecutorService#shutdown shutdown}.
82      *
83      * @param nThreads the number of threads in the pool
84      * @return the newly created thread pool
85      * @throws IllegalArgumentException if {@code nThreads <= 0}
86      */
87     static ThreadPoolExecutor newFixedThreadPool(int nThreads) {
88         return new ThreadPoolExecutor(nThreads, nThreads, 0.hnsecs,
89                                       new LinkedBlockingQueue!(Runnable)());
90     }
91 
92     // /**
93     //  * Creates a thread pool that maintains enough threads to support
94     //  * the given parallelism level, and may use multiple queues to
95     //  * reduce contention. The parallelism level corresponds to the
96     //  * maximum number of threads actively engaged in, or available to
97     //  * engage in, task processing. The actual number of threads may
98     //  * grow and shrink dynamically. A work-stealing pool makes no
99     //  * guarantees about the order in which submitted tasks are
100     //  * executed.
101     //  *
102     //  * @param parallelism the targeted parallelism level
103     //  * @return the newly created thread pool
104     //  * @throws IllegalArgumentException if {@code parallelism <= 0}
105     //  */
106     // static ExecutorService newWorkStealingPool(int parallelism) {
107     //     return new ForkJoinPool
108     //         (parallelism,
109     //          ForkJoinPool.defaultForkJoinWorkerThreadFactory,
110     //          null, true);
111     // }
112 
113     // /**
114     //  * Creates a work-stealing thread pool using the number of
115     //  * {@linkplain Runtime#availableProcessors available processors}
116     //  * as its target parallelism level.
117     //  *
118     //  * @return the newly created thread pool
119     //  * @see #newWorkStealingPool(int)
120     //  */
121     // static ExecutorService newWorkStealingPool() {
122     //     return new ForkJoinPool
123     //         (Runtime.getRuntime().availableProcessors(),
124     //          ForkJoinPool.defaultForkJoinWorkerThreadFactory,
125     //          null, true);
126     // }
127 
128     /**
129      * Creates a thread pool that reuses a fixed number of threads
130      * operating off a shared unbounded queue, using the provided
131      * ThreadFactory to create new threads when needed.  At any point,
132      * at most {@code nThreads} threads will be active processing
133      * tasks.  If additional tasks are submitted when all threads are
134      * active, they will wait in the queue until a thread is
135      * available.  If any thread terminates due to a failure during
136      * execution prior to shutdown, a new one will take its place if
137      * needed to execute subsequent tasks.  The threads in the pool will
138      * exist until it is explicitly {@link ExecutorService#shutdown
139      * shutdown}.
140      *
141      * @param nThreads the number of threads in the pool
142      * @param threadFactory the factory to use when creating new threads
143      * @return the newly created thread pool
144      * @throws NullPointerException if threadFactory is null
145      * @throws IllegalArgumentException if {@code nThreads <= 0}
146      */
147     static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
148         return new ThreadPoolExecutor(nThreads, nThreads, 0.msecs,
149                                       new LinkedBlockingQueue!(Runnable)(),
150                                       threadFactory);
151     }
152 
153     /**
154      * Creates an Executor that uses a single worker thread operating
155      * off an unbounded queue. (Note however that if this single
156      * thread terminates due to a failure during execution prior to
157      * shutdown, a new one will take its place if needed to execute
158      * subsequent tasks.)  Tasks are guaranteed to execute
159      * sequentially, and no more than one task will be active at any
160      * given time. Unlike the otherwise equivalent
161      * {@code newFixedThreadPool(1)} the returned executor is
162      * guaranteed not to be reconfigurable to use additional threads.
163      *
164      * @return the newly created single-threaded Executor
165      */
166     // static ExecutorService newSingleThreadExecutor() {
167     //     return new FinalizableDelegatedExecutorService
168     //         (new ThreadPoolExecutor(1, 1,
169     //                                 0L, TimeUnit.MILLISECONDS,
170     //                                 new LinkedBlockingQueue!(Runnable)()));
171     // }
172 
173     // /**
174     //  * Creates an Executor that uses a single worker thread operating
175     //  * off an unbounded queue, and uses the provided ThreadFactory to
176     //  * create a new thread when needed. Unlike the otherwise
177     //  * equivalent {@code newFixedThreadPool(1, threadFactory)} the
178     //  * returned executor is guaranteed not to be reconfigurable to use
179     //  * additional threads.
180     //  *
181     //  * @param threadFactory the factory to use when creating new threads
182     //  * @return the newly created single-threaded Executor
183     //  * @throws NullPointerException if threadFactory is null
184     //  */
185     // static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
186     //     return new FinalizableDelegatedExecutorService
187     //         (new ThreadPoolExecutor(1, 1,
188     //                                 0L, TimeUnit.MILLISECONDS,
189     //                                 new LinkedBlockingQueue!(Runnable)(),
190     //                                 threadFactory));
191     // }
192 
193     /**
194      * Creates a thread pool that creates new threads as needed, but
195      * will reuse previously constructed threads when they are
196      * available.  These pools will typically improve the performance
197      * of programs that execute many short-lived asynchronous tasks.
198      * Calls to {@code execute} will reuse previously constructed
199      * threads if available. If no existing thread is available, a new
200      * thread will be created and added to the pool. Threads that have
201      * not been used for sixty seconds are terminated and removed from
202      * the cache. Thus, a pool that remains idle for long enough will
203      * not consume any resources. Note that pools with similar
204      * properties but different details (for example, timeout parameters)
205      * may be created using {@link ThreadPoolExecutor} constructors.
206      *
207      * @return the newly created thread pool
208      */
209     // static ExecutorService newCachedThreadPool() {
210     //     return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
211     //                                   60L, TimeUnit.SECONDS,
212     //                                   new SynchronousQueue!(Runnable)());
213     // }
214 
215     // /**
216     //  * Creates a thread pool that creates new threads as needed, but
217     //  * will reuse previously constructed threads when they are
218     //  * available, and uses the provided
219     //  * ThreadFactory to create new threads when needed.
220     //  *
221     //  * @param threadFactory the factory to use when creating new threads
222     //  * @return the newly created thread pool
223     //  * @throws NullPointerException if threadFactory is null
224     //  */
225     // static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
226     //     return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
227     //                                   60L, TimeUnit.SECONDS,
228     //                                   new SynchronousQueue!(Runnable)(),
229     //                                   threadFactory);
230     // }
231 
232     /**
233      * Creates a single-threaded executor that can schedule commands
234      * to run after a given delay, or to execute periodically.
235      * (Note however that if this single
236      * thread terminates due to a failure during execution prior to
237      * shutdown, a new one will take its place if needed to execute
238      * subsequent tasks.)  Tasks are guaranteed to execute
239      * sequentially, and no more than one task will be active at any
240      * given time. Unlike the otherwise equivalent
241      * {@code newScheduledThreadPool(1)} the returned executor is
242      * guaranteed not to be reconfigurable to use additional threads.
243      *
244      * @return the newly created scheduled executor
245      */
246     static ScheduledExecutorService newSingleThreadScheduledExecutor() {
247         return new DelegatedScheduledExecutorService!ScheduledThreadPoolExecutor
248             (new ScheduledThreadPoolExecutor(1));
249     }
250 
251     /**
252      * Creates a single-threaded executor that can schedule commands
253      * to run after a given delay, or to execute periodically.  (Note
254      * however that if this single thread terminates due to a failure
255      * during execution prior to shutdown, a new one will take its
256      * place if needed to execute subsequent tasks.)  Tasks are
257      * guaranteed to execute sequentially, and no more than one task
258      * will be active at any given time. Unlike the otherwise
259      * equivalent {@code newScheduledThreadPool(1, threadFactory)}
260      * the returned executor is guaranteed not to be reconfigurable to
261      * use additional threads.
262      *
263      * @param threadFactory the factory to use when creating new threads
264      * @return the newly created scheduled executor
265      * @throws NullPointerException if threadFactory is null
266      */
267     static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
268         return new DelegatedScheduledExecutorService!ScheduledThreadPoolExecutor
269             (new ScheduledThreadPoolExecutor(1, threadFactory));
270     }
271 
272     /**
273      * Creates a thread pool that can schedule commands to run after a
274      * given delay, or to execute periodically.
275      * @param corePoolSize the number of threads to keep in the pool,
276      * even if they are idle
277      * @return the newly created scheduled thread pool
278      * @throws IllegalArgumentException if {@code corePoolSize < 0}
279      */
280     static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
281         return new ScheduledThreadPoolExecutor(corePoolSize);
282     }
283 
284     /**
285      * Creates a thread pool that can schedule commands to run after a
286      * given delay, or to execute periodically.
287      * @param corePoolSize the number of threads to keep in the pool,
288      * even if they are idle
289      * @param threadFactory the factory to use when the executor
290      * creates a new thread
291      * @return the newly created scheduled thread pool
292      * @throws IllegalArgumentException if {@code corePoolSize < 0}
293      * @throws NullPointerException if threadFactory is null
294      */
295     static ScheduledExecutorService newScheduledThreadPool(
296             int corePoolSize, ThreadFactory threadFactory) {
297         return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
298     }
299 
300     // /**
301     //  * Returns an object that delegates all defined {@link
302     //  * ExecutorService} methods to the given executor, but not any
303     //  * other methods that might otherwise be accessible using
304     //  * casts. This provides a way to safely "freeze" configuration and
305     //  * disallow tuning of a given concrete implementation.
306     //  * @param executor the underlying implementation
307     //  * @return an {@code ExecutorService} instance
308     //  * @throws NullPointerException if executor null
309     //  */
310     // static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
311     //     if (executor is null)
312     //         throw new NullPointerException();
313     //     return new DelegatedExecutorService(executor);
314     // }
315 
316     // /**
317     //  * Returns an object that delegates all defined {@link
318     //  * ScheduledExecutorService} methods to the given executor, but
319     //  * not any other methods that might otherwise be accessible using
320     //  * casts. This provides a way to safely "freeze" configuration and
321     //  * disallow tuning of a given concrete implementation.
322     //  * @param executor the underlying implementation
323     //  * @return a {@code ScheduledExecutorService} instance
324     //  * @throws NullPointerException if executor null
325     //  */
326     // static ScheduledExecutorService unconfigurableScheduledExecutorService(ScheduledExecutorService executor) {
327     //     if (executor is null)
328     //         throw new NullPointerException();
329     //     return new DelegatedScheduledExecutorService(executor);
330     // }
331 
332     /**
333      * Returns a default thread factory used to create new threads.
334      * This factory creates all new threads used by an Executor in the
335      * same {@link ThreadGroupEx}. If there is a {@link
336      * java.lang.SecurityManager}, it uses the group of {@link
337      * System#getSecurityManager}, else the group of the thread
338      * invoking this {@code defaultThreadFactory} method. Each new
339      * thread is created as a non-daemon thread with priority set to
340      * the smaller of {@code Thread.PRIORITY_DEFAULT} and the maximum
341      * priority permitted in the thread group.  New threads have names
342      * accessible via {@link Thread#getName} of
343      * <em>pool-N-thread-M</em>, where <em>N</em> is the sequence
344      * number of this factory, and <em>M</em> is the sequence number
345      * of the thread created by this factory.
346      * @return a thread factory
347      */
348     static ThreadFactory defaultThreadFactory() {
349         return ThreadFactory.defaultThreadFactory();
350     }
351 
352     // /**
353     //  * Returns a thread factory used to create new threads that
354     //  * have the same permissions as the current thread.
355     //  * This factory creates threads with the same settings as {@link
356     //  * Executors#defaultThreadFactory}, additionally setting the
357     //  * AccessControlContext and contextClassLoader of new threads to
358     //  * be the same as the thread invoking this
359     //  * {@code privilegedThreadFactory} method.  A new
360     //  * {@code privilegedThreadFactory} can be created within an
361     //  * {@link AccessController#doPrivileged AccessController.doPrivileged}
362     //  * action setting the current thread's access control context to
363     //  * create threads with the selected permission settings holding
364     //  * within that action.
365     //  *
366     //  * <p>Note that while tasks running within such threads will have
367     //  * the same access control and class loader settings as the
368     //  * current thread, they need not have the same {@link
369     //  * java.lang.ThreadLocal} or {@link
370     //  * java.lang.InheritableThreadLocal} values. If necessary,
371     //  * particular values of thread locals can be set or reset before
372     //  * any task runs in {@link ThreadPoolExecutor} subclasses using
373     //  * {@link ThreadPoolExecutor#beforeExecute(Thread, Runnable)}.
374     //  * Also, if it is necessary to initialize worker threads to have
375     //  * the same InheritableThreadLocal settings as some other
376     //  * designated thread, you can create a custom ThreadFactory in
377     //  * which that thread waits for and services requests to create
378     //  * others that will inherit its values.
379     //  *
380     //  * @return a thread factory
381     //  * @throws AccessControlException if the current access control
382     //  * context does not have permission to both get and set context
383     //  * class loader
384     //  */
385     // static ThreadFactory privilegedThreadFactory() {
386     //     return new PrivilegedThreadFactory();
387     // }
388 
389     /**
390      * Returns a {@link Callable} object that, when
391      * called, runs the given task and returns the given result.  This
392      * can be useful when applying methods requiring a
393      * {@code Callable} to an otherwise resultless action.
394      * @param task the task to run
395      * @param result the result to return
396      * @param (T) the type of the result
397      * @return a callable object
398      * @throws NullPointerException if task null
399      */
400     static Callable!(void) callable(Runnable task) {
401         if (task is null)
402             throw new NullPointerException();
403         return new RunnableAdapter!(void)(task);
404     }
405 
406     static Callable!(T) callable(T)(Runnable task, T result) if(!is(T == void)) {
407         if (task is null)
408             throw new NullPointerException();
409         return new RunnableAdapter!(T)(task, result);
410     }
411 
412     /**
413      * Returns a {@link Callable} object that, when
414      * called, runs the given task and returns {@code null}.
415      * @param task the task to run
416      * @return a callable object
417      * @throws NullPointerException if task null
418      */
419     // static Callable!(Object) callable(Runnable task) {
420     //     if (task is null)
421     //         throw new NullPointerException();
422     //     return new RunnableAdapter!(Object)(task, null);
423     // }
424 
425     // /**
426     //  * Returns a {@link Callable} object that, when
427     //  * called, runs the given privileged action and returns its result.
428     //  * @param action the privileged action to run
429     //  * @return a callable object
430     //  * @throws NullPointerException if action null
431     //  */
432     // static Callable!(Object) callable(PrivilegedAction<?> action) {
433     //     if (action is null)
434     //         throw new NullPointerException();
435     //     return new Callable!(Object)() {
436     //         Object call() { return action.run(); }};
437     // }
438 
439     // /**
440     //  * Returns a {@link Callable} object that, when
441     //  * called, runs the given privileged exception action and returns
442     //  * its result.
443     //  * @param action the privileged exception action to run
444     //  * @return a callable object
445     //  * @throws NullPointerException if action null
446     //  */
447     // static Callable!(Object) callable(PrivilegedExceptionAction<?> action) {
448     //     if (action is null)
449     //         throw new NullPointerException();
450     //     return new Callable!(Object)() {
451     //         Object call() throws Exception { return action.run(); }};
452     // }
453 
454     // /**
455     //  * Returns a {@link Callable} object that will, when called,
456     //  * execute the given {@code callable} under the current access
457     //  * control context. This method should normally be invoked within
458     //  * an {@link AccessController#doPrivileged AccessController.doPrivileged}
459     //  * action to create callables that will, if possible, execute
460     //  * under the selected permission settings holding within that
461     //  * action; or if not possible, throw an associated {@link
462     //  * AccessControlException}.
463     //  * @param callable the underlying task
464     //  * @param (T) the type of the callable's result
465     //  * @return a callable object
466     //  * @throws NullPointerException if callable null
467     //  */
468     // static !(T) Callable!(T) privilegedCallable(Callable!(T) callable) {
469     //     if (callable is null)
470     //         throw new NullPointerException();
471     //     return new PrivilegedCallable!(T)(callable);
472     // }
473 
474     // /**
475     //  * Returns a {@link Callable} object that will, when called,
476     //  * execute the given {@code callable} under the current access
477     //  * control context, with the current context class loader as the
478     //  * context class loader. This method should normally be invoked
479     //  * within an
480     //  * {@link AccessController#doPrivileged AccessController.doPrivileged}
481     //  * action to create callables that will, if possible, execute
482     //  * under the selected permission settings holding within that
483     //  * action; or if not possible, throw an associated {@link
484     //  * AccessControlException}.
485     //  *
486     //  * @param callable the underlying task
487     //  * @param (T) the type of the callable's result
488     //  * @return a callable object
489     //  * @throws NullPointerException if callable null
490     //  * @throws AccessControlException if the current access control
491     //  * context does not have permission to both set and get context
492     //  * class loader
493     //  */
494     // static !(T) Callable!(T) privilegedCallableUsingCurrentClassLoader(Callable!(T) callable) {
495     //     if (callable is null)
496     //         throw new NullPointerException();
497     //     return new PrivilegedCallableUsingCurrentClassLoader!(T)(callable);
498     // }
499 
500 
501     // Methods for ExecutorService
502 
503     /**
504      * Submits a Runnable task for execution and returns a Future
505      * representing that task. The Future's {@code get} method will
506      * return {@code null} upon <em>successful</em> completion.
507      *
508      * @param task the task to submit
509      * @return a Future representing pending completion of the task
510      * @throws RejectedExecutionException if the task cannot be
511      *         scheduled for execution
512      * @throws NullPointerException if the task is null
513      */
514     static Future!(void) submit(ExecutorService es, Runnable task) {
515 
516         AbstractExecutorService aes = cast(AbstractExecutorService)es;
517         if(aes is null) 
518             throw new RejectedExecutionException("ExecutorService is null");
519         else
520             return aes.submit(task);
521 
522         // TypeInfo typeInfo = typeid(cast(Object)es);
523         // if(typeInfo == typeid(ThreadPoolExecutor)) {
524         //     AbstractExecutorService aes = cast(AbstractExecutorService)es;
525         //     return aes.submit(task);
526         // } else {
527         //     implementationMissing(false);
528         // }
529     }
530 
531     /**
532      * Submits a Runnable task for execution and returns a Future
533      * representing that task. The Future's {@code get} method will
534      * return the given result upon successful completion.
535      *
536      * @param task the task to submit
537      * @param result the result to return
538      * @param (T) the type of the result
539      * @return a Future representing pending completion of the task
540      * @throws RejectedExecutionException if the task cannot be
541      *         scheduled for execution
542      * @throws NullPointerException if the task is null
543      */
544     static Future!(T) submit(T)(ExecutorService es, Runnable task, T result) {
545         AbstractExecutorService aes = cast(AbstractExecutorService)es;
546         if(aes is null) 
547             throw new RejectedExecutionException("ExecutorService is null");
548         else
549             return aes.submit!T(task, result);
550                     
551         // TypeInfo typeInfo = typeid(cast(Object)es);
552         // if(typeInfo == typeid(ThreadPoolExecutor)) {
553         //     AbstractExecutorService aes = cast(AbstractExecutorService)es;
554         //     if(aes is null) 
555         //         throw new RejectedExecutionException("ExecutorService is null");
556         //     else
557         //         return aes.submit!T(task, result);
558         // } else {
559         //     implementationMissing(false);
560         // }
561     }
562 
563     /**
564      * Submits a value-returning task for execution and returns a
565      * Future representing the pending results of the task. The
566      * Future's {@code get} method will return the task's result upon
567      * successful completion.
568      *
569      * <p>
570      * If you would like to immediately block waiting
571      * for a task, you can use constructions of the form
572      * {@code result = exec.submit(aCallable).get();}
573      *
574      * <p>Note: The {@link Executors} class includes a set of methods
575      * that can convert some other common closure-like objects,
576      * for example, {@link java.security.PrivilegedAction} to
577      * {@link Callable} form so they can be submitted.
578      *
579      * @param task the task to submit
580      * @param (T) the type of the task's result
581      * @return a Future representing pending completion of the task
582      * @throws RejectedExecutionException if the task cannot be
583      *         scheduled for execution
584      * @throws NullPointerException if the task is null
585      */
586     static Future!(T) submit(T)(ExecutorService es, Callable!(T) task) {
587         AbstractExecutorService aes = cast(AbstractExecutorService)es;
588         if(aes is null) 
589             throw new RejectedExecutionException("ExecutorService is null");
590         else
591             return aes.submit!(T)(task);
592             
593         // TypeInfo typeInfo = typeid(cast(Object)es);
594         // if(typeInfo == typeid(ThreadPoolExecutor)) {
595         //     AbstractExecutorService aes = cast(AbstractExecutorService)es;
596         //     if(aes is null) 
597         //         throw new RejectedExecutionException("ExecutorService is null");
598         //     else
599         //         return aes.submit!(T)(task);
600         // } else {
601         //     implementationMissing(false);
602         // }
603     }
604 
605     /**
606      * Executes the given tasks, returning a list of Futures holding
607      * their status and results when all complete.
608      * {@link Future#isDone} is {@code true} for each
609      * element of the returned list.
610      * Note that a <em>completed</em> task could have
611      * terminated either normally or by throwing an exception.
612      * The results of this method are undefined if the given
613      * collection is modified while this operation is in progress.
614      *
615      * @param tasks the collection of tasks
616      * @param (T) the type of the values returned from the tasks
617      * @return a list of Futures representing the tasks, in the same
618      *         sequential order as produced by the iterator for the
619      *         given task list, each of which has completed
620      * @throws InterruptedException if interrupted while waiting, in
621      *         which case unfinished tasks are cancelled
622      * @throws NullPointerException if tasks or any of its elements are {@code null}
623      * @throws RejectedExecutionException if any task cannot be
624      *         scheduled for execution
625      */
626     static List!(Future!(T)) invokeAll(T)(ExecutorService es, Collection!(Callable!(T)) tasks) {
627 
628         AbstractExecutorService aes = cast(AbstractExecutorService)es;
629         if(aes is null) 
630             throw new RejectedExecutionException("ExecutorService is null");
631         else {
632             aes.invokeAll!(T)(tasks);
633         }
634 
635     }
636 
637     /**
638      * Executes the given tasks, returning a list of Futures holding
639      * their status and results
640      * when all complete or the timeout expires, whichever happens first.
641      * {@link Future#isDone} is {@code true} for each
642      * element of the returned list.
643      * Upon return, tasks that have not completed are cancelled.
644      * Note that a <em>completed</em> task could have
645      * terminated either normally or by throwing an exception.
646      * The results of this method are undefined if the given
647      * collection is modified while this operation is in progress.
648      *
649      * @param tasks the collection of tasks
650      * @param timeout the maximum time to wait
651      * @param unit the time unit of the timeout argument
652      * @param (T) the type of the values returned from the tasks
653      * @return a list of Futures representing the tasks, in the same
654      *         sequential order as produced by the iterator for the
655      *         given task list. If the operation did not time out,
656      *         each task will have completed. If it did time out, some
657      *         of these tasks will not have completed.
658      * @throws InterruptedException if interrupted while waiting, in
659      *         which case unfinished tasks are cancelled
660      * @throws NullPointerException if tasks, any of its elements, or
661      *         unit are {@code null}
662      * @throws RejectedExecutionException if any task cannot be scheduled
663      *         for execution
664      */
665     static List!(Future!(T)) invokeAll(T)(ExecutorService es, Collection!(Callable!(T)) tasks,
666                                   Duration timeout) {
667         AbstractExecutorService aes = cast(AbstractExecutorService)es;
668         if(aes is null) 
669             throw new RejectedExecutionException("ExecutorService is null");
670         else {
671             aes.invokeAll!(T)(tasks, timeout);
672         }
673     }
674 
675     /**
676      * Executes the given tasks, returning the result
677      * of one that has completed successfully (i.e., without throwing
678      * an exception), if any do. Upon normal or exceptional return,
679      * tasks that have not completed are cancelled.
680      * The results of this method are undefined if the given
681      * collection is modified while this operation is in progress.
682      *
683      * @param tasks the collection of tasks
684      * @param (T) the type of the values returned from the tasks
685      * @return the result returned by one of the tasks
686      * @throws InterruptedException if interrupted while waiting
687      * @throws NullPointerException if tasks or any element task
688      *         subject to execution is {@code null}
689      * @throws IllegalArgumentException if tasks is empty
690      * @throws ExecutionException if no task successfully completes
691      * @throws RejectedExecutionException if tasks cannot be scheduled
692      *         for execution
693      */
694     static T invokeAny(T)(ExecutorService es, Collection!(Callable!(T)) tasks) {
695         AbstractExecutorService aes = cast(AbstractExecutorService)es;
696         if(aes is null) 
697             throw new RejectedExecutionException("ExecutorService is null");
698         else {
699             aes.invokeAny!(T)(tasks);
700         }
701     }
702 
703     /**
704      * Executes the given tasks, returning the result
705      * of one that has completed successfully (i.e., without throwing
706      * an exception), if any do before the given timeout elapses.
707      * Upon normal or exceptional return, tasks that have not
708      * completed are cancelled.
709      * The results of this method are undefined if the given
710      * collection is modified while this operation is in progress.
711      *
712      * @param tasks the collection of tasks
713      * @param timeout the maximum time to wait
714      * @param unit the time unit of the timeout argument
715      * @param (T) the type of the values returned from the tasks
716      * @return the result returned by one of the tasks
717      * @throws InterruptedException if interrupted while waiting
718      * @throws NullPointerException if tasks, or unit, or any element
719      *         task subject to execution is {@code null}
720      * @throws TimeoutException if the given timeout elapses before
721      *         any task successfully completes
722      * @throws ExecutionException if no task successfully completes
723      * @throws RejectedExecutionException if tasks cannot be scheduled
724      *         for execution
725      */
726     static T invokeAny(T)(ExecutorService es, Collection!(Callable!(T)) tasks,
727                     Duration timeout)  {
728         AbstractExecutorService aes = cast(AbstractExecutorService)es;
729         if(aes is null) 
730             throw new RejectedExecutionException("ExecutorService is null");
731         else {
732             aes.invokeAny!(T)(tasks, timeout);
733         }
734     }
735 
736     /** Cannot instantiate. */
737     private this() {}
738 }
739 
740 // Non-classes supporting the methods
741 
742 /**
743  * A callable that runs given task and returns given result.
744  */
745 private final class RunnableAdapter(T) : Callable!(T) if(is(T == void)) {
746     private Runnable task;
747     this(Runnable task) {
748         this.task = task;
749     }
750 
751     T call() {
752         task.run();
753     }
754 
755     override string toString() {
756         return super.toString() ~ "[Wrapped task = " ~ (cast(Object)task).toString() ~ "]";
757     }
758 }
759 
760 private final class RunnableAdapter(T) : Callable!(T) if(!is(T == void)) {
761     private Runnable task;
762     private T result;
763 
764     this(Runnable task, T result) {
765         this.task = task;
766         this.result = result;
767     }
768 
769     T call() {
770         task.run();
771         return result;
772     }
773 
774     override string toString() {
775         return super.toString() ~ "[Wrapped task = " ~ (cast(Object)task).toString() ~ "]";
776     }
777 }
778 
779 // /**
780 //  * A callable that runs under established access control settings.
781 //  */
782 // private final class PrivilegedCallable!(T) : Callable!(T) {
783 //     Callable!(T) task;
784 //     AccessControlContext acc;
785 
786 //     PrivilegedCallable(Callable!(T) task) {
787 //         this.task = task;
788 //         this.acc = AccessController.getContext();
789 //     }
790 
791 //     T call() throws Exception {
792 //         try {
793 //             return AccessController.doPrivileged(
794 //                 new PrivilegedExceptionAction!(T)() {
795 //                     T run() throws Exception {
796 //                         return task.call();
797 //                     }
798 //                 }, acc);
799 //         } catch (PrivilegedActionException e) {
800 //             throw e.getException();
801 //         }
802 //     }
803 
804 //     string toString() {
805 //         return super.toString() ~ "[Wrapped task = " ~ task ~ "]";
806 //     }
807 // }
808 
809 // /**
810 //  * A callable that runs under established access control settings and
811 //  * current ClassLoader.
812 //  */
813 // private final class PrivilegedCallableUsingCurrentClassLoader(T)
814 //         : Callable!(T) {
815 //     Callable!(T) task;
816 //     AccessControlContext acc;
817 //     ClassLoader ccl;
818 
819 //     this(Callable!(T) task) {
820 //         SecurityManager sm = System.getSecurityManager();
821 //         if (sm !is null) {
822 //             // Calls to getContextClassLoader from this class
823 //             // never trigger a security check, but we check
824 //             // whether our callers have this permission anyways.
825 //             sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
826 
827 //             // Whether setContextClassLoader turns out to be necessary
828 //             // or not, we fail fast if permission is not available.
829 //             sm.checkPermission(new RuntimePermission("setContextClassLoader"));
830 //         }
831 //         this.task = task;
832 //         this.acc = AccessController.getContext();
833 //         this.ccl = Thread.getThis().getContextClassLoader();
834 //     }
835 
836 //     T call() throws Exception {
837 //         try {
838 //             return AccessController.doPrivileged(
839 //                 new PrivilegedExceptionAction!(T)() {
840 //                     T run() throws Exception {
841 //                         Thread t = Thread.getThis();
842 //                         ClassLoader cl = t.getContextClassLoader();
843 //                         if (ccl == cl) {
844 //                             return task.call();
845 //                         } else {
846 //                             t.setContextClassLoader(ccl);
847 //                             try {
848 //                                 return task.call();
849 //                             } finally {
850 //                                 t.setContextClassLoader(cl);
851 //                             }
852 //                         }
853 //                     }
854 //                 }, acc);
855 //         } catch (PrivilegedActionException e) {
856 //             throw e.getException();
857 //         }
858 //     }
859 
860 //     string toString() {
861 //         return super.toString() ~ "[Wrapped task = " ~ task ~ "]";
862 //     }
863 // }
864 
865 void reachabilityFence(ExecutorService) {
866     // do nothing;
867     // TODO: Tasks pending completion -@zxp at 5/10/2019, 10:50:31 AM    
868     // remove this
869 }
870 
871 /**
872  * A wrapper class that exposes only the ExecutorService methods
873  * of an ExecutorService implementation.
874  */
875 private class DelegatedExecutorService(U) : ExecutorService 
876     if(is(U : ExecutorService)) {
877         
878     private U e;
879 
880     this(U executor) { e = executor; }
881 
882     void execute(Runnable command) {
883         try {
884             e.execute(command);
885         } finally { reachabilityFence(this); }
886     }
887 
888     void shutdown() { e.shutdown(); }
889 
890     List!(Runnable) shutdownNow() {
891         try {
892             return e.shutdownNow();
893         } finally { reachabilityFence(this); }
894     }
895 
896     bool isShutdown() {
897         try {
898             return e.isShutdown();
899         } finally { reachabilityFence(this); }
900     }
901 
902     bool isTerminated() {
903         try {
904             return e.isTerminated();
905         } finally { reachabilityFence(this); }
906     }
907 
908     bool awaitTermination(Duration timeout) {
909         try {
910             return e.awaitTermination(timeout);
911         } finally { reachabilityFence(this); }
912     }
913 
914     Future!void submit(Runnable task) {
915         try {
916             return e.submit(task);
917         } finally { reachabilityFence(this); }
918     }
919 
920     Future!(T) submit(T)(Callable!(T) task) {
921         try {
922             return e.submit(task);
923         } finally { reachabilityFence(this); }
924     }
925 
926     Future!(T) submit(T)(Runnable task, T result) {
927         try {
928             return e.submit(task, result);
929         } finally { reachabilityFence(this); }
930     }
931 
932     List!(Future!(T)) invokeAll(T)(Collection!(Callable!(T)) tasks) {
933         try {
934             return e.invokeAll(tasks);
935         } finally { reachabilityFence(this); }
936     }
937 
938     List!(Future!(T)) invokeAll(T)(Collection!(Callable!(T)) tasks,
939                                          Duration timeout) {
940         try {
941             return e.invokeAll(tasks, timeout, unit);
942         } finally { reachabilityFence(this); }
943     }
944 
945     T invokeAny(T)(Collection!(Callable!(T)) tasks) {
946         try {
947             return e.invokeAny(tasks);
948         } finally { reachabilityFence(this); }
949     }
950     
951     T invokeAny(T)(Collection!(Callable!(T)) tasks,
952                            Duration timeout) {
953         try {
954             return e.invokeAny(tasks, timeout, unit);
955         } finally { reachabilityFence(this); }
956     }
957 }
958 
959 private class FinalizableDelegatedExecutorService(T) : DelegatedExecutorService!T {
960     this(T executor) {
961         super(executor);
962     }
963 
964     protected void finalize() {
965         super.shutdown();
966     }
967 }
968 
969 /**
970  * A wrapper class that exposes only the ScheduledExecutorService
971  * methods of a ScheduledExecutorService implementation.
972  */
973 private class DelegatedScheduledExecutorService(T) : DelegatedExecutorService!T,
974         ScheduledExecutorService if(is(T : ScheduledExecutorService)){
975 
976     private T e;
977 
978     this(T executor) {
979         super(executor);
980         e = executor;
981     }
982 
983     ScheduledFuture!void schedule(Runnable command, Duration delay) {
984         return e.schedule(command, delay);
985     }
986 
987     ScheduledFuture!(V) schedule(V)(Callable!(V) callable, Duration delay) {
988         return e.schedule!V(callable, delay);
989     }
990 
991     ScheduledFuture!void scheduleAtFixedRate(Runnable command, Duration initialDelay, Duration period) {
992         return e.scheduleAtFixedRate(command, initialDelay, period);
993     }
994 
995     ScheduledFuture!void scheduleWithFixedDelay(Runnable command, Duration initialDelay, Duration delay) {
996         return e.scheduleWithFixedDelay(command, initialDelay, delay);
997     }
998 }