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 * . . . 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 * . . . 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 "default" 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 }