bpo-33608: Deal with pending calls relative to runtime shutdown. (gh-… · python/cpython@842a2f0 (original) (raw)

`@@ -330,31 +330,33 @@ _PyEval_SignalReceived(void)

`

330

330

``

331

331

`/* Push one item onto the queue while holding the lock. */

`

332

332

`static int

`

333

``

`-

_push_pending_call(int (*func)(void *), void *arg)

`

``

333

`+

_push_pending_call(struct _pending_calls *pending,

`

``

334

`+

int (*func)(void *), void *arg)

`

334

335

`{

`

335

``

`-

int i = _PyRuntime.ceval.pending.last;

`

``

336

`+

int i = pending->last;

`

336

337

`int j = (i + 1) % NPENDINGCALLS;

`

337

``

`-

if (j == _PyRuntime.ceval.pending.first) {

`

``

338

`+

if (j == pending->first) {

`

338

339

`return -1; /* Queue full */

`

339

340

` }

`

340

``

`-

_PyRuntime.ceval.pending.calls[i].func = func;

`

341

``

`-

_PyRuntime.ceval.pending.calls[i].arg = arg;

`

342

``

`-

_PyRuntime.ceval.pending.last = j;

`

``

341

`+

pending->calls[i].func = func;

`

``

342

`+

pending->calls[i].arg = arg;

`

``

343

`+

pending->last = j;

`

343

344

`return 0;

`

344

345

`}

`

345

346

``

346

347

`/* Pop one item off the queue while holding the lock. */

`

347

348

`static void

`

348

``

`-

_pop_pending_call(int (**func)(void *), void **arg)

`

``

349

`+

_pop_pending_call(struct _pending_calls *pending,

`

``

350

`+

int (**func)(void *), void **arg)

`

349

351

`{

`

350

``

`-

int i = _PyRuntime.ceval.pending.first;

`

351

``

`-

if (i == _PyRuntime.ceval.pending.last) {

`

``

352

`+

int i = pending->first;

`

``

353

`+

if (i == pending->last) {

`

352

354

`return; /* Queue empty */

`

353

355

` }

`

354

356

``

355

``

`-

*func = _PyRuntime.ceval.pending.calls[i].func;

`

356

``

`-

*arg = _PyRuntime.ceval.pending.calls[i].arg;

`

357

``

`-

_PyRuntime.ceval.pending.first = (i + 1) % NPENDINGCALLS;

`

``

357

`+

*func = pending->calls[i].func;

`

``

358

`+

*arg = pending->calls[i].arg;

`

``

359

`+

pending->first = (i + 1) % NPENDINGCALLS;

`

358

360

`}

`

359

361

``

360

362

`/* This implementation is thread-safe. It allows

`

`@@ -365,9 +367,23 @@ _pop_pending_call(int (**func)(void *), void **arg)

`

365

367

`int

`

366

368

`Py_AddPendingCall(int (*func)(void *), void *arg)

`

367

369

`{

`

368

``

`-

PyThread_acquire_lock(_PyRuntime.ceval.pending.lock, WAIT_LOCK);

`

369

``

`-

int result = _push_pending_call(func, arg);

`

370

``

`-

PyThread_release_lock(_PyRuntime.ceval.pending.lock);

`

``

370

`+

struct _pending_calls *pending = &_PyRuntime.ceval.pending;

`

``

371

+

``

372

`+

PyThread_acquire_lock(pending->lock, WAIT_LOCK);

`

``

373

`+

if (pending->finishing) {

`

``

374

`+

PyThread_release_lock(pending->lock);

`

``

375

+

``

376

`+

PyObject *exc, *val, *tb;

`

``

377

`+

PyErr_Fetch(&exc, &val, &tb);

`

``

378

`+

PyErr_SetString(PyExc_SystemError,

`

``

379

`+

"Py_AddPendingCall: cannot add pending calls "

`

``

380

`+

"(Python shutting down)");

`

``

381

`+

PyErr_Print();

`

``

382

`+

PyErr_Restore(exc, val, tb);

`

``

383

`+

return -1;

`

``

384

`+

}

`

``

385

`+

int result = _push_pending_call(pending, func, arg);

`

``

386

`+

PyThread_release_lock(pending->lock);

`

371

387

``

372

388

`/* signal main loop */

`

373

389

`SIGNAL_PENDING_CALLS();

`

`@@ -400,7 +416,7 @@ handle_signals(void)

`

400

416

`}

`

401

417

``

402

418

`static int

`

403

``

`-

make_pending_calls(void)

`

``

419

`+

make_pending_calls(struct _pending_calls* pending)

`

404

420

`{

`

405

421

`static int busy = 0;

`

406

422

``

`@@ -425,9 +441,9 @@ make_pending_calls(void)

`

425

441

`void *arg = NULL;

`

426

442

``

427

443

`/* pop one item off the queue while holding the lock */

`

428

``

`-

PyThread_acquire_lock(_PyRuntime.ceval.pending.lock, WAIT_LOCK);

`

429

``

`-

_pop_pending_call(&func, &arg);

`

430

``

`-

PyThread_release_lock(_PyRuntime.ceval.pending.lock);

`

``

444

`+

PyThread_acquire_lock(pending->lock, WAIT_LOCK);

`

``

445

`+

_pop_pending_call(pending, &func, &arg);

`

``

446

`+

PyThread_release_lock(pending->lock);

`

431

447

``

432

448

`/* having released the lock, perform the callback */

`

433

449

`if (func == NULL) {

`

`@@ -448,6 +464,30 @@ make_pending_calls(void)

`

448

464

`return res;

`

449

465

`}

`

450

466

``

``

467

`+

void

`

``

468

`+

_Py_FinishPendingCalls(void)

`

``

469

`+

{

`

``

470

`+

struct _pending_calls *pending = &_PyRuntime.ceval.pending;

`

``

471

+

``

472

`+

assert(PyGILState_Check());

`

``

473

+

``

474

`+

PyThread_acquire_lock(pending->lock, WAIT_LOCK);

`

``

475

`+

pending->finishing = 1;

`

``

476

`+

PyThread_release_lock(pending->lock);

`

``

477

+

``

478

`+

if (!_Py_atomic_load_relaxed(&(pending->calls_to_do))) {

`

``

479

`+

return;

`

``

480

`+

}

`

``

481

+

``

482

`+

if (make_pending_calls(pending) < 0) {

`

``

483

`+

PyObject *exc, *val, *tb;

`

``

484

`+

PyErr_Fetch(&exc, &val, &tb);

`

``

485

`+

PyErr_BadInternalCall();

`

``

486

`+

_PyErr_ChainExceptions(exc, val, tb);

`

``

487

`+

PyErr_Print();

`

``

488

`+

}

`

``

489

`+

}

`

``

490

+

451

491

`/* Py_MakePendingCalls() is a simple wrapper for the sake

`

452

492

` of backward-compatibility. */

`

453

493

`int

`

`@@ -462,7 +502,7 @@ Py_MakePendingCalls(void)

`

462

502

`return res;

`

463

503

` }

`

464

504

``

465

``

`-

res = make_pending_calls();

`

``

505

`+

res = make_pending_calls(&_PyRuntime.ceval.pending);

`

466

506

`if (res != 0) {

`

467

507

`return res;

`

468

508

` }

`

`@@ -1012,7 +1052,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)

`

1012

1052

`if (_Py_atomic_load_relaxed(

`

1013

1053

`&_PyRuntime.ceval.pending.calls_to_do))

`

1014

1054

` {

`

1015

``

`-

if (make_pending_calls() != 0) {

`

``

1055

`+

if (make_pending_calls(&_PyRuntime.ceval.pending) != 0) {

`

1016

1056

` goto error;

`

1017

1057

` }

`

1018

1058

` }

`