Skip to content

Commit 2f18646

Browse files
committed
Add convinience fields to C Task/Future for profilers
1 parent 62c054b commit 2f18646

File tree

1 file changed

+18
-4
lines changed

1 file changed

+18
-4
lines changed

Modules/_asynciomodule.c

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ typedef enum {
4646
so that these and bitfields from TaskObj are contiguous.
4747
*/ \
4848
unsigned prefix##_log_tb: 1; \
49-
unsigned prefix##_blocking: 1;
49+
unsigned prefix##_blocking: 1; \
50+
/* Used by profilers to make traversing the stack from an external \
51+
process faster. */ \
52+
unsigned prefix##_is_task: 1; \
53+
unsigned prefix##_awaited_by_is_set: 1;
5054

5155
typedef struct {
5256
FutureObj_HEAD(fut)
@@ -513,6 +517,8 @@ future_init(FutureObj *fut, PyObject *loop)
513517
fut->fut_state = STATE_PENDING;
514518
fut->fut_log_tb = 0;
515519
fut->fut_blocking = 0;
520+
fut->fut_awaited_by_is_set = 0;
521+
fut->fut_is_task = 0;
516522

517523
if (loop == Py_None) {
518524
asyncio_state *state = get_asyncio_state_by_def((PyObject *)fut);
@@ -568,12 +574,14 @@ future_awaited_by_add(asyncio_state *state, PyObject *fut, PyObject *thing)
568574
to avoid always creating a set for `fut_awaited_by`.
569575
*/
570576
if (_fut->fut_awaited_by == NULL) {
577+
assert(!_fut->fut_awaited_by_is_set);
571578
Py_INCREF(thing);
572579
_fut->fut_awaited_by = thing;
573580
return 0;
574581
}
575582

576-
if (PySet_Check(_fut->fut_awaited_by)) {
583+
if (_fut->fut_awaited_by_is_set) {
584+
assert(PySet_Check(_fut->fut_awaited_by));
577585
return PySet_Add(_fut->fut_awaited_by, thing);
578586
}
579587

@@ -590,6 +598,7 @@ future_awaited_by_add(asyncio_state *state, PyObject *fut, PyObject *thing)
590598
return -1;
591599
}
592600
Py_SETREF(_fut->fut_awaited_by, set);
601+
_fut->fut_awaited_by_is_set = 1;
593602
return 0;
594603
}
595604

@@ -615,7 +624,8 @@ future_awaited_by_discard(asyncio_state *state, PyObject *fut, PyObject *thing)
615624
Py_CLEAR(_fut->fut_awaited_by);
616625
return 0;
617626
}
618-
if (PySet_Check(_fut->fut_awaited_by)) {
627+
if (_fut->fut_awaited_by_is_set) {
628+
assert(PySet_Check(_fut->fut_awaited_by));
619629
int err = PySet_Discard(_fut->fut_awaited_by, thing);
620630
if (err < 0 && PyErr_Occurred()) {
621631
return -1;
@@ -633,7 +643,9 @@ future_get_awaited_by(FutureObj *fut)
633643
if (fut->fut_awaited_by == NULL) {
634644
Py_RETURN_NONE;
635645
}
636-
if (PySet_Check(fut->fut_awaited_by)) {
646+
if (fut->fut_awaited_by_is_set) {
647+
/* Already a set, just wrap it into a frozen set and return. */
648+
assert(PySet_Check(fut->fut_awaited_by));
637649
return PyFrozenSet_New(fut->fut_awaited_by);
638650
}
639651

@@ -935,6 +947,7 @@ FutureObj_clear(FutureObj *fut)
935947
Py_CLEAR(fut->fut_cancel_msg);
936948
Py_CLEAR(fut->fut_cancelled_exc);
937949
Py_CLEAR(fut->fut_awaited_by);
950+
fut->fut_awaited_by_is_set = 0;
938951
PyObject_ClearManagedDict((PyObject *)fut);
939952
return 0;
940953
}
@@ -2229,6 +2242,7 @@ _asyncio_Task___init___impl(TaskObj *self, PyObject *coro, PyObject *loop,
22292242
if (future_init((FutureObj*)self, loop)) {
22302243
return -1;
22312244
}
2245+
self->task_is_task = 1;
22322246

22332247
asyncio_state *state = get_asyncio_state_by_def((PyObject *)self);
22342248
int is_coro = is_coroutine(state, coro);

0 commit comments

Comments
 (0)