| 928 | #[pyclass(with(GetAttr, SetAttr), flags(BASETYPE))] |
| 929 | impl Local { |
| 930 | fn l_dict(&self, vm: &VirtualMachine) -> PyDictRef { |
| 931 | let thread_id = std::thread::current().id(); |
| 932 | |
| 933 | // Fast path: check if dict exists under lock |
| 934 | if let Some(dict) = self.inner.data.lock().get(&thread_id).cloned() { |
| 935 | return dict; |
| 936 | } |
| 937 | |
| 938 | // Slow path: allocate dict outside lock to reduce lock hold time |
| 939 | let new_dict = vm.ctx.new_dict(); |
| 940 | |
| 941 | // Insert with double-check to handle races |
| 942 | let mut data = self.inner.data.lock(); |
| 943 | use std::collections::hash_map::Entry; |
| 944 | let (dict, need_guard) = match data.entry(thread_id) { |
| 945 | Entry::Occupied(e) => (e.get().clone(), false), |
| 946 | Entry::Vacant(e) => { |
| 947 | e.insert(new_dict.clone()); |
| 948 | (new_dict, true) |
| 949 | } |
| 950 | }; |
| 951 | drop(data); // Release lock before TLS access |
| 952 | |
| 953 | // Register cleanup guard only if we inserted a new entry |
| 954 | if need_guard { |
| 955 | let guard = LocalGuard { |
| 956 | local: Arc::downgrade(&self.inner), |
| 957 | thread_id, |
| 958 | }; |
| 959 | LOCAL_GUARDS.with(|guards| { |
| 960 | guards.borrow_mut().push(guard); |
| 961 | }); |
| 962 | } |
| 963 | |
| 964 | dict |
| 965 | } |
| 966 | |
| 967 | #[pyslot] |
| 968 | fn slot_new(cls: PyTypeRef, _args: FuncArgs, vm: &VirtualMachine) -> PyResult { |