From 01660896e8ae6130c174f50484628fc37efc8bf2 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 4 May 2021 15:03:44 -0700 Subject: [PATCH 1/5] bpo-40521: Convert deque freelist from global variables to instance variables --- Modules/_collectionsmodule.c | 59 +++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 9c8701af904ab9..7a3de879057440 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -30,6 +30,7 @@ static PyTypeObject tuplegetter_type; #define BLOCKLEN 64 #define CENTER ((BLOCKLEN - 1) / 2) +#define MAXFREEBLOCKS 16 /* Data for deque objects is stored in a doubly-linked list of fixed * length blocks. This assures that appends or pops never move any @@ -92,6 +93,8 @@ typedef struct { Py_ssize_t rightindex; /* 0 <= rightindex < BLOCKLEN */ size_t state; /* incremented whenever the indices move */ Py_ssize_t maxlen; /* maxlen is -1 for unbounded deques */ + Py_ssize_t numfreeblocks; + block *freeblocks[MAXFREEBLOCKS]; PyObject *weakreflist; } dequeobject; @@ -123,16 +126,12 @@ static PyTypeObject deque_type; added at about the same rate as old blocks are being freed. */ -#define MAXFREEBLOCKS 16 -static Py_ssize_t numfreeblocks = 0; -static block *freeblocks[MAXFREEBLOCKS]; - -static block * -newblock(void) { +static inline block * +newblock(dequeobject *deque) { block *b; - if (numfreeblocks) { - numfreeblocks--; - return freeblocks[numfreeblocks]; + if (deque->numfreeblocks) { + deque->numfreeblocks--; + return deque->freeblocks[deque->numfreeblocks]; } b = PyMem_Malloc(sizeof(block)); if (b != NULL) { @@ -142,12 +141,12 @@ newblock(void) { return NULL; } -static void -freeblock(block *b) +static inline void +freeblock(dequeobject *deque, block *b) { - if (numfreeblocks < MAXFREEBLOCKS) { - freeblocks[numfreeblocks] = b; - numfreeblocks++; + if (deque->numfreeblocks < MAXFREEBLOCKS) { + deque->freeblocks[deque->numfreeblocks] = b; + deque->numfreeblocks++; } else { PyMem_Free(b); } @@ -164,7 +163,7 @@ deque_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (deque == NULL) return NULL; - b = newblock(); + b = newblock(deque); if (b == NULL) { Py_DECREF(deque); return NULL; @@ -180,6 +179,7 @@ deque_new(PyTypeObject *type, PyObject *args, PyObject *kwds) deque->rightindex = CENTER; deque->state = 0; deque->maxlen = -1; + deque->numfreeblocks = 0; deque->weakreflist = NULL; return (PyObject *)deque; @@ -204,7 +204,7 @@ deque_pop(dequeobject *deque, PyObject *unused) if (Py_SIZE(deque)) { prevblock = deque->rightblock->leftlink; assert(deque->leftblock != deque->rightblock); - freeblock(deque->rightblock); + freeblock(deque, deque->rightblock); CHECK_NOT_END(prevblock); MARK_END(prevblock->rightlink); deque->rightblock = prevblock; @@ -242,7 +242,7 @@ deque_popleft(dequeobject *deque, PyObject *unused) if (Py_SIZE(deque)) { assert(deque->leftblock != deque->rightblock); prevblock = deque->leftblock->rightlink; - freeblock(deque->leftblock); + freeblock(deque, deque->leftblock); CHECK_NOT_END(prevblock); MARK_END(prevblock->leftlink); deque->leftblock = prevblock; @@ -278,7 +278,7 @@ static inline int deque_append_internal(dequeobject *deque, PyObject *item, Py_ssize_t maxlen) { if (deque->rightindex == BLOCKLEN - 1) { - block *b = newblock(); + block *b = newblock(deque); if (b == NULL) return -1; b->leftlink = deque->rightblock; @@ -315,7 +315,7 @@ static inline int deque_appendleft_internal(dequeobject *deque, PyObject *item, Py_ssize_t maxlen) { if (deque->leftindex == 0) { - block *b = newblock(); + block *b = newblock(deque); if (b == NULL) return -1; b->rightlink = deque->leftblock; @@ -584,7 +584,7 @@ deque_clear(dequeobject *deque) adversary could cause it to never terminate). */ - b = newblock(); + b = newblock(deque); if (b == NULL) { PyErr_Clear(); goto alternate_method; @@ -623,13 +623,13 @@ deque_clear(dequeobject *deque) itemptr = leftblock->data; limit = itemptr + m; n -= m; - freeblock(prevblock); + freeblock(deque, prevblock); } item = *(itemptr++); Py_DECREF(item); } CHECK_END(leftblock->rightlink); - freeblock(leftblock); + freeblock(deque, leftblock); return 0; alternate_method: @@ -679,7 +679,7 @@ deque_inplace_repeat(dequeobject *deque, Py_ssize_t n) deque->state++; for (i = 0 ; i < n-1 ; ) { if (deque->rightindex == BLOCKLEN - 1) { - block *b = newblock(); + block *b = newblock(deque); if (b == NULL) { Py_SET_SIZE(deque, Py_SIZE(deque) + i); return NULL; @@ -797,7 +797,7 @@ _deque_rotate(dequeobject *deque, Py_ssize_t n) while (n > 0) { if (leftindex == 0) { if (b == NULL) { - b = newblock(); + b = newblock(deque); if (b == NULL) goto done; } @@ -841,7 +841,7 @@ _deque_rotate(dequeobject *deque, Py_ssize_t n) while (n < 0) { if (rightindex == BLOCKLEN - 1) { if (b == NULL) { - b = newblock(); + b = newblock(deque); if (b == NULL) goto done; } @@ -885,7 +885,7 @@ _deque_rotate(dequeobject *deque, Py_ssize_t n) rv = 0; done: if (b != NULL) - freeblock(b); + freeblock(deque, b); deque->leftblock = leftblock; deque->rightblock = rightblock; deque->leftindex = leftindex; @@ -1306,16 +1306,21 @@ deque_ass_item(dequeobject *deque, Py_ssize_t i, PyObject *v) static void deque_dealloc(dequeobject *deque) { + Py_ssize_t i; + PyObject_GC_UnTrack(deque); if (deque->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) deque); if (deque->leftblock != NULL) { deque_clear(deque); assert(deque->leftblock != NULL); - freeblock(deque->leftblock); + freeblock(deque, deque->leftblock); } deque->leftblock = NULL; deque->rightblock = NULL; + for (i=0 ; i < deque->numfreeblocks ; i++) { + free(deque->freeblocks[i]); + } Py_TYPE(deque)->tp_free(deque); } From 79f20e359ee4c3d127814d49222da34f88749672 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 4 May 2021 15:37:26 -0700 Subject: [PATCH 2/5] Blocks in the freelist have already been freed --- Modules/_collectionsmodule.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 7a3de879057440..2e9b3d5d690a4e 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1306,8 +1306,6 @@ deque_ass_item(dequeobject *deque, Py_ssize_t i, PyObject *v) static void deque_dealloc(dequeobject *deque) { - Py_ssize_t i; - PyObject_GC_UnTrack(deque); if (deque->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) deque); @@ -1318,9 +1316,6 @@ deque_dealloc(dequeobject *deque) } deque->leftblock = NULL; deque->rightblock = NULL; - for (i=0 ; i < deque->numfreeblocks ; i++) { - free(deque->freeblocks[i]); - } Py_TYPE(deque)->tp_free(deque); } From d5b6e8ab84107169b56d83b6f7377f1a94e5f516 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 4 May 2021 15:44:53 -0700 Subject: [PATCH 3/5] Revert "Blocks in the freelist have already been freed" This reverts commit 79f20e359ee4c3d127814d49222da34f88749672. --- Modules/_collectionsmodule.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 2e9b3d5d690a4e..7a3de879057440 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1306,6 +1306,8 @@ deque_ass_item(dequeobject *deque, Py_ssize_t i, PyObject *v) static void deque_dealloc(dequeobject *deque) { + Py_ssize_t i; + PyObject_GC_UnTrack(deque); if (deque->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) deque); @@ -1316,6 +1318,9 @@ deque_dealloc(dequeobject *deque) } deque->leftblock = NULL; deque->rightblock = NULL; + for (i=0 ; i < deque->numfreeblocks ; i++) { + free(deque->freeblocks[i]); + } Py_TYPE(deque)->tp_free(deque); } From 89636a1614e993a526010980ec0e8257595c6031 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 4 May 2021 15:46:44 -0700 Subject: [PATCH 4/5] Use PyMem_Free() instead of free() --- Modules/_collectionsmodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c index 7a3de879057440..79c6b5752afa2e 100644 --- a/Modules/_collectionsmodule.c +++ b/Modules/_collectionsmodule.c @@ -1319,7 +1319,7 @@ deque_dealloc(dequeobject *deque) deque->leftblock = NULL; deque->rightblock = NULL; for (i=0 ; i < deque->numfreeblocks ; i++) { - free(deque->freeblocks[i]); + PyMem_Free(deque->freeblocks[i]); } Py_TYPE(deque)->tp_free(deque); } From 584cbcce4660fc5981f6c75f2510cb190a3c7b2a Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 4 May 2021 16:16:51 -0700 Subject: [PATCH 5/5] Adjust sizeof() test for the new fields --- Lib/test/test_deque.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py index 93cc6ca4f44ecb..f1a79373decda5 100644 --- a/Lib/test/test_deque.py +++ b/Lib/test/test_deque.py @@ -740,8 +740,9 @@ class C(object): @support.cpython_only def test_sizeof(self): + MAXFREEBLOCKS = 16 BLOCKLEN = 64 - basesize = support.calcvobjsize('2P4nP') + basesize = support.calcvobjsize('2P5n%dPP' % MAXFREEBLOCKS) blocksize = struct.calcsize('P%dPP' % BLOCKLEN) self.assertEqual(object.__sizeof__(deque()), basesize) check = self.check_sizeof pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy