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.thread.ThreadEx;
13 
14 import hunt.concurrency.thread.LockSupport;
15 
16 import hunt.Exceptions;
17 import hunt.Functions;
18 import hunt.logging.ConsoleLogger;
19 import hunt.system.Memory;
20 import hunt.util.Common;
21 import hunt.util.DateTime;
22 
23 import core.atomic;
24 import core.thread;
25 import core.time;
26 import core.sync.condition;
27 import core.sync.mutex;
28 
29 import std.algorithm: min, max;
30 import std.conv: to;
31 
32 
33 /**
34 */
35 interface Interruptible {
36     void interrupt(Thread t);
37 }
38 
39 
40 /**
41  * Interface for handlers invoked when a {@code Thread} abruptly
42  * terminates due to an uncaught exception.
43  * <p>When a thread is about to terminate due to an uncaught exception
44  * the Java Virtual Machine will query the thread for its
45  * {@code UncaughtExceptionHandler} using
46  * {@link #getUncaughtExceptionHandler} and will invoke the handler's
47  * {@code uncaughtException} method, passing the thread and the
48  * exception as arguments.
49  * If a thread has not had its {@code UncaughtExceptionHandler}
50  * explicitly set, then its {@code ThreadGroupEx} object acts as its
51  * {@code UncaughtExceptionHandler}. If the {@code ThreadGroupEx} object
52  * has no
53  * special requirements for dealing with the exception, it can forward
54  * the invocation to the {@linkplain #getDefaultUncaughtExceptionHandler
55  * default uncaught exception handler}.
56  *
57  * @see #setDefaultUncaughtExceptionHandler
58  * @see #setUncaughtExceptionHandler
59  * @see ThreadGroupEx#uncaughtException
60  */
61 interface UncaughtExceptionHandler {
62     /**
63      * Method invoked when the given thread terminates due to the
64      * given uncaught exception.
65      * <p>Any exception thrown by this method will be ignored by the
66      * Java Virtual Machine.
67      * @param t the thread
68      * @param e the exception
69      */
70     void uncaughtException(Thread t, Throwable e);
71 }
72 
73 
74 /**
75  * A thread state.  A thread can be in one of the following states:
76  * <ul>
77  * <li>{@link #NEW}<br>
78  *     A thread that has not yet started is in this state.
79  *     </li>
80  * <li>{@link #RUNNABLE}<br>
81  *     A thread executing in the Java virtual machine is in this state.
82  *     </li>
83  * <li>{@link #BLOCKED}<br>
84  *     A thread that is blocked waiting for a monitor lock
85  *     is in this state.
86  *     </li>
87  * <li>{@link #WAITING}<br>
88  *     A thread that is waiting indefinitely for another thread to
89  *     perform a particular action is in this state.
90  *     </li>
91  * <li>{@link #TIMED_WAITING}<br>
92  *     A thread that is waiting for another thread to perform an action
93  *     for up to a specified waiting time is in this state.
94  *     </li>
95  * <li>{@link #TERMINATED}<br>
96  *     A thread that has exited is in this state.
97  *     </li>
98  * </ul>
99  *
100  * <p>
101  * A thread can be in only one state at a given point in time.
102  * These states are virtual machine states which do not reflect
103  * any operating system thread states.
104  *
105  * @see #getState
106  */
107 enum ThreadState {
108     /**
109      * Thread state for a thread which has not yet started.
110      */
111     NEW,
112 
113     /**
114      * Thread state for a runnable thread.  A thread in the runnable
115      * state is executing in the Java virtual machine but it may
116      * be waiting for other resources from the operating system
117      * such as processor.
118      */
119     RUNNABLE,
120 
121     /**
122      * Thread state for a thread blocked waiting for a monitor lock.
123      * A thread in the blocked state is waiting for a monitor lock
124      * to enter a synchronized block/method or
125      * reenter a synchronized block/method after calling
126      * {@link Object#wait() Object.wait}.
127      */
128     BLOCKED,
129 
130     /**
131      * Thread state for a waiting thread.
132      * A thread is in the waiting state due to calling one of the
133      * following methods:
134      * <ul>
135      *   <li>{@link Object#wait() Object.wait} with no timeout</li>
136      *   <li>{@link #join() Thread.join} with no timeout</li>
137      *   <li>{@link LockSupport#park() LockSupport.park}</li>
138      * </ul>
139      *
140      * <p>A thread in the waiting state is waiting for another thread to
141      * perform a particular action.
142      *
143      * For example, a thread that has called {@code Object.wait()}
144      * on an object is waiting for another thread to call
145      * {@code Object.notify()} or {@code Object.notifyAll()} on
146      * that object. A thread that has called {@code Thread.join()}
147      * is waiting for a specified thread to terminate.
148      */
149     WAITING,
150 
151     /**
152      * Thread state for a waiting thread with a specified waiting time.
153      * A thread is in the timed waiting state due to calling one of
154      * the following methods with a specified positive waiting time:
155      * <ul>
156      *   <li>{@link #sleep Thread.sleep}</li>
157      *   <li>{@link Object#wait(long) Object.wait} with timeout</li>
158      *   <li>{@link #join(long) Thread.join} with timeout</li>
159      *   <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
160      *   <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
161      * </ul>
162      */
163     TIMED_WAITING,
164 
165     /**
166      * Thread state for a terminated thread.
167      * The thread has completed execution.
168      */
169     TERMINATED
170 }
171 
172 
173 /**
174  * A <i>thread</i> is a thread of execution in a program. The Java
175  * Virtual Machine allows an application to have multiple threads of
176  * execution running concurrently.
177  * <p>
178  * Every thread has a priority. Threads with higher priority are
179  * executed in preference to threads with lower priority. Each thread
180  * may or may not also be marked as a daemon. When code running in
181  * some thread creates a new {@code Thread} object, the new
182  * thread has its priority initially set equal to the priority of the
183  * creating thread, and is a daemon thread if and only if the
184  * creating thread is a daemon.
185  * <p>
186  * When a Java Virtual Machine starts up, there is usually a single
187  * non-daemon thread (which typically calls the method named
188  * {@code main} of some designated class). The Java Virtual
189  * Machine continues to execute threads until either of the following
190  * occurs:
191  * <ul>
192  * <li>The {@code exit} method of class {@code Runtime} has been
193  *     called and the security manager has permitted the exit operation
194  *     to take place.
195  * <li>All threads that are not daemon threads have died, either by
196  *     returning from the call to the {@code run} method or by
197  *     throwing an exception that propagates beyond the {@code run}
198  *     method.
199  * </ul>
200  * <p>
201  * There are two ways to create a new thread of execution. One is to
202  * declare a class to be a subclass of {@code Thread}. This
203  * subclass should override the {@code run} method of class
204  * {@code Thread}. An instance of the subclass can then be
205  * allocated and started. For example, a thread that computes primes
206  * larger than a stated value could be written as follows:
207  * <hr><blockquote><pre>
208  *     class PrimeThread extends Thread {
209  *         long minPrime;
210  *         PrimeThread(long minPrime) {
211  *             this.minPrime = minPrime;
212  *         }
213  *
214  *         public void run() {
215  *             // compute primes larger than minPrime
216  *             &nbsp;.&nbsp;.&nbsp;.
217  *         }
218  *     }
219  * </pre></blockquote><hr>
220  * <p>
221  * The following code would then create a thread and start it running:
222  * <blockquote><pre>
223  *     PrimeThread p = new PrimeThread(143);
224  *     p.start();
225  * </pre></blockquote>
226  * <p>
227  * The other way to create a thread is to declare a class that
228  * implements the {@code Runnable} interface. That class then
229  * implements the {@code run} method. An instance of the class can
230  * then be allocated, passed as an argument when creating
231  * {@code Thread}, and started. The same example in this other
232  * style looks like the following:
233  * <hr><blockquote><pre>
234  *     class PrimeRun implements Runnable {
235  *         long minPrime;
236  *         PrimeRun(long minPrime) {
237  *             this.minPrime = minPrime;
238  *         }
239  *
240  *         public void run() {
241  *             // compute primes larger than minPrime
242  *             &nbsp;.&nbsp;.&nbsp;.
243  *         }
244  *     }
245  * </pre></blockquote><hr>
246  * <p>
247  * The following code would then create a thread and start it running:
248  * <blockquote><pre>
249  *     PrimeRun p = new PrimeRun(143);
250  *     new Thread(p).start();
251  * </pre></blockquote>
252  * <p>
253  * Every thread has a name for identification purposes. More than
254  * one thread may have the same name. If a name is not specified when
255  * a thread is created, a new name is generated for it.
256  * <p>
257  * Unless otherwise noted, passing a {@code null} argument to a constructor
258  * or method in this class will cause a {@link NullPointerException} to be
259  * thrown.
260  *
261  */
262 class ThreadEx : Thread, Runnable {
263 
264     /* What will be run. */
265     private Runnable target;
266 
267     // Object parkBlocker;
268     ThreadState state;
269     
270 
271     /* The object in which this thread is blocked in an interruptible I/O
272      * operation, if any.  The blocker's interrupt method should be invoked
273      * after setting this thread's interrupt status.
274      */
275     private Interruptible blocker;
276     private Object blockerLock;
277     private shared bool _interrupted;     // Thread.isInterrupted state
278     
279     /* For autonumbering anonymous threads. */
280     private static shared int threadInitNumber;
281     private static int nextThreadNum() {
282         return core.atomic.atomicOp!"+="(threadInitNumber, 1);
283     }
284 
285     this() {
286         this(null, null, "Thread-" ~ nextThreadNum().to!string());
287     }
288 
289     this(string name) {
290         this(null, null, name);
291     }
292 
293     this(Runnable target) {
294         this(null, target, "Thread-" ~ nextThreadNum().to!string());
295     }
296 
297     this(Runnable target, string name) {
298         this(null, target, name);
299     }
300 
301     this(ThreadGroupEx group,  string name) {
302         this(group, null, name);
303     }
304 
305     this(ThreadGroupEx group, Runnable target, string name,  size_t sz = 0) {
306         this.name = name;
307         this.group = group;
308         this.target = target;
309         super(&run, sz);
310         initialize();
311     }
312 
313     this(Action dg, string name) {
314         this(new class Runnable {
315             void run() { dg();}
316         }, name);
317     }
318 
319     this(Action dg) {
320         this(new class Runnable {
321             void run() { dg();}
322         });
323     }
324 
325     this(void function() fn) {
326         this(new class Runnable {
327             void run() { fn();}
328         });
329     }
330 
331     ~this() {
332         blocker = null;
333         blockerLock = null;
334         // parkBlocker = null;
335         target = null;
336         _parker = null;
337     }
338 
339     private void initialize() nothrow {
340         _parker = Parker.allocate(this);
341         blockerLock = new Object();
342         state = ThreadState.NEW;
343     }
344 
345     
346     /**
347      * Returns the thread group to which this thread belongs.
348      * This method returns null if this thread has died
349      * (been stopped).
350      *
351      * @return  this thread's thread group.
352      */
353     final ThreadGroupEx getThreadGroup() {
354         return group;
355     }
356 
357     /* The group of this thread */
358     private ThreadGroupEx group;
359 
360     /**
361      * If this thread was constructed using a separate
362      * {@code Runnable} run object, then that
363      * {@code Runnable} object's {@code run} method is called;
364      * otherwise, this method does nothing and returns.
365      * <p>
366      * Subclasses of {@code Thread} should override this method.
367      *
368      * @see     #start()
369      * @see     #stop()
370      * @see     #Thread(ThreadGroup, Runnable, String)
371      * See_also:
372      *  https://stackoverflow.com/questions/8579657/whats-the-difference-between-thread-start-and-runnable-run
373      */
374     void run() {
375         version(HUNT_CONCURRENCY_DEBUG_MORE) {
376             infof("trying to run a target %s...", target is null ? "(null)" : "");
377         }
378         if (target !is null) {
379             target.run();
380         }
381     }
382 
383 
384 
385      /**
386      * Tests if this thread is alive. A thread is alive if it has
387      * been started and has not yet died.
388      *
389      * @return  <code>true</code> if this thread is alive;
390      *          <code>false</code> otherwise.
391      */
392     final bool isAlive() {
393         // TODO: Tasks pending completion -@zxp at 11/7/2018, 10:30:43 AM
394         // 
395         return isRunning();
396     }
397 
398 
399     /**
400      * Marks this thread as either a {@linkplain #isDaemon daemon} thread
401      * or a user thread. The Java Virtual Machine exits when the only
402      * threads running are all daemon threads.
403      *
404      * <p> This method must be invoked before the thread is started.
405      *
406      * @param  on
407      *         if {@code true}, marks this thread as a daemon thread
408      *
409      * @throws  IllegalThreadStateException
410      *          if this thread is {@linkplain #isAlive alive}
411      *
412      * @throws  SecurityException
413      *          if {@link #checkAccess} determines that the current
414      *          thread cannot modify this thread
415      */
416     final void setDaemon(bool on) {
417         if (isAlive()) {
418             throw new IllegalThreadStateException();
419         }
420         isDaemon(on);
421     }
422 
423     /**
424      * Returns the state of this thread.
425      * This method is designed for use in monitoring of the system state,
426      * not for synchronization control.
427      *
428      * @return this thread's state.
429      */
430     ThreadState getState() {
431         // get current thread state
432         // return jdk.internal.misc.VM.toThreadState(threadStatus);
433         return state;
434     }
435 
436     /* Set the blocker field; invoked via sun.misc.SharedSecrets from java.nio code
437      */
438     void blockedOn(Interruptible b) {
439         synchronized (blockerLock) {
440             blocker = b;
441         }
442     }
443 
444     /**
445      * Interrupts this thread.
446      *
447      * <p> Unless the current thread is interrupting itself, which is
448      * always permitted, the {@link #checkAccess() checkAccess} method
449      * of this thread is invoked, which may cause a {@link
450      * SecurityException} to be thrown.
451      *
452      * <p> If this thread is blocked in an invocation of the {@link
453      * Object#wait() wait()}, {@link Object#wait(long) wait(long)}, or {@link
454      * Object#wait(long, int) wait(long, int)} methods of the {@link Object}
455      * class, or of the {@link #join()}, {@link #join(long)}, {@link
456      * #join(long, int)}, {@link #sleep(long)}, or {@link #sleep(long, int)},
457      * methods of this class, then its interrupt status will be cleared and it
458      * will receive an {@link InterruptedException}.
459      *
460      * <p> If this thread is blocked in an I/O operation upon an {@link
461      * java.nio.channels.InterruptibleChannel InterruptibleChannel}
462      * then the channel will be closed, the thread's interrupt
463      * status will be set, and the thread will receive a {@link
464      * java.nio.channels.ClosedByInterruptException}.
465      *
466      * <p> If this thread is blocked in a {@link java.nio.channels.Selector}
467      * then the thread's interrupt status will be set and it will return
468      * immediately from the selection operation, possibly with a non-zero
469      * value, just as if the selector's {@link
470      * java.nio.channels.Selector#wakeup wakeup} method were invoked.
471      *
472      * <p> If none of the previous conditions hold then this thread's interrupt
473      * status will be set. </p>
474      *
475      * <p> Interrupting a thread that is not alive need not have any effect.
476      *
477      * @throws  SecurityException
478      *          if the current thread cannot modify this thread
479      *
480      * @revised 6.0
481      * @spec JSR-51
482      */
483     void interrupt() {
484         synchronized (blockerLock) {
485             Interruptible b = blocker;
486             if (b !is null) {
487                 interrupt0();           // Just to set the interrupt flag
488                 b.interrupt(this);
489                 return;
490             }
491         }
492         interrupt0();
493     }
494 
495     private void interrupt0() {
496         if(!_interrupted) {
497             _interrupted = true;
498             // More than one thread can get here with the same value of osthread,
499             // resulting in multiple notifications.  We do, however, want the store
500             // to interrupted() to be visible to other threads before we execute unpark().
501             // OrderAccess::fence();
502             // ParkEvent * const slp = thread->_SleepEvent ;
503             // if (slp != NULL) slp->unpark() ;
504         }
505 
506         // For JSR166. Unpark even if interrupt status already was set
507         _parker.unpark();
508         // LockSupport.unpark();
509 
510         // ParkEvent * ev = thread->_ParkEvent ;
511         // if (ev != NULL) ev->unpark() ;
512     }
513 
514     /**
515      * Tests whether this thread has been interrupted.  The <i>interrupted
516      * status</i> of the thread is unaffected by this method.
517      *
518      * <p>A thread interruption ignored because a thread was not alive
519      * at the time of the interrupt will be reflected by this method
520      * returning false.
521      *
522      * @return  <code>true</code> if this thread has been interrupted;
523      *          <code>false</code> otherwise.
524      * @see     #interrupted()
525      * @revised 6.0
526      */
527     bool isInterrupted() {
528         return isInterrupted(false);
529     }
530 
531 
532     /**
533      * Tests whether the current thread has been interrupted.  The
534      * <i>interrupted status</i> of the thread is cleared by this method.  In
535      * other words, if this method were to be called twice in succession, the
536      * second call would return false (unless the current thread were
537      * interrupted again, after the first call had cleared its interrupted
538      * status and before the second call had examined it).
539      *
540      * <p>A thread interruption ignored because a thread was not alive
541      * at the time of the interrupt will be reflected by this method
542      * returning false.
543      *
544      * @return  <code>true</code> if the current thread has been interrupted;
545      *          <code>false</code> otherwise.
546      * @see #isInterrupted()
547      * @revised 6.0
548      */
549     static bool interrupted() {
550         ThreadEx tex = cast(ThreadEx) Thread.getThis();
551         if(tex is null)
552             return false;
553 
554         return tex.isInterrupted(true);
555     }
556 
557     /**
558      * Tests if some Thread has been interrupted.  The interrupted state
559      * is reset or not based on the value of ClearInterrupted that is
560      * passed.
561      */
562     private bool isInterrupted(bool canClear) {
563         // bool interrupted = osthread->interrupted();
564 
565         // NOTE that since there is no "lock" around the interrupt and
566         // is_interrupted operations, there is the possibility that the
567         // interrupted flag (in osThread) will be "false" but that the
568         // low-level events will be in the signaled state. This is
569         // intentional. The effect of this is that Object.wait() and
570         // LockSupport.park() will appear to have a spurious wakeup, which
571         // is allowed and not harmful, and the possibility is so rare that
572         // it is not worth the added complexity to add yet another lock.
573         // For the sleep event an explicit reset is performed on entry
574         // to os::sleep, so there is no early return. It has also been
575         // recommended not to put the interrupted flag into the "event"
576         // structure because it hides the issue.
577         if (_interrupted && canClear) {
578             _interrupted = false;
579             // consider thread->_SleepEvent->reset() ... optional optimization
580         }
581 
582         return _interrupted;
583     }
584 
585     static ThreadEx currentThread() {
586         ThreadEx tex = cast(ThreadEx) Thread.getThis();
587         assert(tex !is null, "Must be a ThreadEx");
588         return tex;
589     }
590 
591 
592     Parker parker() {
593         return _parker;
594     }
595     private Parker _parker;
596 
597     // Short sleep, direct OS call.
598     static void nakedSleep(Duration timeout) {
599         Thread.sleep(timeout);
600     }
601 
602     // Sleep forever; naked call to OS-specific sleep; use with CAUTION
603     static void infiniteSleep() {
604         while (true) {    // sleep forever ...
605             Thread.sleep(100.seconds);   // ... 100 seconds at a time
606         }
607     }
608 
609     static void sleep(Duration timeout) {
610         // TODO: Tasks pending completion -@zxp at 11/6/2018, 12:29:22 PM
611         // using ParkEvent
612         LockSupport.park(timeout);
613     }
614 
615     // Low-level leaf-lock primitives used to implement synchronization
616     // and native monitor-mutex infrastructure.
617     // Not for general synchronization use.
618     private static void spinAcquire(shared(int)* adr, string name) nothrow  {
619         int last = *adr;
620         cas(adr, 0, 1);
621         if (last == 0) return; // normal fast-path return
622 
623         // Slow-path : We've encountered contention -- Spin/Yield/Block strategy.
624         //   TEVENT(SpinAcquire - ctx);
625         int ctr = 0;
626         int yields = 0;
627         for (;;) {
628             while (*adr != 0) {
629                 ++ctr;
630                 if ((ctr & 0xFFF) == 0 && !is_MP()) {
631                     if (yields > 5) {
632                         Thread.sleep(1.msecs);
633                     } else {
634                         Thread.yield();
635                         ++yields;
636                     }
637                 } else {
638                     spinPause();
639                 }
640             }
641             last = *adr;
642             cas(adr, 1, 0);
643             if (last == 0) return;
644         }
645     }
646 
647     private static void spinRelease(shared(int)* adr) @safe nothrow @nogc {
648         assert(*adr != 0, "invariant");
649         atomicFence(); // guarantee at least release consistency.
650         // Roach-motel semantics.
651         // It's safe if subsequent LDs and STs float "up" into the critical section,
652         // but prior LDs and STs within the critical section can't be allowed
653         // to reorder or float past the ST that releases the lock.
654         // Loads and stores in the critical section - which appear in program
655         // order before the store that releases the lock - must also appear
656         // before the store that releases the lock in memory visibility order.
657         // Conceptually we need a #loadstore|#storestore "release" MEMBAR before
658         // the ST of 0 into the lock-word which releases the lock, so fence
659         // more than covers this on all platforms.
660         *adr = 0;
661     }
662 
663     //   static void muxAcquire(shared intptr_t * Lock, string Name);
664     // //   static void muxAcquireW(shared intptr_t * Lock, ParkEvent * ev);
665     //   static void muxRelease(shared intptr_t * Lock);
666 
667     private static int spinPause() @safe nothrow @nogc {
668         version (X86_64) {
669             return 0;
670         }
671         else version (AsmX86_Windows) {
672             asm pure nothrow @nogc {
673                 pause;
674             }
675             return 1;
676         }
677         else {
678             return -1;
679         }
680     }
681 
682     private static bool is_MP() @safe pure nothrow @nogc {
683         // During bootstrap if _processor_count is not yet initialized
684         // we claim to be MP as that is safest. If any platform has a
685         // stub generator that might be triggered in this phase and for
686         // which being declared MP when in fact not, is a problem - then
687         // the bootstrap routine for the stub generator needs to check
688         // the processor count directly and leave the bootstrap routine
689         // in place until called after initialization has ocurred.
690         // return (_processor_count != 1); // AssumeMP || 
691         return totalCPUs != 1;
692     }
693 
694     
695     
696     // null unless explicitly set
697     private UncaughtExceptionHandler uncaughtExceptionHandler;
698 
699     // null unless explicitly set
700     private __gshared UncaughtExceptionHandler defaultUncaughtExceptionHandler;
701 
702     /**
703      * Set the default handler invoked when a thread abruptly terminates
704      * due to an uncaught exception, and no other handler has been defined
705      * for that thread.
706      *
707      * <p>Uncaught exception handling is controlled first by the thread, then
708      * by the thread's {@link ThreadGroup} object and finally by the default
709      * uncaught exception handler. If the thread does not have an explicit
710      * uncaught exception handler set, and the thread's thread group
711      * (including parent thread groups)  does not specialize its
712      * {@code uncaughtException} method, then the default handler's
713      * {@code uncaughtException} method will be invoked.
714      * <p>By setting the default uncaught exception handler, an application
715      * can change the way in which uncaught exceptions are handled (such as
716      * logging to a specific device, or file) for those threads that would
717      * already accept whatever &quot;default&quot; behavior the system
718      * provided.
719      *
720      * <p>Note that the default uncaught exception handler should not usually
721      * defer to the thread's {@code ThreadGroup} object, as that could cause
722      * infinite recursion.
723      *
724      * @param eh the object to use as the default uncaught exception handler.
725      * If {@code null} then there is no default handler.
726      *
727      * @throws SecurityException if a security manager is present and it denies
728      *         {@link RuntimePermission}{@code ("setDefaultUncaughtExceptionHandler")}
729      *
730      * @see #setUncaughtExceptionHandler
731      * @see #getUncaughtExceptionHandler
732      * @see ThreadGroup#uncaughtException
733      */
734     static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
735         // SecurityManager sm = System.getSecurityManager();
736         // if (sm != null) {
737         //     sm.checkPermission(
738         //         new RuntimePermission("setDefaultUncaughtExceptionHandler")
739         //             );
740         // }
741 
742          defaultUncaughtExceptionHandler = eh;
743      }
744 
745     /**
746      * Returns the default handler invoked when a thread abruptly terminates
747      * due to an uncaught exception. If the returned value is {@code null},
748      * there is no default.
749      * @see #setDefaultUncaughtExceptionHandler
750      * @return the default uncaught exception handler for all threads
751      */
752     static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){
753         return defaultUncaughtExceptionHandler;
754     }
755 
756     /**
757      * Returns the handler invoked when this thread abruptly terminates
758      * due to an uncaught exception. If this thread has not had an
759      * uncaught exception handler explicitly set then this thread's
760      * {@code ThreadGroup} object is returned, unless this thread
761      * has terminated, in which case {@code null} is returned.
762      * @return the uncaught exception handler for this thread
763      */
764     UncaughtExceptionHandler getUncaughtExceptionHandler() {
765         return uncaughtExceptionHandler !is null ?
766             uncaughtExceptionHandler : group;
767     }
768 
769     /**
770      * Set the handler invoked when this thread abruptly terminates
771      * due to an uncaught exception.
772      * <p>A thread can take full control of how it responds to uncaught
773      * exceptions by having its uncaught exception handler explicitly set.
774      * If no such handler is set then the thread's {@code ThreadGroup}
775      * object acts as its handler.
776      * @param eh the object to use as this thread's uncaught exception
777      * handler. If {@code null} then this thread has no explicit handler.
778      * @throws  SecurityException  if the current thread is not allowed to
779      *          modify this thread.
780      * @see #setDefaultUncaughtExceptionHandler
781      * @see ThreadGroup#uncaughtException
782      */
783     void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {
784         checkAccess();
785         uncaughtExceptionHandler = eh;
786     }
787 
788     void checkAccess() {
789 
790     }
791 }
792 
793 
794 /*
795  * Per-thread blocking support for JSR166. See the Java-level
796  * Documentation for rationale. Basically, park acts like wait, unpark
797  * like notify.
798  *
799  * 6271289 --
800  * To avoid errors where an os thread expires but the JavaThread still
801  * exists, Parkers are immortal (type-stable) and are recycled across
802  * new threads.  This parallels the ParkEvent implementation.
803  * Because park-unpark allow spurious wakeups it is harmless if an
804  * unpark call unparks a new thread using the old Parker reference.
805  *
806  * In the future we'll want to think about eliminating Parker and using
807  * ParkEvent instead.  There's considerable duplication between the two
808  * services.
809  *
810  */
811 class Parker {
812 
813     enum int REL_INDEX = 0;
814     enum int ABS_INDEX = 1;
815 
816     private Object parkBlocker;
817 
818     private shared int _counter;
819     private int _nParked;
820     private Parker freeNext;
821     private Thread associatedWith; // Current association
822 
823     private  int _cur_index;  // which cond is in use: -1, 0, 1
824     private Mutex _mutex;
825     private Condition[2]  _cond; // one for relative times and one for absolute
826 
827     this() @safe nothrow {
828         _counter = 0;
829         _mutex = new Mutex();
830         _cond[REL_INDEX] = new Condition(_mutex);
831         _cond[ABS_INDEX] = new Condition(_mutex);
832         _cur_index = -1; // mark as unused
833     }
834 
835     // For simplicity of interface, all forms of park (indefinite,
836     // relative, and absolute) are multiplexed into one call.
837     // park decrements count if > 0, else does a condvar wait.  Unpark
838     // sets count to 1 and signals condvar.  Only one thread ever waits
839     // on the condvar. Contention seen when trying to park implies that someone
840     // is unparking you, so don't wait. And spurious returns are fine, so there
841     // is no need to track notifications.
842     void park(Duration time) {
843         debug(HUNT_CONCURRENCY_DEBUG) {
844             tracef("try to park a thread %s",
845                 time <= Duration.zero ? "forever" : "in " ~ time.toString());
846         }
847         // Optional fast-path check:
848         // Return immediately if a permit is available.
849         // We depend on Atomic::xchg() having full barrier semantics
850         // since we are doing a lock-free update to _counter.
851         const int c = _counter;
852         if(c > 0) {
853             atomicStore(_counter, 0);
854             debug(HUNT_CONCURRENCY_DEBUG) infof("no need to park, counter=%s", c);
855             return;
856         }
857 
858         // Next, demultiplex/decode time arguments
859         if (time < Duration.zero) { // don't wait at all
860             return;
861         }
862 
863         ThreadEx thread = cast(ThreadEx) Thread.getThis();
864 
865         // Enter safepoint region
866         // Beware of deadlocks such as 6317397.
867         // The per-thread Parker. mutex is a classic leaf-lock.
868         // In particular a thread must never block on the Threads_lock while
869         // holding the Parker.mutex. 
870 
871         // Don't wait if cannot get lock since interference arises from
872         // unparking. Also re-check interrupt before trying wait.
873         if((thread !is null && thread.isInterrupted()) || !_mutex.tryLock())
874             return;
875 
876         if (_counter > 0) { // no wait needed
877             return;
878         }
879 
880         scope(exit) {
881             _counter = 0;
882             _mutex.unlock();
883             // Paranoia to ensure our locked and lock-free paths interact
884             // correctly with each other and Java-level accesses.
885             atomicFence();
886         }
887 
888         // OSThreadWaitState osts(thread.osthread(), false  /* not Object.wait() */ );
889         // jt.set_suspend_equivalent();
890         // // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
891 
892         assert(_cur_index == -1, "invariant");
893         if (time == Duration.zero) {
894             _cur_index = REL_INDEX; // arbitrary choice when not timed
895             _cond[_cur_index].wait();
896         }
897         else {
898             _cur_index = REL_INDEX;
899             _cond[REL_INDEX].wait(time);
900         }
901         _cur_index = -1;
902     }
903 
904     void park(MonoTime time) {
905         debug(HUNT_CONCURRENCY_DEBUG) {
906             Duration d = time - MonoTime.currTime;
907             tracef("try to park a thread %s",  
908                 d <= Duration.zero ? "forever" : "in " ~ d.toString());
909         }
910         // Optional fast-path check:
911         // Return immediately if a permit is available.
912         // We depend on Atomic::xchg() having full barrier semantics
913         // since we are doing a lock-free update to _counter.
914         const int c = _counter;
915         if(c > 0) {
916             atomicStore(_counter, 0);
917             debug(HUNT_CONCURRENCY_DEBUG) infof("no need to park, counter=%s", c);
918             return;
919         }
920 
921         // Next, demultiplex/decode time arguments
922         if (time <= MonoTime.zero) { // don't wait at all
923             return;
924         }
925 
926         ThreadEx thread = cast(ThreadEx) Thread.getThis();
927 
928         // Enter safepoint region
929         // Beware of deadlocks such as 6317397.
930         // The per-thread Parker. mutex is a classic leaf-lock.
931         // In particular a thread must never block on the Threads_lock while
932         // holding the Parker.mutex. 
933 
934         // Don't wait if cannot get lock since interference arises from
935         // unparking. Also re-check interrupt before trying wait.
936         if((thread !is null && thread.isInterrupted()) || !_mutex.tryLock())
937             return;
938 
939         if (_counter > 0) { // no wait needed
940             return;
941         }
942 
943         scope(exit) {
944             _counter = 0;
945             _mutex.unlock();
946             // Paranoia to ensure our locked and lock-free paths interact
947             // correctly with each other and Java-level accesses.
948             atomicFence();
949         }
950 
951         // OSThreadWaitState osts(thread.osthread(), false  /* not Object.wait() */ );
952         // jt.set_suspend_equivalent();
953         // // cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
954 
955         assert(_cur_index == -1, "invariant");
956         if (time == MonoTime.zero) {
957             _cur_index = REL_INDEX; // arbitrary choice when not timed
958             _cond[_cur_index].wait();
959         }
960         else {
961             _cur_index = ABS_INDEX;
962             Duration t = time - MonoTime.currTime;
963             if(t > Duration.zero)
964                 _cond[ABS_INDEX].wait(t);
965         }
966         _cur_index = -1;
967     }
968 
969     void unpark() {
970         debug(HUNT_CONCURRENCY_DEBUG) {
971             tracef("try to unpark a thread");
972         }
973         _mutex.lock();
974         const int s = _counter;
975         _counter = 1;
976         // must capture correct index before unlocking
977         int index = _cur_index;
978         _mutex.unlock();
979 
980         // Note that we signal() *after* dropping the lock for "immortal" Events.
981         // This is safe and avoids a common class of futile wakeups.  In rare
982         // circumstances this can cause a thread to return prematurely from
983         // cond_{timed}wait() but the spurious wakeup is benign and the victim
984         // will simply re-test the condition and re-park itself.
985         // This provides particular benefit if the underlying platform does not
986         // provide wait morphing.
987 
988         if (s < 1 && index != -1) {
989             // thread is definitely parked
990             _cond[index].notify();
991         }
992     }
993 
994     Object getBlocker() {
995         return parkBlocker;
996     }
997 
998     void setBlocker(Object arg) {
999         parkBlocker = arg;
1000     }
1001 
1002     // Lifecycle operators
1003     static Parker allocate(Thread t) nothrow {
1004         assert(t !is null, "invariant");
1005         Parker p;
1006 
1007         // Start by trying to recycle an existing but unassociated
1008         // Parker from the global free list.
1009         // 8028280: using concurrent free list without memory management can leak
1010         // pretty badly it turns out.
1011         ThreadEx.spinAcquire(&listLock, "ParkerFreeListAllocate");
1012         {
1013             p = freeList;
1014             if (p !is null) {
1015                 freeList = p.freeNext;
1016             }
1017         }
1018         ThreadEx.spinRelease(&listLock);
1019 
1020         if (p !is null) {
1021             assert(p.associatedWith is null, "invariant");
1022         }
1023         else {
1024             // Do this the hard way -- materialize a new Parker..
1025             p = new Parker();
1026         }
1027         p.associatedWith = t; // Associate p with t
1028         p.freeNext = null;
1029         return p;
1030     }
1031 
1032     static void release(Parker p) {
1033         if (p is null)
1034             return;
1035         assert(p.associatedWith !is null, "invariant");
1036         assert(p.freeNext is null, "invariant");
1037         p.associatedWith = null;
1038 
1039         ThreadEx.spinAcquire(&listLock, "ParkerFreeListRelease");
1040         {
1041             p.freeNext = freeList;
1042             freeList = p;
1043         }
1044         ThreadEx.spinRelease(&listLock);
1045     }
1046 
1047     private static Parker freeList;
1048     private static shared int listLock;
1049 }
1050 
1051 
1052 /**
1053  * A thread group represents a set of threads. In addition, a thread
1054  * group can also include other thread groups. The thread groups form
1055  * a tree in which every thread group except the initial thread group
1056  * has a parent.
1057  * <p>
1058  * A thread is allowed to access information about its own thread
1059  * group, but not to access information about its thread group's
1060  * parent thread group or any other thread groups.
1061  *
1062  * @author  unascribed
1063  */
1064 /* The locking strategy for this code is to try to lock only one level of the
1065  * tree wherever possible, but otherwise to lock from the bottom up.
1066  * That is, from child thread groups to parents.
1067  * This has the advantage of limiting the number of locks that need to be held
1068  * and in particular avoids having to grab the lock for the root thread group,
1069  * (or a global lock) which would be a source of contention on a
1070  * multi-processor system with many thread groups.
1071  * This policy often leads to taking a snapshot of the state of a thread group
1072  * and working off of that snapshot, rather than holding the thread group locked
1073  * while we work on the children.
1074  */
1075 class ThreadGroupEx : UncaughtExceptionHandler { 
1076     private ThreadGroupEx parent;
1077     string name;
1078     int maxPriority;
1079     bool destroyed;
1080     bool daemon;
1081 
1082     int nUnstartedThreads = 0;
1083     int nthreads;
1084     Thread[] threads;
1085 
1086     int ngroups;
1087     ThreadGroupEx[] groups;
1088 
1089     /**
1090      * Creates an empty Thread group that is not in any Thread group.
1091      * This method is used to create the system Thread group.
1092      */
1093     private this() {     // called from C code
1094         this.name = "system";
1095         this.maxPriority = Thread.PRIORITY_MAX;
1096         this.parent = null;
1097     }
1098 
1099     /**
1100      * Constructs a new thread group. The parent of this new group is
1101      * the thread group of the currently running thread.
1102      * <p>
1103      * The {@code checkAccess} method of the parent thread group is
1104      * called with no arguments; this may result in a security exception.
1105      *
1106      * @param   name   the name of the new thread group.
1107      * @throws  SecurityException  if the current thread cannot create a
1108      *               thread in the specified thread group.
1109      * @see     java.lang.ThreadGroupEx#checkAccess()
1110      */
1111     this(string name) {
1112         ThreadEx t = cast(ThreadEx)Thread.getThis();
1113         if(t is null)
1114             this(null, name);
1115         else
1116             this(t.getThreadGroup(), name);
1117     }
1118 
1119     /**
1120      * Creates a new thread group. The parent of this new group is the
1121      * specified thread group.
1122      * <p>
1123      * The {@code checkAccess} method of the parent thread group is
1124      * called with no arguments; this may result in a security exception.
1125      *
1126      * @param     parent   the parent thread group.
1127      * @param     name     the name of the new thread group.
1128      * @throws    NullPointerException  if the thread group argument is
1129      *               {@code null}.
1130      * @throws    SecurityException  if the current thread cannot create a
1131      *               thread in the specified thread group.
1132      * @see     java.lang.SecurityException
1133      * @see     java.lang.ThreadGroupEx#checkAccess()
1134      */
1135     this(ThreadGroupEx parent, string name) {
1136         // this(checkParentAccess(parent), parent, name);
1137         
1138         this.name = name;
1139         if(parent !is null) {
1140             parent.checkAccess();
1141             this.maxPriority = parent.maxPriority;
1142             this.daemon = parent.daemon;
1143             this.parent = parent;
1144             parent.add(this);
1145         }
1146     }
1147 
1148     // private ThreadGroupEx(Void unused, ThreadGroupEx parent, string name) {
1149     //     this.name = name;
1150     //     this.maxPriority = parent.maxPriority;
1151     //     this.daemon = parent.daemon;
1152     //     this.parent = parent;
1153     //     parent.add(this);
1154     // }
1155 
1156     /*
1157      * @throws  NullPointerException  if the parent argument is {@code null}
1158      * @throws  SecurityException     if the current thread cannot create a
1159      *                                thread in the specified thread group.
1160      */
1161     // private static void checkParentAccess(ThreadGroupEx parent) {
1162     //     parent.checkAccess();
1163     //     // return null;
1164     // }
1165 
1166     /**
1167      * Returns the name of this thread group.
1168      *
1169      * @return  the name of this thread group.
1170      */
1171     final string getName() {
1172         return name;
1173     }
1174 
1175     /**
1176      * Returns the parent of this thread group.
1177      * <p>
1178      * First, if the parent is not {@code null}, the
1179      * {@code checkAccess} method of the parent thread group is
1180      * called with no arguments; this may result in a security exception.
1181      *
1182      * @return  the parent of this thread group. The top-level thread group
1183      *          is the only thread group whose parent is {@code null}.
1184      * @throws  SecurityException  if the current thread cannot modify
1185      *               this thread group.
1186      * @see        java.lang.ThreadGroupEx#checkAccess()
1187      * @see        java.lang.SecurityException
1188      * @see        java.lang.RuntimePermission
1189      */
1190     final ThreadGroupEx getParent() {
1191         if (parent !is null)
1192             parent.checkAccess();
1193         return parent;
1194     }
1195 
1196     /**
1197      * Returns the maximum priority of this thread group. Threads that are
1198      * part of this group cannot have a higher priority than the maximum
1199      * priority.
1200      *
1201      * @return  the maximum priority that a thread in this thread group
1202      *          can have.
1203      * @see     #setMaxPriority
1204      */
1205     final int getMaxPriority() {
1206         return maxPriority;
1207     }
1208 
1209     /**
1210      * Tests if this thread group is a daemon thread group. A
1211      * daemon thread group is automatically destroyed when its last
1212      * thread is stopped or its last thread group is destroyed.
1213      *
1214      * @return  {@code true} if this thread group is a daemon thread group;
1215      *          {@code false} otherwise.
1216      */
1217     final bool isDaemon() {
1218         return daemon;
1219     }
1220 
1221     /**
1222      * Tests if this thread group has been destroyed.
1223      *
1224      * @return  true if this object is destroyed
1225      */
1226     bool isDestroyed() {
1227         return destroyed;
1228     }
1229 
1230     /**
1231      * Changes the daemon status of this thread group.
1232      * <p>
1233      * First, the {@code checkAccess} method of this thread group is
1234      * called with no arguments; this may result in a security exception.
1235      * <p>
1236      * A daemon thread group is automatically destroyed when its last
1237      * thread is stopped or its last thread group is destroyed.
1238      *
1239      * @param      daemon   if {@code true}, marks this thread group as
1240      *                      a daemon thread group; otherwise, marks this
1241      *                      thread group as normal.
1242      * @throws     SecurityException  if the current thread cannot modify
1243      *               this thread group.
1244      * @see        java.lang.SecurityException
1245      * @see        java.lang.ThreadGroupEx#checkAccess()
1246      */
1247     final void setDaemon(bool daemon) {
1248         // checkAccess();
1249         this.daemon = daemon;
1250     }
1251 
1252     /**
1253      * Sets the maximum priority of the group. Threads in the thread
1254      * group that already have a higher priority are not affected.
1255      * <p>
1256      * First, the {@code checkAccess} method of this thread group is
1257      * called with no arguments; this may result in a security exception.
1258      * <p>
1259      * If the {@code pri} argument is less than
1260      * {@link Thread#PRIORITY_MIN} or greater than
1261      * {@link Thread#PRIORITY_MAX}, the maximum priority of the group
1262      * remains unchanged.
1263      * <p>
1264      * Otherwise, the priority of this ThreadGroupEx object is set to the
1265      * smaller of the specified {@code pri} and the maximum permitted
1266      * priority of the parent of this thread group. (If this thread group
1267      * is the system thread group, which has no parent, then its maximum
1268      * priority is simply set to {@code pri}.) Then this method is
1269      * called recursively, with {@code pri} as its argument, for
1270      * every thread group that belongs to this thread group.
1271      *
1272      * @param      pri   the new priority of the thread group.
1273      * @throws     SecurityException  if the current thread cannot modify
1274      *               this thread group.
1275      * @see        #getMaxPriority
1276      * @see        java.lang.SecurityException
1277      * @see        java.lang.ThreadGroupEx#checkAccess()
1278      */
1279     final void setMaxPriority(int pri) {
1280         int ngroupsSnapshot;
1281         ThreadGroupEx[] groupsSnapshot;
1282         synchronized (this) {
1283             checkAccess();
1284             if (pri < Thread.PRIORITY_MIN || pri > Thread.PRIORITY_MAX) {
1285                 return;
1286             }
1287             maxPriority = (parent !is null) ? min(pri, parent.maxPriority) : pri;
1288             ngroupsSnapshot = ngroups;
1289             if (groups !is null) {
1290                 // groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
1291                 size_t limit = min(ngroupsSnapshot, groups.length);
1292                 groupsSnapshot = groups[0..limit].dup;
1293             } else {
1294                 groupsSnapshot = null;
1295             }
1296         }
1297         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
1298             groupsSnapshot[i].setMaxPriority(pri);
1299         }
1300     }
1301 
1302     /**
1303      * Tests if this thread group is either the thread group
1304      * argument or one of its ancestor thread groups.
1305      *
1306      * @param   g   a thread group.
1307      * @return  {@code true} if this thread group is the thread group
1308      *          argument or one of its ancestor thread groups;
1309      *          {@code false} otherwise.
1310      */
1311     final bool parentOf(ThreadGroupEx g) {
1312         for (; g !is null ; g = g.parent) {
1313             if (g is this) {
1314                 return true;
1315             }
1316         }
1317         return false;
1318     }
1319 
1320     /**
1321      * Determines if the currently running thread has permission to
1322      * modify this thread group.
1323      * <p>
1324      * If there is a security manager, its {@code checkAccess} method
1325      * is called with this thread group as its argument. This may result
1326      * in throwing a {@code SecurityException}.
1327      *
1328      * @throws     SecurityException  if the current thread is not allowed to
1329      *               access this thread group.
1330      * @see        java.lang.SecurityManager#checkAccess(java.lang.ThreadGroupEx)
1331      */
1332     final void checkAccess() {
1333         // SecurityManager security = System.getSecurityManager();
1334         // if (security !is null) {
1335         //     security.checkAccess(this);
1336         // }
1337     }
1338 
1339     /**
1340      * Returns an estimate of the number of active threads in this thread
1341      * group and its subgroups. Recursively iterates over all subgroups in
1342      * this thread group.
1343      *
1344      * <p> The value returned is only an estimate because the number of
1345      * threads may change dynamically while this method traverses internal
1346      * data structures, and might be affected by the presence of certain
1347      * system threads. This method is intended primarily for debugging
1348      * and monitoring purposes.
1349      *
1350      * @return  an estimate of the number of active threads in this thread
1351      *          group and in any other thread group that has this thread
1352      *          group as an ancestor
1353      *
1354      */
1355     int activeCount() {
1356         int result;
1357         // Snapshot sub-group data so we don't hold this lock
1358         // while our children are computing.
1359         int ngroupsSnapshot;
1360         ThreadGroupEx[] groupsSnapshot;
1361         synchronized (this) {
1362             if (destroyed) {
1363                 return 0;
1364             }
1365             result = nthreads;
1366             ngroupsSnapshot = ngroups;
1367             if (groups !is null) {
1368                 size_t limit = min(ngroupsSnapshot, groups.length);
1369                 groupsSnapshot = groups[0..limit].dup;
1370             } else {
1371                 groupsSnapshot = null;
1372             }
1373         }
1374         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
1375             result += groupsSnapshot[i].activeCount();
1376         }
1377         return result;
1378     }
1379 
1380     /**
1381      * Copies into the specified array every active thread in this
1382      * thread group and its subgroups.
1383      *
1384      * <p> An invocation of this method behaves in exactly the same
1385      * way as the invocation
1386      *
1387      * <blockquote>
1388      * {@linkplain #enumerate(Thread[], bool) enumerate}{@code (list, true)}
1389      * </blockquote>
1390      *
1391      * @param  list
1392      *         an array into which to put the list of threads
1393      *
1394      * @return  the number of threads put into the array
1395      *
1396      * @throws  SecurityException
1397      *          if {@linkplain #checkAccess checkAccess} determines that
1398      *          the current thread cannot access this thread group
1399      *
1400      */
1401     int enumerate(Thread[] list) {
1402         checkAccess();
1403         return enumerate(list, 0, true);
1404     }
1405 
1406     /**
1407      * Copies into the specified array every active thread in this
1408      * thread group. If {@code recurse} is {@code true},
1409      * this method recursively enumerates all subgroups of this
1410      * thread group and references to every active thread in these
1411      * subgroups are also included. If the array is too short to
1412      * hold all the threads, the extra threads are silently ignored.
1413      *
1414      * <p> An application might use the {@linkplain #activeCount activeCount}
1415      * method to get an estimate of how big the array should be, however
1416      * <i>if the array is too short to hold all the threads, the extra threads
1417      * are silently ignored.</i>  If it is critical to obtain every active
1418      * thread in this thread group, the caller should verify that the returned
1419      * int value is strictly less than the length of {@code list}.
1420      *
1421      * <p> Due to the inherent race condition in this method, it is recommended
1422      * that the method only be used for debugging and monitoring purposes.
1423      *
1424      * @param  list
1425      *         an array into which to put the list of threads
1426      *
1427      * @param  recurse
1428      *         if {@code true}, recursively enumerate all subgroups of this
1429      *         thread group
1430      *
1431      * @return  the number of threads put into the array
1432      *
1433      * @throws  SecurityException
1434      *          if {@linkplain #checkAccess checkAccess} determines that
1435      *          the current thread cannot access this thread group
1436      *
1437      */
1438     int enumerate(Thread[] list, bool recurse) {
1439         checkAccess();
1440         return enumerate(list, 0, recurse);
1441     }
1442 
1443     private int enumerate(Thread[] list, int n, bool recurse) {
1444         int ngroupsSnapshot = 0;
1445         ThreadGroupEx[] groupsSnapshot = null;
1446         synchronized (this) {
1447             if (destroyed) {
1448                 return 0;
1449             }
1450             int nt = nthreads;
1451             if (nt > cast(int)list.length - n) {
1452                 nt = cast(int)list.length - n;
1453             }
1454             for (int i = 0; i < nt; i++) {
1455                 // TODO: Tasks pending completion -@zxp at 10/14/2018, 9:11:46 AM
1456                 // 
1457                 implementationMissing(false);
1458                 // if (threads[i].isAlive()) {
1459                 //     list[n++] = threads[i];
1460                 // }
1461             }
1462             if (recurse) {
1463                 ngroupsSnapshot = ngroups;
1464                 if (groups !is null) {
1465                     size_t limit = min(ngroupsSnapshot, groups.length);
1466                     groupsSnapshot = groups[0..limit].dup;
1467                 } else {
1468                     groupsSnapshot = null;
1469                 }
1470             }
1471         }
1472         if (recurse) {
1473             for (int i = 0 ; i < ngroupsSnapshot ; i++) {
1474                 n = groupsSnapshot[i].enumerate(list, n, true);
1475             }
1476         }
1477         return n;
1478     }
1479 
1480     /**
1481      * Returns an estimate of the number of active groups in this
1482      * thread group and its subgroups. Recursively iterates over
1483      * all subgroups in this thread group.
1484      *
1485      * <p> The value returned is only an estimate because the number of
1486      * thread groups may change dynamically while this method traverses
1487      * internal data structures. This method is intended primarily for
1488      * debugging and monitoring purposes.
1489      *
1490      * @return  the number of active thread groups with this thread group as
1491      *          an ancestor
1492      *
1493      */
1494     int activeGroupCount() {
1495         int ngroupsSnapshot;
1496         ThreadGroupEx[] groupsSnapshot;
1497         synchronized (this) {
1498             if (destroyed) {
1499                 return 0;
1500             }
1501             ngroupsSnapshot = ngroups;
1502             if (groups !is null) {
1503                 size_t limit = min(ngroupsSnapshot, groups.length);
1504                 groupsSnapshot = groups[0..limit].dup;
1505             } else {
1506                 groupsSnapshot = null;
1507             }
1508         }
1509         int n = ngroupsSnapshot;
1510         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
1511             n += groupsSnapshot[i].activeGroupCount();
1512         }
1513         return n;
1514     }
1515 
1516     /**
1517      * Copies into the specified array references to every active
1518      * subgroup in this thread group and its subgroups.
1519      *
1520      * <p> An invocation of this method behaves in exactly the same
1521      * way as the invocation
1522      *
1523      * <blockquote>
1524      * {@linkplain #enumerate(ThreadGroupEx[], bool) enumerate}{@code (list, true)}
1525      * </blockquote>
1526      *
1527      * @param  list
1528      *         an array into which to put the list of thread groups
1529      *
1530      * @return  the number of thread groups put into the array
1531      *
1532      * @throws  SecurityException
1533      *          if {@linkplain #checkAccess checkAccess} determines that
1534      *          the current thread cannot access this thread group
1535      *
1536      */
1537     int enumerate(ThreadGroupEx[] list) {
1538         checkAccess();
1539         return enumerate(list, 0, true);
1540     }
1541 
1542     /**
1543      * Copies into the specified array references to every active
1544      * subgroup in this thread group. If {@code recurse} is
1545      * {@code true}, this method recursively enumerates all subgroups of this
1546      * thread group and references to every active thread group in these
1547      * subgroups are also included.
1548      *
1549      * <p> An application might use the
1550      * {@linkplain #activeGroupCount activeGroupCount} method to
1551      * get an estimate of how big the array should be, however <i>if the
1552      * array is too short to hold all the thread groups, the extra thread
1553      * groups are silently ignored.</i>  If it is critical to obtain every
1554      * active subgroup in this thread group, the caller should verify that
1555      * the returned int value is strictly less than the length of
1556      * {@code list}.
1557      *
1558      * <p> Due to the inherent race condition in this method, it is recommended
1559      * that the method only be used for debugging and monitoring purposes.
1560      *
1561      * @param  list
1562      *         an array into which to put the list of thread groups
1563      *
1564      * @param  recurse
1565      *         if {@code true}, recursively enumerate all subgroups
1566      *
1567      * @return  the number of thread groups put into the array
1568      *
1569      * @throws  SecurityException
1570      *          if {@linkplain #checkAccess checkAccess} determines that
1571      *          the current thread cannot access this thread group
1572      *
1573      */
1574     int enumerate(ThreadGroupEx[] list, bool recurse) {
1575         checkAccess();
1576         return enumerate(list, 0, recurse);
1577     }
1578 
1579     private int enumerate(ThreadGroupEx[] list, int n, bool recurse) {
1580         int ngroupsSnapshot = 0;
1581         ThreadGroupEx[] groupsSnapshot = null;
1582         synchronized (this) {
1583             if (destroyed) {
1584                 return 0;
1585             }
1586             int ng = ngroups;
1587             if (ng > cast(int)list.length - n) {
1588                 ng = cast(int)list.length - n;
1589             }
1590             if (ng > 0) {
1591                 // System.arraycopy(groups, 0, list, n, ng);
1592                 list[n .. n+ng] = groups[0..ng];
1593                 n += ng;
1594             }
1595             if (recurse) {
1596                 ngroupsSnapshot = ngroups;
1597                 if (groups !is null) {
1598                     size_t limit = min(ngroupsSnapshot, groups.length);
1599                     groupsSnapshot = groups[0..limit].dup;
1600                 } else {
1601                     groupsSnapshot = null;
1602                 }
1603             }
1604         }
1605         if (recurse) {
1606             for (int i = 0 ; i < ngroupsSnapshot ; i++) {
1607                 n = groupsSnapshot[i].enumerate(list, n, true);
1608             }
1609         }
1610         return n;
1611     }
1612 
1613     /**
1614      * Stops all threads in this thread group.
1615      * <p>
1616      * First, the {@code checkAccess} method of this thread group is
1617      * called with no arguments; this may result in a security exception.
1618      * <p>
1619      * This method then calls the {@code stop} method on all the
1620      * threads in this thread group and in all of its subgroups.
1621      *
1622      * @throws     SecurityException  if the current thread is not allowed
1623      *               to access this thread group or any of the threads in
1624      *               the thread group.
1625      * @see        java.lang.SecurityException
1626      * @see        java.lang.Thread#stop()
1627      * @see        java.lang.ThreadGroupEx#checkAccess()
1628      * @deprecated    This method is inherently unsafe.  See
1629      *     {@link Thread#stop} for details.
1630      */
1631     // @Deprecated(since="1.2")
1632     // final void stop() {
1633     //     if (stopOrSuspend(false))
1634     //         Thread.getThis().stop();
1635     // }
1636 
1637     /**
1638      * Interrupts all threads in this thread group.
1639      * <p>
1640      * First, the {@code checkAccess} method of this thread group is
1641      * called with no arguments; this may result in a security exception.
1642      * <p>
1643      * This method then calls the {@code interrupt} method on all the
1644      * threads in this thread group and in all of its subgroups.
1645      *
1646      * @throws     SecurityException  if the current thread is not allowed
1647      *               to access this thread group or any of the threads in
1648      *               the thread group.
1649      * @see        java.lang.Thread#interrupt()
1650      * @see        java.lang.SecurityException
1651      * @see        java.lang.ThreadGroupEx#checkAccess()
1652      */
1653     final void interrupt() {
1654         int ngroupsSnapshot;
1655         ThreadGroupEx[] groupsSnapshot;
1656         synchronized (this) {
1657             checkAccess();
1658             // for (int i = 0 ; i < nthreads ; i++) {
1659             //     threads[i].interrupt();
1660             // }
1661             ngroupsSnapshot = ngroups;
1662             if (groups !is null) {
1663                 size_t limit = min(ngroupsSnapshot, groups.length);
1664                 groupsSnapshot = groups[0..limit].dup;
1665             } else {
1666                 groupsSnapshot = null;
1667             }
1668         }
1669         for (int i = 0 ; i < ngroupsSnapshot ; i++) {
1670             groupsSnapshot[i].interrupt();
1671         }
1672     }
1673 
1674     /**
1675      * Suspends all threads in this thread group.
1676      * <p>
1677      * First, the {@code checkAccess} method of this thread group is
1678      * called with no arguments; this may result in a security exception.
1679      * <p>
1680      * This method then calls the {@code suspend} method on all the
1681      * threads in this thread group and in all of its subgroups.
1682      *
1683      * @throws     SecurityException  if the current thread is not allowed
1684      *               to access this thread group or any of the threads in
1685      *               the thread group.
1686      * @see        java.lang.Thread#suspend()
1687      * @see        java.lang.SecurityException
1688      * @see        java.lang.ThreadGroupEx#checkAccess()
1689      * @deprecated    This method is inherently deadlock-prone.  See
1690      *     {@link Thread#suspend} for details.
1691      */
1692     // @Deprecated(since="1.2")
1693     // @SuppressWarnings("deprecation")
1694     // final void suspend() {
1695     //     if (stopOrSuspend(true))
1696     //         Thread.getThis().suspend();
1697     // }
1698 
1699     /**
1700      * Helper method: recursively stops or suspends (as directed by the
1701      * bool argument) all of the threads in this thread group and its
1702      * subgroups, except the current thread.  This method returns true
1703      * if (and only if) the current thread is found to be in this thread
1704      * group or one of its subgroups.
1705      */
1706     // @SuppressWarnings("deprecation")
1707     // private bool stopOrSuspend(bool suspend) {
1708     //     bool suicide = false;
1709     //     Thread us = Thread.getThis();
1710     //     int ngroupsSnapshot;
1711     //     ThreadGroupEx[] groupsSnapshot = null;
1712     //     synchronized (this) {
1713     //         checkAccess();
1714     //         for (int i = 0 ; i < nthreads ; i++) {
1715     //             if (threads[i]==us)
1716     //                 suicide = true;
1717     //             else if (suspend)
1718     //                 threads[i].suspend();
1719     //             else
1720     //                 threads[i].stop();
1721     //         }
1722 
1723     //         ngroupsSnapshot = ngroups;
1724     //         if (groups !is null) {
1725     //             groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
1726     //         }
1727     //     }
1728     //     for (int i = 0 ; i < ngroupsSnapshot ; i++)
1729     //         suicide = groupsSnapshot[i].stopOrSuspend(suspend) || suicide;
1730 
1731     //     return suicide;
1732     // }
1733 
1734     /**
1735      * Resumes all threads in this thread group.
1736      * <p>
1737      * First, the {@code checkAccess} method of this thread group is
1738      * called with no arguments; this may result in a security exception.
1739      * <p>
1740      * This method then calls the {@code resume} method on all the
1741      * threads in this thread group and in all of its sub groups.
1742      *
1743      * @throws     SecurityException  if the current thread is not allowed to
1744      *               access this thread group or any of the threads in the
1745      *               thread group.
1746      * @see        java.lang.SecurityException
1747      * @see        java.lang.Thread#resume()
1748      * @see        java.lang.ThreadGroupEx#checkAccess()
1749      * @deprecated    This method is used solely in conjunction with
1750      *       {@code Thread.suspend} and {@code ThreadGroupEx.suspend},
1751      *       both of which have been deprecated, as they are inherently
1752      *       deadlock-prone.  See {@link Thread#suspend} for details.
1753      */
1754     // @Deprecated(since="1.2")
1755     // @SuppressWarnings("deprecation")
1756     // final void resume() {
1757     //     int ngroupsSnapshot;
1758     //     ThreadGroupEx[] groupsSnapshot;
1759     //     synchronized (this) {
1760     //         checkAccess();
1761     //         for (int i = 0 ; i < nthreads ; i++) {
1762     //             threads[i].resume();
1763     //         }
1764     //         ngroupsSnapshot = ngroups;
1765     //         if (groups !is null) {
1766     //             groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
1767     //         } else {
1768     //             groupsSnapshot = null;
1769     //         }
1770     //     }
1771     //     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
1772     //         groupsSnapshot[i].resume();
1773     //     }
1774     // }
1775 
1776     /**
1777      * Destroys this thread group and all of its subgroups. This thread
1778      * group must be empty, indicating that all threads that had been in
1779      * this thread group have since stopped.
1780      * <p>
1781      * First, the {@code checkAccess} method of this thread group is
1782      * called with no arguments; this may result in a security exception.
1783      *
1784      * @throws     IllegalThreadStateException  if the thread group is not
1785      *               empty or if the thread group has already been destroyed.
1786      * @throws     SecurityException  if the current thread cannot modify this
1787      *               thread group.
1788      * @see        java.lang.ThreadGroupEx#checkAccess()
1789      */
1790     final void destroy() {
1791         int ngroupsSnapshot;
1792         ThreadGroupEx[] groupsSnapshot;
1793         synchronized (this) {
1794             checkAccess();
1795             if (destroyed || (nthreads > 0)) {
1796                 throw new IllegalThreadStateException();
1797             }
1798             ngroupsSnapshot = ngroups;
1799             if (groups !is null) {
1800                 size_t limit = min(ngroupsSnapshot, groups.length);
1801                 groupsSnapshot = groups[0..limit].dup;
1802             } else {
1803                 groupsSnapshot = null;
1804             }
1805             if (parent !is null) {
1806                 destroyed = true;
1807                 ngroups = 0;
1808                 groups = null;
1809                 nthreads = 0;
1810                 threads = null;
1811             }
1812         }
1813         for (int i = 0 ; i < ngroupsSnapshot ; i += 1) {
1814             groupsSnapshot[i].destroy();
1815         }
1816         if (parent !is null) {
1817             parent.remove(this);
1818         }
1819     }
1820 
1821     /**
1822      * Adds the specified Thread group to this group.
1823      * @param g the specified Thread group to be added
1824      * @throws  IllegalThreadStateException If the Thread group has been destroyed.
1825      */
1826     private final void add(ThreadGroupEx g){
1827         synchronized (this) {
1828             if (destroyed) {
1829                 throw new IllegalThreadStateException();
1830             }
1831             if (groups == null) {
1832                 groups = new ThreadGroupEx[4];
1833             } else if (ngroups == groups.length) {
1834                 size_t limit = min(ngroups * 2, groups.length);
1835                 groups = groups[0..limit].dup;
1836             }
1837             groups[ngroups] = g;
1838 
1839             // This is done last so it doesn't matter in case the
1840             // thread is killed
1841             ngroups++;
1842         }
1843     }
1844 
1845     /**
1846      * Removes the specified Thread group from this group.
1847      * @param g the Thread group to be removed
1848      * @return if this Thread has already been destroyed.
1849      */
1850     private void remove(ThreadGroupEx g) {
1851         synchronized (this) {
1852             if (destroyed) {
1853                 return;
1854             }
1855             for (int i = 0 ; i < ngroups ; i++) {
1856                 if (groups[i] == g) {
1857                     ngroups -= 1;
1858                     // System.arraycopy(groups, i + 1, groups, i, ngroups - i);
1859                     for(int j=i; j<ngroups; j++)
1860                         groups[j] = groups[j+1];                    
1861                     // Zap dangling reference to the dead group so that
1862                     // the garbage collector will collect it.
1863                     groups[ngroups] = null;
1864                     break;
1865                 }
1866             }
1867             if (nthreads == 0) {
1868                 // TODO: Tasks pending completion -@zxp at 12/19/2018, 4:57:38 PM
1869                 // 
1870                 // notifyAll();
1871             }
1872             if (daemon && (nthreads == 0) &&
1873                 (nUnstartedThreads == 0) && (ngroups == 0))
1874             {
1875                 // TODO: Tasks pending completion -@zxp at 12/19/2018, 4:57:42 PM
1876                 // 
1877                 // destroy();
1878             }
1879         }
1880     }
1881 
1882 
1883     /**
1884      * Increments the count of unstarted threads in the thread group.
1885      * Unstarted threads are not added to the thread group so that they
1886      * can be collected if they are never started, but they must be
1887      * counted so that daemon thread groups with unstarted threads in
1888      * them are not destroyed.
1889      */
1890     void addUnstarted() {
1891         synchronized(this) {
1892             if (destroyed) {
1893                 throw new IllegalThreadStateException();
1894             }
1895             nUnstartedThreads++;
1896         }
1897     }
1898 
1899     /**
1900      * Adds the specified thread to this thread group.
1901      *
1902      * <p> Note: This method is called from both library code
1903      * and the Virtual Machine. It is called from VM to add
1904      * certain system threads to the system thread group.
1905      *
1906      * @param  t
1907      *         the Thread to be added
1908      *
1909      * @throws IllegalThreadStateException
1910      *          if the Thread group has been destroyed
1911      */
1912     void add(Thread t) {
1913         synchronized (this) {
1914             if (destroyed) {
1915                 throw new IllegalThreadStateException();
1916             }
1917             if (threads == null) {
1918                 threads = new Thread[4];
1919             } else if (nthreads == threads.length) {
1920                 size_t limit = min(nthreads * 2, threads.length);
1921                 threads = threads[0..limit].dup;
1922             }
1923             threads[nthreads] = t;
1924 
1925             // This is done last so it doesn't matter in case the
1926             // thread is killed
1927             nthreads++;
1928 
1929             // The thread is now a fully fledged member of the group, even
1930             // though it may, or may not, have been started yet. It will prevent
1931             // the group from being destroyed so the unstarted Threads count is
1932             // decremented.
1933             nUnstartedThreads--;
1934         }
1935     }
1936 
1937     /**
1938      * Notifies the group that the thread {@code t} has failed
1939      * an attempt to start.
1940      *
1941      * <p> The state of this thread group is rolled back as if the
1942      * attempt to start the thread has never occurred. The thread is again
1943      * considered an unstarted member of the thread group, and a subsequent
1944      * attempt to start the thread is permitted.
1945      *
1946      * @param  t
1947      *         the Thread whose start method was invoked
1948      */
1949     void threadStartFailed(Thread t) {
1950         synchronized(this) {
1951             remove(t);
1952             nUnstartedThreads++;
1953         }
1954     }
1955 
1956     /**
1957      * Notifies the group that the thread {@code t} has terminated.
1958      *
1959      * <p> Destroy the group if all of the following conditions are
1960      * true: this is a daemon thread group; there are no more alive
1961      * or unstarted threads in the group; there are no subgroups in
1962      * this thread group.
1963      *
1964      * @param  t
1965      *         the Thread that has terminated
1966      */
1967     void threadTerminated(Thread t) {
1968         synchronized (this) {
1969             remove(t);
1970 
1971             if (nthreads == 0) {
1972                 // TODO: Tasks pending completion -@zxp at 12/19/2018, 4:57:55 PM
1973                 // 
1974                 // notifyAll();
1975             }
1976             if (daemon && (nthreads == 0) &&
1977                 (nUnstartedThreads == 0) && (ngroups == 0))
1978             {
1979                 destroy();
1980             }
1981         }
1982     }
1983 
1984     /**
1985      * Removes the specified Thread from this group. Invoking this method
1986      * on a thread group that has been destroyed has no effect.
1987      *
1988      * @param  t
1989      *         the Thread to be removed
1990      */
1991     private void remove(Thread t) {
1992         synchronized (this) {
1993             if (destroyed) {
1994                 return;
1995             }
1996             for (int i = 0 ; i < nthreads ; i++) {
1997                 if (threads[i] == t) {
1998                     // System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
1999                     for(int j=i; j<ngroups; j++)
2000                         groups[j] = groups[j+1];                    
2001                     // Zap dangling reference to the dead thread so that
2002                     // the garbage collector will collect it.
2003                     threads[nthreads] = null;
2004                     break;
2005                 }
2006             }
2007         }
2008     }
2009 
2010     /**
2011      * Prints information about this thread group to the standard
2012      * output. This method is useful only for debugging.
2013      *
2014      */
2015     void list() {
2016         // list(System.out, 0);
2017     }
2018     // void list(PrintStream out, int indent) {
2019     //     int ngroupsSnapshot;
2020     //     ThreadGroupEx[] groupsSnapshot;
2021     //     synchronized (this) {
2022     //         for (int j = 0 ; j < indent ; j++) {
2023     //             out.print(" ");
2024     //         }
2025     //         out.println(this);
2026     //         indent += 4;
2027     //         for (int i = 0 ; i < nthreads ; i++) {
2028     //             for (int j = 0 ; j < indent ; j++) {
2029     //                 out.print(" ");
2030     //             }
2031     //             out.println(threads[i]);
2032     //         }
2033     //         ngroupsSnapshot = ngroups;
2034     //         if (groups !is null) {
2035     //             groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
2036     //         } else {
2037     //             groupsSnapshot = null;
2038     //         }
2039     //     }
2040     //     for (int i = 0 ; i < ngroupsSnapshot ; i++) {
2041     //         groupsSnapshot[i].list(out, indent);
2042     //     }
2043     // }
2044 
2045     /**
2046      * Called by the Java Virtual Machine when a thread in this
2047      * thread group stops because of an uncaught exception, and the thread
2048      * does not have a specific {@link Thread.UncaughtExceptionHandler}
2049      * installed.
2050      * <p>
2051      * The {@code uncaughtException} method of
2052      * {@code ThreadGroupEx} does the following:
2053      * <ul>
2054      * <li>If this thread group has a parent thread group, the
2055      *     {@code uncaughtException} method of that parent is called
2056      *     with the same two arguments.
2057      * <li>Otherwise, this method checks to see if there is a
2058      *     {@linkplain Thread#getDefaultUncaughtExceptionHandler default
2059      *     uncaught exception handler} installed, and if so, its
2060      *     {@code uncaughtException} method is called with the same
2061      *     two arguments.
2062      * <li>Otherwise, this method determines if the {@code Throwable}
2063      *     argument is an instance of {@link ThreadDeath}. If so, nothing
2064      *     special is done. Otherwise, a message containing the
2065      *     thread's name, as returned from the thread's {@link
2066      *     Thread#getName getName} method, and a stack backtrace,
2067      *     using the {@code Throwable}'s {@link
2068      *     Throwable#printStackTrace printStackTrace} method, is
2069      *     printed to the {@linkplain System#err standard error stream}.
2070      * </ul>
2071      * <p>
2072      * Applications can override this method in subclasses of
2073      * {@code ThreadGroupEx} to provide alternative handling of
2074      * uncaught exceptions.
2075      *
2076      * @param   t   the thread that is about to exit.
2077      * @param   e   the uncaught exception.
2078      */
2079     void uncaughtException(Thread t, Throwable e) {
2080         if (parent !is null) {
2081             parent.uncaughtException(t, e);
2082         } else {
2083             // Thread.UncaughtExceptionHandler ueh =
2084             //     Thread.getDefaultUncaughtExceptionHandler();
2085             // if (ueh !is null) {
2086             //     ueh.uncaughtException(t, e);
2087             // } else if (!(e instanceof ThreadDeath)) {
2088             //     System.err.print("Exception in thread \""
2089             //                      + t.getName() + "\" ");
2090             //     e.printStackTrace(System.err);
2091             // }
2092         }
2093     }
2094 
2095     /**
2096      * Used by VM to control lowmem implicit suspension.
2097      *
2098      * @param b bool to allow or disallow suspension
2099      * @return true on success
2100      * @deprecated The definition of this call depends on {@link #suspend},
2101      *             which is deprecated.  Further, the behavior of this call
2102      *             was never specified.
2103      */
2104     // @Deprecated(since="1.2")
2105     // bool allowThreadSuspension(bool b) {
2106     //     return true;
2107     // }
2108 
2109     /**
2110      * Returns a string representation of this Thread group.
2111      *
2112      * @return  a string representation of this thread group.
2113      */
2114     // string toString() {
2115     //     return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]";
2116     // }
2117 }