@@ -181,7 +181,7 @@ def find_free(self, size: int, allocation_align=True) -> Optional[int]:
181181 return info .base
182182 return None
183183
184- def reserve (self , start : int , size : int , protect : MemoryProtect , memory_type : MemoryType = MemoryType .MEM_PRIVATE , info : Any = None ) -> None :
184+ def reserve (self , start : int , size : int , protect : MemoryProtect , memory_type : MemoryType = MemoryType .MEM_PRIVATE , info : Any = None ) -> MemoryRegion :
185185 assert isinstance (protect , MemoryProtect )
186186 assert isinstance (memory_type , MemoryType )
187187 assert size > 0 and self .align_page (size ) == size
@@ -203,6 +203,7 @@ def check_overlaps(idx):
203203 check_overlaps (index - 1 )
204204 check_overlaps (index )
205205 self ._regions .insert (index , region )
206+ return region
206207
207208 def _decommit_region (self , parent_region : MemoryRegion , decommit_region : MemoryRegion ):
208209 assert decommit_region in parent_region
@@ -227,19 +228,42 @@ def _decommit_region(self, parent_region: MemoryRegion, decommit_region: MemoryR
227228 del self ._committed [release_start + i * PAGE_SIZE ]
228229 parent_region .commit_count -= 1
229230
230- def release (self , start : int ) -> None :
231+ def release (self , start : int , size : int = 0 ) -> None :
231232 assert self .align_allocation (start ) == start
233+ assert self .align_allocation (size ) == size
232234
233- parent_region = self .find_region (start )
234- if parent_region is None :
235+ parent = self .find_region (start )
236+ if parent is None :
235237 raise KeyError (f"Could not find parent for { hex (start )} " )
236- if parent_region .start != start :
237- raise KeyError (f"You can only release the whole parent region" )
238238
239- self ._decommit_region (parent_region , parent_region )
239+ if size == 0 :
240+ size = parent .size
241+ if start + size > parent .start + parent .size :
242+ raise KeyError (f"You can only release part of the parent region" )
243+
244+ decommit = MemoryRegion (start , size )
245+ self ._decommit_region (parent , decommit )
246+ self ._regions .remove (parent )
247+
248+ before = MemoryRegion (parent .start , decommit .start - parent .start )
249+ after = MemoryRegion (decommit .end , parent .end - decommit .end )
250+
251+ if parent .size == decommit .size :
252+ # Make sure the whole region was freed
253+ assert parent .commit_count == 0
254+
255+ if before .size > 0 :
256+ before = self .reserve (before .start , before .size , parent .protect , parent .type , parent .info )
257+ for page in before .pages ():
258+ if page in self ._committed :
259+ before .commit_count += 1
260+ if after .size > 0 :
261+ after = self .reserve (after .start , after .size , parent .protect , parent .type , parent .info )
262+ for page in after .pages ():
263+ if page in self ._committed :
264+ after .commit_count += 1
240265
241- assert parent_region .commit_count == 0
242- self ._regions .remove (parent_region )
266+ assert before .commit_count + after .commit_count == parent .commit_count
243267
244268 def commit (self , start : int , size : int , protect : MemoryProtect = MemoryProtect .UNDEFINED ) -> None :
245269 assert isinstance (protect , MemoryProtect )
0 commit comments