summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <rhettinger@users.noreply.github.com>2021-05-05 00:08:31 (GMT)
committerGitHub <noreply@github.com>2021-05-05 00:08:31 (GMT)
commit6fdc4d37f3fdbc1bd51f841be6e5e4708a3b8798 (patch)
tree47852ade23869b887fab4b48be3e18d3ced5a753
parent355bae88822bee4de6092b63d69c5a5dad393a16 (diff)
downloadcpython-6fdc4d37f3fdbc1bd51f841be6e5e4708a3b8798.zip
cpython-6fdc4d37f3fdbc1bd51f841be6e5e4708a3b8798.tar.gz
cpython-6fdc4d37f3fdbc1bd51f841be6e5e4708a3b8798.tar.bz2
bpo-40521: Convert deque freelist from global vars to instance vars (GH-25906)
-rw-r--r--Lib/test/test_deque.py3
-rw-r--r--Modules/_collectionsmodule.c59
2 files changed, 34 insertions, 28 deletions
diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py
index 93cc6ca..f1a7937 100644
--- a/Lib/test/test_deque.py
+++ b/Lib/test/test_deque.py
@@ -740,8 +740,9 @@ class TestBasic(unittest.TestCase):
@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
diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c
index 9c8701a..79c6b57 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++) {
+ PyMem_Free(deque->freeblocks[i]);
+ }
Py_TYPE(deque)->tp_free(deque);
}