Skip to content

Commit 6fdc4d3

Browse files
authored
bpo-40521: Convert deque freelist from global vars to instance vars (GH-25906)
1 parent 355bae8 commit 6fdc4d3

File tree

2 files changed

+34
-28
lines changed

2 files changed

+34
-28
lines changed

Lib/test/test_deque.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -740,8 +740,9 @@ class C(object):
740740

741741
@support.cpython_only
742742
def test_sizeof(self):
743+
MAXFREEBLOCKS = 16
743744
BLOCKLEN = 64
744-
basesize = support.calcvobjsize('2P4nP')
745+
basesize = support.calcvobjsize('2P5n%dPP' % MAXFREEBLOCKS)
745746
blocksize = struct.calcsize('P%dPP' % BLOCKLEN)
746747
self.assertEqual(object.__sizeof__(deque()), basesize)
747748
check = self.check_sizeof

Modules/_collectionsmodule.c

Lines changed: 32 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ static PyTypeObject tuplegetter_type;
3030

3131
#define BLOCKLEN 64
3232
#define CENTER ((BLOCKLEN - 1) / 2)
33+
#define MAXFREEBLOCKS 16
3334

3435
/* Data for deque objects is stored in a doubly-linked list of fixed
3536
* length blocks. This assures that appends or pops never move any
@@ -92,6 +93,8 @@ typedef struct {
9293
Py_ssize_t rightindex; /* 0 <= rightindex < BLOCKLEN */
9394
size_t state; /* incremented whenever the indices move */
9495
Py_ssize_t maxlen; /* maxlen is -1 for unbounded deques */
96+
Py_ssize_t numfreeblocks;
97+
block *freeblocks[MAXFREEBLOCKS];
9598
PyObject *weakreflist;
9699
} dequeobject;
97100

@@ -123,16 +126,12 @@ static PyTypeObject deque_type;
123126
added at about the same rate as old blocks are being freed.
124127
*/
125128

