mirror of https://git.suyu.dev/suyu/suyu
				
				
				
			common: Add free region manager
* Abstraction for placeholder region tracking in host_memorymerge-requests/60/head
							parent
							
								
									20011dfeb8
								
							
						
					
					
						commit
						29e7d79a86
					
				@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0-or-later
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mutex>
 | 
				
			||||||
 | 
					#include <boost/icl/interval_set.hpp>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Common {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FreeRegionManager {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    explicit FreeRegionManager() = default;
 | 
				
			||||||
 | 
					    ~FreeRegionManager() = default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void SetAddressSpace(void* start, size_t size) {
 | 
				
			||||||
 | 
					        this->FreeBlock(start, size);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::pair<void*, size_t> FreeBlock(void* block_ptr, size_t size) {
 | 
				
			||||||
 | 
					        std::scoped_lock lk(m_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Check to see if we are adjacent to any regions.
 | 
				
			||||||
 | 
					        auto start_address = reinterpret_cast<uintptr_t>(block_ptr);
 | 
				
			||||||
 | 
					        auto end_address = start_address + size;
 | 
				
			||||||
 | 
					        auto it = m_free_regions.find({start_address - 1, end_address + 1});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // If we are, join with them, ensuring we stay in bounds.
 | 
				
			||||||
 | 
					        if (it != m_free_regions.end()) {
 | 
				
			||||||
 | 
					            start_address = std::min(start_address, it->lower());
 | 
				
			||||||
 | 
					            end_address = std::max(end_address, it->upper());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Free the relevant region.
 | 
				
			||||||
 | 
					        m_free_regions.insert({start_address, end_address});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Return the adjusted pointers.
 | 
				
			||||||
 | 
					        block_ptr = reinterpret_cast<void*>(start_address);
 | 
				
			||||||
 | 
					        size = end_address - start_address;
 | 
				
			||||||
 | 
					        return {block_ptr, size};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void AllocateBlock(void* block_ptr, size_t size) {
 | 
				
			||||||
 | 
					        std::scoped_lock lk(m_mutex);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        auto address = reinterpret_cast<uintptr_t>(block_ptr);
 | 
				
			||||||
 | 
					        m_free_regions.subtract({address, address + size});
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    std::mutex m_mutex;
 | 
				
			||||||
 | 
					    boost::icl::interval_set<uintptr_t> m_free_regions;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace Common
 | 
				
			||||||
					Loading…
					
					
				
		Reference in New Issue