@@ -142,9 +142,6 @@ def __init__(self, size=mmap.PAGESIZE):
142
142
self ._allocated_blocks = defaultdict (set )
143
143
self ._arenas = []
144
144
145
- # List of pending blocks to free - see comment in free() below
146
- self ._pending_free_blocks = []
147
-
148
145
# Statistics
149
146
self ._n_mallocs = 0
150
147
self ._n_frees = 0
@@ -255,43 +252,16 @@ def _remove_allocated_block(self, block):
255
252
# Arena is entirely free, discard it from this process
256
253
self ._discard_arena (arena )
257
254
258
- def _free_pending_blocks (self ):
259
- # Free all the blocks in the pending list - called with the lock held.
260
- while True :
261
- try :
262
- block = self ._pending_free_blocks .pop ()
263
- except IndexError :
264
- break
265
- self ._add_free_block (block )
266
- self ._remove_allocated_block (block )
267
-
268
255
def free (self , block ):
269
256
# free a block returned by malloc()
270
- # Since free() can be called asynchronously by the GC, it could happen
271
- # that it's called while self._lock is held: in that case,
272
- # self._lock.acquire() would deadlock (issue #12352). To avoid that, a
273
- # trylock is used instead, and if the lock can't be acquired
274
- # immediately, the block is added to a list of blocks to be freed
275
- # synchronously sometimes later from malloc() or free(), by calling
276
- # _free_pending_blocks() (appending and retrieving from a list is not
277
- # strictly thread-safe but under CPython it's atomic thanks to the GIL).
278
257
if os .getpid () != self ._lastpid :
279
258
raise ValueError (
280
259
"My pid ({0:n}) is not last pid {1:n}" .format (
281
260
os .getpid (),self ._lastpid ))
282
- if not self ._lock .acquire (False ):
283
- # can't acquire the lock right now, add the block to the list of
284
- # pending blocks to free
285
- self ._pending_free_blocks .append (block )
286
- else :
287
- # we hold the lock
288
- try :
289
- self ._n_frees += 1
290
- self ._free_pending_blocks ()
291
- self ._add_free_block (block )
292
- self ._remove_allocated_block (block )
293
- finally :
294
- self ._lock .release ()
261
+ with self ._lock :
262
+ self ._n_frees += 1
263
+ self ._add_free_block (block )
264
+ self ._remove_allocated_block (block )
295
265
296
266
def malloc (self , size ):
297
267
# return a block of right size (possibly rounded up)
@@ -303,8 +273,6 @@ def malloc(self, size):
303
273
self .__init__ () # reinitialize after fork
304
274
with self ._lock :
305
275
self ._n_mallocs += 1
306
- # allow pending blocks to be marked available
307
- self ._free_pending_blocks ()
308
276
size = self ._roundup (max (size , 1 ), self ._alignment )
309
277
(arena , start , stop ) = self ._malloc (size )
310
278
real_stop = start + size
@@ -330,7 +298,8 @@ def __init__(self, size):
330
298
raise OverflowError ("Size {0:n} too large" .format (size ))
331
299
block = BufferWrapper ._heap .malloc (size )
332
300
self ._state = (block , size )
333
- util .Finalize (self , BufferWrapper ._heap .free , args = (block ,))
301
+ util .Finalize (self , BufferWrapper ._heap .free , args = (block ,),
302
+ reentrant = False )
334
303
335
304
def create_memoryview (self ):
336
305
(arena , start , stop ), size = self ._state
0 commit comments