@@ -165,7 +165,7 @@ use panic;
165
165
use panicking;
166
166
use str;
167
167
use sync:: { Mutex , Condvar , Arc } ;
168
- use sync:: atomic:: { AtomicUsize , Ordering , ATOMIC_USIZE_INIT } ;
168
+ use sync:: atomic:: { AtomicBool , Ordering } ;
169
169
use sys:: thread as imp;
170
170
use sys_common:: thread_info;
171
171
use sys_common:: util;
@@ -536,21 +536,52 @@ pub fn park_timeout(dur: Duration) {
536
536
/// designated identifier.
537
537
#[ unstable( feature = "thread_id" , issue = "21507" ) ]
538
538
#[ derive( Eq , PartialEq , Copy , Clone ) ]
539
- pub struct ThreadId ( usize ) ;
539
+ pub struct ThreadId ( u64 ) ;
540
540
541
541
impl 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
+ }
547
567
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" ) ;
551
574
}
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)
554
585
}
555
586
}
556
587
@@ -561,6 +592,7 @@ impl ThreadId {
561
592
/// The internal representation of a `Thread` handle
562
593
struct Inner {
563
594
name : Option < CString > , // Guaranteed to be UTF-8
595
+ id : ThreadId ,
564
596
lock : Mutex < bool > , // true when there is a buffered unpark
565
597
cvar : Condvar ,
566
598
}
@@ -581,6 +613,7 @@ impl Thread {
581
613
Thread {
582
614
inner : Arc :: new ( Inner {
583
615
name : cname,
616
+ id : ThreadId :: new ( ) ,
584
617
lock : Mutex :: new ( false ) ,
585
618
cvar : Condvar :: new ( ) ,
586
619
} )
@@ -599,6 +632,12 @@ impl Thread {
599
632
}
600
633
}
601
634
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
+
602
641
/// Gets the thread's name.
603
642
///
604
643
/// # Examples
@@ -1009,12 +1048,13 @@ mod tests {
1009
1048
1010
1049
#[ test]
1011
1050
fn test_thread_id_equal ( ) {
1012
- assert ! ( thread:: ThreadId :: current( ) == thread:: ThreadId :: current( ) ) ;
1051
+ assert ! ( thread:: current( ) . id ( ) == thread:: current( ) . id ( ) ) ;
1013
1052
}
1014
1053
1015
1054
#[ test]
1016
1055
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) ;
1018
1058
}
1019
1059
1020
1060
// NOTE: the corresponding test for stderr is in run-pass/thread-stderr, due
0 commit comments