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