(self, block)
| 266 | self._remove_allocated_block(block) |
| 267 | |
| 268 | def free(self, block): |
| 269 | # 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 | if os.getpid() != self._lastpid: |
| 279 | raise ValueError( |
| 280 | "My pid ({0:n}) is not last pid {1:n}".format( |
| 281 | 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() |
| 295 | |
| 296 | def malloc(self, size): |
| 297 | # return a block of right size (possibly rounded up) |
nothing calls this directly
no test coverage detected