Changeset 487
- Timestamp:
- 01/08/11 19:35:23 (14 years ago)
- Files:
-
- trunk/src/core/thread.d (modified) (5 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/src/core/thread.d
r486 r487 150 150 151 151 assert( obj.m_curr is &obj.m_main ); 152 152 obj.m_main.bstack = getStackBottom(); 153 153 obj.m_main.tstack = obj.m_main.bstack; 154 154 155 155 void* pstart = cast(void*) &_tlsstart; 156 156 void* pend = cast(void*) &_tlsend; 157 157 obj.m_tls = pstart[0 .. pend - pstart]; 158 158 159 159 Thread.setThis( obj ); 160 Thread.add( obj );160 //Thread.add( obj ); 161 161 scope( exit ) 162 162 { 163 163 Thread.remove( obj ); 164 164 } 165 165 Thread.add( &obj.m_main ); 166 166 167 167 // NOTE: No GC allocations may occur until the stack pointers have 168 168 // been set and Thread.getThis returns a valid reference to 169 169 // this thread object (this latter condition is not strictly 170 170 // necessary on Windows but it should be followed for the … … 353 353 } 354 354 else 355 355 { 356 356 auto pstart = cast(void*) &_tlsstart; 357 357 auto pend = cast(void*) &_tlsend; 358 358 obj.m_tls = pstart[0 .. pend - pstart]; 359 359 } 360 360 361 361 obj.m_isRunning = true; 362 362 Thread.setThis( obj ); 363 Thread.add( obj );363 //Thread.add( obj ); 364 364 scope( exit ) 365 365 { 366 366 // NOTE: isRunning should be set to false after the thread is 367 367 // removed or a double-removal could occur between this 368 368 // function and thread_suspendAll. 369 369 Thread.remove( obj ); 370 370 obj.m_isRunning = false; 371 371 } 372 372 Thread.add( &obj.m_main ); 373 373 … … 785 785 pthread_attr_t attr; 786 786 787 787 if( pthread_attr_init( &attr ) ) 788 788 throw new ThreadException( "Error initializing thread attributes" ); 789 789 if( m_sz && pthread_attr_setstacksize( &attr, m_sz ) ) 790 790 throw new ThreadException( "Error initializing thread stack size" ); 791 791 if( pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ) ) 792 792 throw new ThreadException( "Error setting thread joinable" ); 793 793 } 794 794 795 version( Windows ) 796 { 797 m_hndl = cast(HANDLE) _beginthreadex( null, m_sz, &thread_entryPoint, cast(void*) this, 0, &m_addr ); 798 if( cast(size_t) m_hndl == 0 ) 799 throw new ThreadException( "Error creating thread" ); 800 } 801 else version( Posix ) 802 { 803 // NOTE: This is also set to true by thread_entryPoint, but set it 804 // here as well so the calling thread will see the isRunning 805 // state immediately. 806 m_isRunning = true; 807 scope( failure ) m_isRunning = false; 808 809 if( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 ) 810 throw new ThreadException( "Error creating thread" ); 811 } 812 version( OSX ) 813 { 814 m_tmach = pthread_mach_thread_np( m_addr ); 815 if( m_tmach == m_tmach.init ) 816 throw new ThreadException( "Error creating thread" ); 795 // NOTE: The starting thread must be added to the global thread list 796 // here rather than within thread_entryPoint to prevent a race 797 // with the main thread, which could finish and terminat the 798 // app without ever knowing that it should have waited for this 799 // starting thread. In effect, not doing the add here risks 800 // having thread being treated like a daemon thread. 801 synchronized( slock ) 802 { 803 version( Windows ) 804 { 805 m_hndl = cast(HANDLE) _beginthreadex( null, m_sz, &thread_entryPoint, cast(void*) this, 0, &m_addr ); 806 if( cast(size_t) m_hndl == 0 ) 807 throw new ThreadException( "Error creating thread" ); 808 } 809 else version( Posix ) 810 { 811 // NOTE: This is also set to true by thread_entryPoint, but set it 812 // here as well so the calling thread will see the isRunning 813 // state immediately. 814 m_isRunning = true; 815 scope( failure ) m_isRunning = false; 816 817 if( pthread_create( &m_addr, &attr, &thread_entryPoint, cast(void*) this ) != 0 ) 818 throw new ThreadException( "Error creating thread" ); 819 } 820 version( OSX ) 821 { 822 m_tmach = pthread_mach_thread_np( m_addr ); 823 if( m_tmach == m_tmach.init ) 824 throw new ThreadException( "Error creating thread" ); 825 } 826 add( this ); 817 827 } 818 828 } 819 829 820 830 821 831 /** 822 832 * Waits for this thread to complete. If the thread terminated as the 823 833 * result of an unhandled exception, this exception will be rethrown. 824 834 * 825 835 * Params: 826 836 * rethrow = Rethrow any unhandled exception which may have caused this … … 1610 1620 // Add a context to the global context list. 1611 1621 // 1612 1622 static void add( Context* c ) 1613 1623 in 1614 1624 { 1615 1625 assert( c ); 1616 1626 assert( !c.next && !c.prev ); 1617 1627 } 1618 1628 body 1619 1629 { 1620 synchronized( slock ) 1621 { 1622 if( sm_cbeg ) 1623 { 1624 c.next = sm_cbeg; 1625 sm_cbeg.prev = c; 1626 } 1627 sm_cbeg = c; 1628 ++sm_clen; 1630 // NOTE: This loop is necessary to avoid a race between newly created 1631 // threads and the GC. If a collection starts between the time 1632 // Thread.start is called and the new thread calls Thread.add, 1633 // the thread will have its stack scanned without first having 1634 // been properly suspended. Testing has shown this to sometimes 1635 // cause a deadlock. 1636 1637 while( true ) 1638 { 1639 synchronized( slock ) 1640 { 1641 if( !suspendDepth ) 1642 { 1643 if( sm_cbeg ) 1644 { 1645 c.next = sm_cbeg; 1646 sm_cbeg.prev = c; 1647 } 1648 sm_cbeg = c; 1649 ++sm_clen; 1650 return; 1651 } 1652 } 1653 yield(); 1629 1654 } 1630 1655 } 1631 1656 1632 1657 1633 1658 // 1634 1659 // Remove a context from the global context list. 1635 1660 // 1636 1661 static void remove( Context* c ) 1637 1662 in 1638 1663 { … … 1676 1701 assert( t.isRunning ); 1677 1702 } 1678 1703 body 1679 1704 { 1680 1705 // NOTE: This loop is necessary to avoid a race between newly created 1681 1706 // threads and the GC. If a collection starts between the time 1682 1707 // Thread.start is called and the new thread calls Thread.add, 1683 1708 // the thread could manipulate global state while the collection 1684 1709 // is running, and by being added to the thread list it could be 1685 1710 // resumed by the GC when it was never suspended, which would 1686 // result in an exception thrown by the GC code. An alternative 1687 // would be to have Thread.start call Thread.add for the new 1688 // thread, but this introduces its own problems, since the 1689 // thread object isn't entirely ready to be operated on by the 1690 // GC. This could be fixed by tracking thread startup status, 1691 // but it's far easier to simply have Thread.add wait for any 1692 // running collection to stop before altering the thread list. 1711 // result in an exception thrown by the GC code. 1712 // 1713 // An alternative would be to have Thread.start call Thread.add 1714 // for the new thread, but this may introduce its own problems, 1715 // since the thread object isn't entirely ready to be operated 1716 // on by the GC. This could be fixed by tracking thread startup 1717 // status, but it's far easier to simply have Thread.add wait 1718 // for any running collection to stop before altering the thread 1719 // list. 1720 // 1721 // After further testing, having add wait for a collect to end 1722 // proved to have its own problems (explained in Thread.start), 1723 // so add(Thread) is now being done in Thread.start. This 1724 // reintroduced the deadlock issue mentioned in bugzilla 4890, 1725 // which appears to have been solved by doing this same wait 1726 // procedure in add(Context). These comments will remain in 1727 // case other issues surface that require the startup state 1728 // tracking described above. 1693 1729 1694 1730 while( true ) 1695 1731 { 1696 1732 synchronized( slock ) 1697 1733 { 1698 1734 if( !suspendDepth ) 1699 1735 { 1700 1736 if( sm_tbeg ) 1701 1737 { 1702 1738 t.next = sm_tbeg;
