@@ -165,7 +165,7 @@ use panic;
165165use panicking;
166166use str;
167167use sync:: { Mutex , Condvar , Arc } ;
168- use sync:: atomic:: { AtomicUsize , Ordering , ATOMIC_USIZE_INIT } ;
168+ use sync:: atomic:: { AtomicBool , Ordering } ;
169169use sys:: thread as imp;
170170use sys_common:: thread_info;
171171use sys_common:: util;
@@ -536,21 +536,52 @@ pub fn park_timeout(dur: Duration) {
536536/// designated identifier.
537537#[ unstable( feature = "thread_id" , issue = "21507" ) ]
538538#[ derive( Eq , PartialEq , Copy , Clone ) ]
539- pub struct ThreadId ( usize ) ;
539+ pub struct ThreadId ( u64 ) ;
540540
541541impl ThreadId {
542- /// Returns an identifier unique to the current calling thread.
543- #[ unstable( feature = "thread_id" , issue = "21507" ) ]
544- pub fn current ( ) -> ThreadId {
545- static THREAD_ID_COUNT : AtomicUsize = ATOMIC_USIZE_INIT ;
546- #[ thread_local] static mut THREAD_ID : ThreadId = ThreadId ( 0 ) ;
542+ // Generate a new unique thread ID. Since this function is called every
543+ // time a thread is created, this is optimized to generate unique values
544+ // as quickly as possible.
545+ fn new ( ) -> ThreadId {
546+ // 64-bit operations are not atomic on all systems, so use an atomic
547+ // flag as a guard around a 64-bit global counter. The window for
548+ // contention on the counter is rather narrow since the general case
549+ // should be compiled down to three instructions between locking and
550+ // unlocking the guard. Since contention on the guard is low, use a
551+ // spinlock that optimizes for the fast path of the guard being
552+ // unlocked.
553+ static GUARD : AtomicBool = AtomicBool :: new ( false ) ;
554+ static mut COUNTER : u64 = 0 ;
555+
556+ // Get exclusive access to the counter.
557+ while GUARD . compare_exchange_weak (
558+ false ,
559+ true ,
560+ Ordering :: Acquire ,
561+ Ordering :: Relaxed
562+ ) . is_err ( ) {
563+ // Give up the rest of our thread quantum if another thread is
564+ // using the counter. This is the slow_er_ path.
565+ yield_now ( ) ;
566+ }
547567
548- unsafe {
549- if THREAD_ID . 0 == 0 {
550- THREAD_ID . 0 = 1 + THREAD_ID_COUNT . fetch_add ( 1 , Ordering :: SeqCst ) ;
568+ // We have exclusive access to the counter, so use it fast and get out.
569+ let id = unsafe {
570+ // If we somehow use up all our bits, panic so that we're not
571+ // covering up subtle bugs of IDs being reused.
572+ if COUNTER == :: u64:: MAX {
573+ panic ! ( "failed to generate unique thread ID: bitspace exhausted" ) ;
551574 }
552- THREAD_ID
553- }
575+
576+ let id = COUNTER ;
577+ COUNTER += 1 ;
578+ id
579+ } ;
580+
581+ // Unlock the guard.
582+ GUARD . store ( false , Ordering :: Release ) ;
583+
584+ ThreadId ( id)
554585 }
555586}
556587
@@ -561,6 +592,7 @@ impl ThreadId {
561592/// The internal representation of a `Thread` handle
562593struct Inner {
563594 name : Option < CString > , // Guaranteed to be UTF-8
595+ id : ThreadId ,
564596 lock : Mutex < bool > , // true when there is a buffered unpark
565597 cvar : Condvar ,
566598}
@@ -581,6 +613,7 @@ impl Thread {
581613 Thread {
582614 inner : Arc :: new ( Inner {
583615 name : cname,
616+ id : ThreadId :: new ( ) ,
584617 lock : Mutex :: new ( false ) ,
585618 cvar : Condvar :: new ( ) ,
586619 } )
@@ -599,6 +632,12 @@ impl Thread {
599632 }
600633 }
601634
635+ /// Gets the thread's unique identifier.
636+ #[ unstable( feature = "thread_id" , issue = "21507" ) ]
637+ pub fn id ( & self ) -> ThreadId {
638+ self . inner . id
639+ }
640+
602641 /// Gets the thread's name.
603642 ///
604643 /// # Examples
@@ -1009,12 +1048,13 @@ mod tests {
10091048
10101049 #[ test]
10111050 fn test_thread_id_equal ( ) {
1012- assert ! ( thread:: ThreadId :: current( ) == thread:: ThreadId :: current( ) ) ;
1051+ assert ! ( thread:: current( ) . id ( ) == thread:: current( ) . id ( ) ) ;
10131052 }
10141053
10151054 #[ test]
10161055 fn test_thread_id_not_equal ( ) {
1017- assert ! ( thread:: ThreadId :: current( ) != thread:: spawn( || thread:: ThreadId :: current( ) ) . join( ) . unwrap( ) ) ;
1056+ let spawned_id = thread:: spawn ( || thread:: current ( ) . id ( ) ) . join ( ) . unwrap ( ) ;
1057+ assert ! ( thread:: current( ) . id( ) != spawned_id) ;
10181058 }
10191059
10201060 // NOTE: the corresponding test for stderr is in run-pass/thread-stderr, due
0 commit comments