126-
#define MAXFREEBLOCKS 16
127-
static Py_ssize_t numfreeblocks = 0;
128-
static block *freeblocks[MAXFREEBLOCKS];
129-
130-
static block *
131-
newblock(void) {
129+
static inline block *
130+
newblock(dequeobject *deque) {
132131
block *b;
133-
if (numfreeblocks) {
134-
numfreeblocks--;
135-
return freeblocks[numfreeblocks];
132+
if (deque->numfreeblocks) {
133+
deque->numfreeblocks--;
134+
return deque->freeblocks[deque->numfreeblocks];
136135
}
137136
b = PyMem_Malloc(sizeof(block));
138137
if (b != NULL) {
@@ -142,12 +141,12 @@ newblock(void) {
142141
return NULL;
143142
}
144143

145-
static void
146-
freeblock(block *b)
144+
static inline void
145+
freeblock(dequeobject *deque, block *b)
147146
{
148-
if (numfreeblocks < MAXFREEBLOCKS) {
149-
freeblocks[numfreeblocks] = b;
150-
numfreeblocks++;
147+
if (deque->numfreeblocks < MAXFREEBLOCKS) {
148+
deque->freeblocks[deque->numfreeblocks] = b;
149+
deque->numfreeblocks++;
151150
} else {
152151
PyMem_Free(b);
153152
}
@@ -164,7 +163,7 @@ deque_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
164163
if (deque == NULL)
165164
return NULL;
166165

167-
b = newblock();
166+
b = newblock(deque);
168167
if (b == NULL) {
169168
Py_DECREF(deque);
170169
return NULL;
@@ -180,6 +179,7 @@ deque_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
180179
deque->rightindex = CENTER;
181180
deque->state = 0;
182181
deque->maxlen = -1;
182+
deque->numfreeblocks = 0;
183183
deque->weakreflist = NULL;
184184

185185
return (PyObject *)deque;
@@ -204,7 +204,7 @@ deque_pop(dequeobject *deque, PyObject *unused)
204204
if (Py_SIZE(deque)) {
205205
prevblock = deque->rightblock->leftlink;
206206
assert(deque->leftblock != deque->rightblock);
207-
freeblock(deque->rightblock);
207+
freeblock(deque, deque->rightblock);
208208
CHECK_NOT_END(prevblock);
209209
MARK_END(prevblock->rightlink);
210210
deque->rightblock = prevblock;
@@ -242,7 +242,7 @@ deque_popleft(dequeobject *deque, PyObject *unused)
242242
if (Py_SIZE(deque)) {
243243
assert(deque->leftblock != deque->rightblock);
244244
prevblock = deque->leftblock->rightlink;
245-
freeblock(deque->leftblock);
245+
freeblock(deque, deque->leftblock);
246246
CHECK_NOT_END(prevblock);
247247
MARK_END(prevblock->leftlink);
248248
deque->leftblock = prevblock;
@@ -278,7 +278,7 @@ static inline int
278278
deque_append_internal(dequeobject *deque, PyObject *item, Py_ssize_t maxlen)
279279
{
280280
if (deque->rightindex == BLOCKLEN - 1) {
281-
block *b = newblock();
281+
block *b = newblock(deque);
282282
if (b == NULL)
283283
return -1;
284284
b->leftlink = deque->rightblock;
@@ -315,7 +315,7 @@ static inline int
315315
deque_appendleft_internal(dequeobject *deque, PyObject *item, Py_ssize_t maxlen)
316316
{
317317
if (deque->leftindex == 0) {
318-
block *b = newblock();
318+
block *b = newblock(deque);
319319
if (b == NULL)
320320
return -1;
321321
b->rightlink = deque->leftblock;
@@ -584,7 +584,7 @@ deque_clear(dequeobject *deque)
584584
adversary could cause it to never terminate).
585585
*/
586586

587-
b = newblock();
587+
b = newblock(deque);
588588
if (b == NULL) {
589589
PyErr_Clear();
590590
goto alternate_method;
@@ -623,13 +623,13 @@ deque_clear(dequeobject *deque)
623623
itemptr = leftblock->data;
624624
limit = itemptr + m;
625625
n -= m;
626-
freeblock(prevblock);
626+
freeblock(deque, prevblock);
627627
}
628628
item = *(itemptr++);
629629
Py_DECREF(item);
630630
}
631631
CHECK_END(leftblock->rightlink);
632-
freeblock(leftblock);
632+
freeblock(deque, leftblock);
633633
return 0;
634634

635635
alternate_method:
@@ -679,7 +679,7 @@ deque_inplace_repeat(dequeobject *deque, Py_ssize_t n)
679679
deque->state++;
680680
for (i = 0 ; i < n-1 ; ) {
681681
if (deque->rightindex == BLOCKLEN - 1) {
682-
block *b = newblock();
682+
block *b = newblock(deque);
683683
if (b == NULL) {
684684
Py_SET_SIZE(deque, Py_SIZE(deque) + i);
685685
return NULL;
@@ -797,7 +797,7 @@ _deque_rotate(dequeobject *deque, Py_ssize_t n)
797797
while (n > 0) {
798798
if (leftindex == 0) {
799799
if (b == NULL) {
800-
b = newblock();
800+
b = newblock(deque);
801801
if (b == NULL)
802802
goto done;
803803
}
@@ -841,7 +841,7 @@ _deque_rotate(dequeobject *deque, Py_ssize_t n)
841841
while (n < 0) {
842842
if (rightindex == BLOCKLEN - 1) {
843843
if (b == NULL) {
844-
b = newblock();
844+
b = newblock(deque);
845845
if (b == NULL)
846846
goto done;
847847
}
@@ -885,7 +885,7 @@ _deque_rotate(dequeobject *deque, Py_ssize_t n)
885885
rv = 0;
886886
done:
887887
if (b != NULL)
888-
freeblock(b);
888+
freeblock(deque, b);
889889
deque->leftblock = leftblock;
890890
deque->rightblock = rightblock;
891891
deque->leftindex = leftindex;
@@ -1306,16 +1306,21 @@ deque_ass_item(dequeobject *deque, Py_ssize_t i, PyObject *v)
13061306
static void
13071307
deque_dealloc(dequeobject *deque)
13081308
{
1309+
Py_ssize_t i;
1310+
13091311
PyObject_GC_UnTrack(deque);
13101312
if (deque->weakreflist != NULL)
13111313
PyObject_ClearWeakRefs((PyObject *) deque);
13121314
if (deque->leftblock != NULL) {
13131315
deque_clear(deque);
13141316
assert(deque->leftblock != NULL);
1315-
freeblock(deque->leftblock);
1317+
freeblock(deque, deque->leftblock);
13161318
}
13171319
deque->leftblock = NULL;
13181320
deque->rightblock = NULL;
1321+
for (i=0 ; i < deque->numfreeblocks ; i++) {
1322+
PyMem_Free(deque->freeblocks[i]);
1323+
}
13191324
Py_TYPE(deque)->tp_free(deque);
13201325
}
13211326

0 commit comments

Comments
 (0)