4
4
#include "pycore_long.h" // _PyLong_GetZero()
5
5
#include "pycore_moduleobject.h" // _PyModule_GetState()
6
6
#include "pycore_object.h" // _PyObject_GC_TRACK
7
+ #include "pycore_pyatomic_ft_wrappers.h"
7
8
#include "pycore_pystate.h" // _PyThreadState_GET()
8
9
#include "pycore_tuple.h" // _PyTuple_ITEMS()
9
10
@@ -40,7 +41,6 @@ get_functools_state(PyObject *module)
40
41
return (_functools_state * )state ;
41
42
}
42
43
43
-
44
44
/* partial object **********************************************************/
45
45
46
46
@@ -1016,7 +1016,7 @@ _functools_reduce_impl(PyObject *module, PyObject *func, PyObject *seq,
1016
1016
1017
1017
if (result == NULL )
1018
1018
PyErr_SetString (PyExc_TypeError ,
1019
- "reduce() of empty iterable with no initial value" );
1019
+ "reduce() of empty iterable with no initial value" );
1020
1020
1021
1021
Py_DECREF (it );
1022
1022
return result ;
@@ -1173,7 +1173,7 @@ uncached_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwd
1173
1173
{
1174
1174
PyObject * result ;
1175
1175
1176
- self -> misses ++ ;
1176
+ FT_ATOMIC_ADD_SSIZE ( self -> misses , 1 ) ;
1177
1177
result = PyObject_Call (self -> func , args , kwds );
1178
1178
if (!result )
1179
1179
return NULL ;
@@ -1193,18 +1193,17 @@ infinite_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwd
1193
1193
Py_DECREF (key );
1194
1194
return NULL ;
1195
1195
}
1196
- result = _PyDict_GetItem_KnownHash (self -> cache , key , hash );
1197
- if (result ) {
1198
- Py_INCREF (result );
1199
- self -> hits ++ ;
1196
+ int res = _PyDict_GetItemRef_KnownHash ((PyDictObject * )self -> cache , key , hash , & result );
1197
+ if (res > 0 ) {
1198
+ FT_ATOMIC_ADD_SSIZE (self -> hits , 1 );
1200
1199
Py_DECREF (key );
1201
1200
return result ;
1202
1201
}
1203
- if (PyErr_Occurred () ) {
1202
+ if (res < 0 ) {
1204
1203
Py_DECREF (key );
1205
1204
return NULL ;
1206
1205
}
1207
- self -> misses ++ ;
1206
+ FT_ATOMIC_ADD_SSIZE ( self -> misses , 1 ) ;
1208
1207
result = PyObject_Call (self -> func , args , kwds );
1209
1208
if (!result ) {
1210
1209
Py_DECREF (key );
@@ -1279,50 +1278,65 @@ lru_cache_prepend_link(lru_cache_object *self, lru_list_elem *link)
1279
1278
so that we know the cache is a consistent state.
1280
1279
*/
1281
1280
1282
- static PyObject *
1283
- bounded_lru_cache_wrapper (lru_cache_object * self , PyObject * args , PyObject * kwds )
1281
+ static int
1282
+ bounded_lru_cache_get_lock_held (lru_cache_object * self , PyObject * args , PyObject * kwds ,
1283
+ PyObject * * result , PyObject * * key , Py_hash_t * hash )
1284
1284
{
1285
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (self );
1285
1286
lru_list_elem * link ;
1286
- PyObject * key , * result , * testresult ;
1287
- Py_hash_t hash ;
1288
1287
1289
- key = lru_cache_make_key (self -> kwd_mark , args , kwds , self -> typed );
1290
- if (!key )
1291
- return NULL ;
1292
- hash = PyObject_Hash (key );
1293
- if (hash == -1 ) {
1294
- Py_DECREF (key );
1295
- return NULL ;
1288
+ PyObject * key_ = * key = lru_cache_make_key (self -> kwd_mark , args , kwds , self -> typed );
1289
+ if (!key_ )
1290
+ return -1 ;
1291
+ Py_hash_t hash_ = * hash = PyObject_Hash (key_ );
1292
+ if (hash_ == -1 ) {
1293
+ Py_DECREF (key_ ); /* dead reference left in *key, is not used */
1294
+ return -1 ;
1296
1295
}
1297
- link = (lru_list_elem * )_PyDict_GetItem_KnownHash (self -> cache , key , hash );
1298
- if (link != NULL ) {
1296
+ int res = _PyDict_GetItemRef_KnownHash_LockHeld ((PyDictObject * )self -> cache , key_ , hash_ ,
1297
+ (PyObject * * )& link );
1298
+ if (res > 0 ) {
1299
1299
lru_cache_extract_link (link );
1300
1300
lru_cache_append_link (self , link );
1301
- result = link -> result ;
1302
- self -> hits ++ ;
1303
- Py_INCREF (result );
1304
- Py_DECREF (key );
1305
- return result ;
1301
+ * result = link -> result ;
1302
+ FT_ATOMIC_ADD_SSIZE (self -> hits , 1 );
1303
+ Py_INCREF (link -> result );
1304
+ Py_DECREF (link );
1305
+ Py_DECREF (key_ );
1306
+ return 1 ;
1306
1307
}
1307
- if (PyErr_Occurred () ) {
1308
- Py_DECREF (key );
1309
- return NULL ;
1308
+ if (res < 0 ) {
1309
+ Py_DECREF (key_ );
1310
+ return -1 ;
1310
1311
}
1311
- self -> misses ++ ;
1312
- result = PyObject_Call (self -> func , args , kwds );
1312
+ FT_ATOMIC_ADD_SSIZE (self -> misses , 1 );
1313
+ return 0 ;
1314
+ }
1315
+
1316
+ static PyObject *
1317
+ bounded_lru_cache_update_lock_held (lru_cache_object * self ,
1318
+ PyObject * result , PyObject * key , Py_hash_t hash )
1319
+ {
1320
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED (self );
1321
+ lru_list_elem * link ;
1322
+ PyObject * testresult ;
1323
+ int res ;
1324
+
1313
1325
if (!result ) {
1314
1326
Py_DECREF (key );
1315
1327
return NULL ;
1316
1328
}
1317
- testresult = _PyDict_GetItem_KnownHash (self -> cache , key , hash );
1318
- if (testresult != NULL ) {
1329
+ res = _PyDict_GetItemRef_KnownHash_LockHeld ((PyDictObject * )self -> cache , key , hash ,
1330
+ & testresult );
1331
+ if (res > 0 ) {
1319
1332
/* Getting here means that this same key was added to the cache
1320
1333
during the PyObject_Call(). Since the link update is already
1321
1334
done, we need only return the computed result. */
1335
+ Py_DECREF (testresult );
1322
1336
Py_DECREF (key );
1323
1337
return result ;
1324
1338
}
1325
- if (PyErr_Occurred () ) {
1339
+ if (res < 0 ) {
1326
1340
/* This is an unusual case since this same lookup
1327
1341
did not previously trigger an error during lookup.
1328
1342
Treat it the same as an error in user function
@@ -1386,8 +1400,8 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
1386
1400
The cache dict holds one reference to the link.
1387
1401
We created one other reference when the link was created.
1388
1402
The linked list only has borrowed references. */
1389
- int res = _PyDict_Pop_KnownHash ((PyDictObject * )self -> cache , link -> key ,
1390
- link -> hash , & popresult );
1403
+ res = _PyDict_Pop_KnownHash ((PyDictObject * )self -> cache , link -> key ,
1404
+ link -> hash , & popresult );
1391
1405
if (res < 0 ) {
1392
1406
/* An error arose while trying to remove the oldest key (the one
1393
1407
being evicted) from the cache. We restore the link to its
@@ -1445,6 +1459,37 @@ bounded_lru_cache_wrapper(lru_cache_object *self, PyObject *args, PyObject *kwds
1445
1459
return result ;
1446
1460
}
1447
1461
1462
+ static PyObject *
1463
+ bounded_lru_cache_wrapper (lru_cache_object * self , PyObject * args , PyObject * kwds )
1464
+ {
1465
+ PyObject * key , * result ;
1466
+ Py_hash_t hash ;
1467
+ int res ;
1468
+
1469
+ Py_BEGIN_CRITICAL_SECTION (self );
1470
+ res = bounded_lru_cache_get_lock_held (self , args , kwds , & result , & key , & hash );
1471
+ Py_END_CRITICAL_SECTION ();
1472
+
1473
+ if (res < 0 ) {
1474
+ return NULL ;
1475
+ }
1476
+ if (res > 0 ) {
1477
+ return result ;
1478
+ }
1479
+
1480
+ result = PyObject_Call (self -> func , args , kwds );
1481
+
1482
+ Py_BEGIN_CRITICAL_SECTION (self );
1483
+ /* Note: key will be stolen in the below function, and
1484
+ result may be stolen or sometimes re-returned as a passthrough.
1485
+ Treat both as being stolen.
1486
+ */
1487
+ result = bounded_lru_cache_update_lock_held (self , result , key , hash );
1488
+ Py_END_CRITICAL_SECTION ();
1489
+
1490
+ return result ;
1491
+ }
1492
+
1448
1493
static PyObject *
1449
1494
lru_cache_new (PyTypeObject * type , PyObject * args , PyObject * kw )
1450
1495
{
@@ -1577,9 +1622,7 @@ lru_cache_call(PyObject *op, PyObject *args, PyObject *kwds)
1577
1622
{
1578
1623
lru_cache_object * self = lru_cache_object_CAST (op );
1579
1624
PyObject * result ;
1580
- Py_BEGIN_CRITICAL_SECTION (self );
1581
1625
result = self -> wrapper (self , args , kwds );
1582
- Py_END_CRITICAL_SECTION ();
1583
1626
return result ;
1584
1627
}
1585
1628
@@ -1606,11 +1649,15 @@ _functools__lru_cache_wrapper_cache_info_impl(PyObject *self)
1606
1649
lru_cache_object * _self = (lru_cache_object * ) self ;
1607
1650
if (_self -> maxsize == -1 ) {
1608
1651
return PyObject_CallFunction (_self -> cache_info_type , "nnOn" ,
1609
- _self -> hits , _self -> misses , Py_None ,
1652
+ FT_ATOMIC_LOAD_SSIZE_RELAXED (_self -> hits ),
1653
+ FT_ATOMIC_LOAD_SSIZE_RELAXED (_self -> misses ),
1654
+ Py_None ,
1610
1655
PyDict_GET_SIZE (_self -> cache ));
1611
1656
}
1612
1657
return PyObject_CallFunction (_self -> cache_info_type , "nnnn" ,
1613
- _self -> hits , _self -> misses , _self -> maxsize ,
1658
+ FT_ATOMIC_LOAD_SSIZE_RELAXED (_self -> hits ),
1659
+ FT_ATOMIC_LOAD_SSIZE_RELAXED (_self -> misses ),
1660
+ _self -> maxsize ,
1614
1661
PyDict_GET_SIZE (_self -> cache ));
1615
1662
}
1616
1663
@@ -1627,7 +1674,8 @@ _functools__lru_cache_wrapper_cache_clear_impl(PyObject *self)
1627
1674
{
1628
1675
lru_cache_object * _self = (lru_cache_object * ) self ;
1629
1676
lru_list_elem * list = lru_cache_unlink_list (_self );
1630
- _self -> hits = _self -> misses = 0 ;
1677
+ FT_ATOMIC_STORE_SSIZE_RELAXED (_self -> hits , 0 );
1678
+ FT_ATOMIC_STORE_SSIZE_RELAXED (_self -> misses , 0 );
1631
1679
PyDict_Clear (_self -> cache );
1632
1680
lru_cache_clear_list (list );
1633
1681
Py_RETURN_NONE ;
0 commit comments