Skip to content

Commit be398ce

Browse files
committed
Bound CAS retries in subinterpreter pool allocation
Add 100 retry limit to prevent livelock under high contention. After 10 fast retries, adds 1us sleep between attempts. Returns -1 if allocation fails due to contention.
1 parent 738c625 commit be398ce

1 file changed

Lines changed: 14 additions & 3 deletions

File tree

c_src/py_subinterp_pool.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,13 +211,16 @@ int subinterp_pool_init(int size) {
211211
return 0;
212212
}
213213

214+
#define POOL_ALLOC_MAX_RETRIES 100
215+
214216
int subinterp_pool_alloc(void) {
215217
if (!atomic_load(&g_pool_initialized)) {
216218
return -1;
217219
}
218220

219-
/* Try to find and allocate a free slot using CAS */
220-
while (1) {
221+
/* Try to find and allocate a free slot using CAS with bounded retries */
222+
int retries = 0;
223+
while (retries < POOL_ALLOC_MAX_RETRIES) {
221224
uint64_t current = atomic_load(&g_pool_allocation);
222225

223226
/* Find first free bit (0 bit) */
@@ -239,8 +242,16 @@ int subinterp_pool_alloc(void) {
239242
if (atomic_compare_exchange_weak(&g_pool_allocation, &current, new_val)) {
240243
return slot;
241244
}
242-
/* CAS failed, retry */
245+
246+
/* CAS failed, back off briefly after initial fast retries */
247+
retries++;
248+
if (retries > 10) {
249+
usleep(1);
250+
}
243251
}
252+
253+
/* Too much contention, give up */
254+
return -1;
244255
}
245256

246257
void subinterp_pool_free(int slot) {

0 commit comments

Comments
 (0)