| 989 | |
| 990 | template <typename F> |
| 991 | inline auto with_instance_map(const void *ptr, const F &cb) |
| 992 | -> decltype(cb(std::declval<instance_map &>())) { |
| 993 | auto &internals = get_internals(); |
| 994 | |
| 995 | #ifdef Py_GIL_DISABLED |
| 996 | // Hash address to compute shard, but ignore low bits. We'd like allocations |
| 997 | // from the same thread/core to map to the same shard and allocations from |
| 998 | // other threads/cores to map to other shards. Using the high bits is a good |
| 999 | // heuristic because memory allocators often have a per-thread |
| 1000 | // arena/superblock/segment from which smaller allocations are served. |
| 1001 | auto addr = reinterpret_cast<std::uintptr_t>(ptr); |
| 1002 | auto hash = mix64(static_cast<std::uint64_t>(addr >> 20)); |
| 1003 | auto idx = static_cast<size_t>(hash & internals.instance_shards_mask); |
| 1004 | |
| 1005 | auto &shard = internals.instance_shards[idx]; |
| 1006 | std::unique_lock<pymutex> lock(shard.mutex); |
| 1007 | return cb(shard.registered_instances); |
| 1008 | #else |
| 1009 | (void) ptr; |
| 1010 | return cb(internals.registered_instances); |
| 1011 | #endif |
| 1012 | } |
| 1013 | |
| 1014 | // Returns the number of registered instances for testing purposes. The result may not be |
| 1015 | // consistent if other threads are registering or unregistering instances concurrently. |
no test coverage detected