// Copyright 2017 Amanieu d'Antras // // Licensed under the Apache License, Version 2.0, or the MIT license , at your option. This file may not be // copied, modified, or distributed except according to those terms. use std::collections::BinaryHeap; use std::sync::Mutex; use std::usize; // Thread ID manager which allocates thread IDs. It attempts to aggressively // reuse thread IDs where possible to avoid cases where a ThreadLocal grows // indefinitely when it is used by many short-lived threads. struct ThreadIdManager { limit: usize, free_list: BinaryHeap, } impl ThreadIdManager { fn new() -> ThreadIdManager { ThreadIdManager { limit: usize::MAX, free_list: BinaryHeap::new(), } } fn alloc(&mut self) -> usize { if let Some(id) = self.free_list.pop() { id } else { let id = self.limit; self.limit = self.limit.checked_sub(1).expect("Ran out of thread IDs"); id } } fn free(&mut self, id: usize) { self.free_list.push(id); } } lazy_static! { static ref THREAD_ID_MANAGER: Mutex = Mutex::new(ThreadIdManager::new()); } // Non-zero integer which is unique to the current thread while it is running. // A thread ID may be reused after a thread exits. struct ThreadId(usize); impl ThreadId { fn new() -> ThreadId { ThreadId(THREAD_ID_MANAGER.lock().unwrap().alloc()) } } impl Drop for ThreadId { fn drop(&mut self) { THREAD_ID_MANAGER.lock().unwrap().free(self.0); } } thread_local!(static THREAD_ID: ThreadId = ThreadId::new()); /// Returns a non-zero ID for the current thread pub fn get() -> usize { THREAD_ID.with(|x| x.0) }