@@ -191,6 +191,43 @@ STATIC mp_obj_t task_done(mp_obj_t self_in) {
191191}
192192STATIC MP_DEFINE_CONST_FUN_OBJ_1 (task_done_obj , task_done );
193193
194+ STATIC mp_obj_t task_add_done_callback (mp_obj_t self_in , mp_obj_t callback ) {
195+ assert (mp_obj_is_callable (callback ));
196+ mp_obj_task_t * self = MP_OBJ_TO_PTR (self_in );
197+
198+ if (TASK_IS_DONE (self )) {
199+ // In CPython the callbacks are not immediately called and are instead
200+ // called by the event loop. However, CircuitPython's event loop doesn't
201+ // support `call_soon` to handle callback processing.
202+ //
203+ // Because of this, it's close enough to call the callback immediately.
204+ mp_call_function_1 (callback , self_in );
205+ return mp_const_none ;
206+ }
207+
208+ if (self -> state != mp_const_true ) {
209+ // Tasks SHOULD support more than one callback per CPython but to reduce
210+ // the surface area of this change tasks can currently only support one.
211+ mp_raise_RuntimeError (MP_ERROR_TEXT ("Tasks only support one done callback." ));
212+ }
213+
214+ self -> state = callback ;
215+ return mp_const_none ;
216+ }
217+ STATIC MP_DEFINE_CONST_FUN_OBJ_2 (task_add_done_callback_obj , task_add_done_callback );
218+
219+ STATIC mp_obj_t task_remove_done_callback (mp_obj_t self_in , mp_obj_t callback ) {
220+ mp_obj_task_t * self = MP_OBJ_TO_PTR (self_in );
221+
222+ if (callback != self -> state ) {
223+ return mp_obj_new_int (0 );
224+ }
225+
226+ self -> state = mp_const_true ;
227+ return mp_obj_new_int (1 );
228+ }
229+ STATIC MP_DEFINE_CONST_FUN_OBJ_2 (task_remove_done_callback_obj , task_remove_done_callback );
230+
194231STATIC mp_obj_t task_get_coro (mp_obj_t self_in ) {
195232 mp_obj_task_t * self = MP_OBJ_TO_PTR (self_in );
196233 return MP_OBJ_FROM_PTR (self -> coro );
@@ -350,6 +387,12 @@ STATIC void task_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
350387 } else if (attr == MP_QSTR___await__ ) {
351388 dest [0 ] = MP_OBJ_FROM_PTR (& task_await_obj );
352389 dest [1 ] = self_in ;
390+ } else if (attr == MP_QSTR_add_done_callback ) {
391+ dest [0 ] = MP_OBJ_FROM_PTR (& task_add_done_callback_obj );
392+ dest [1 ] = self_in ;
393+ } else if (attr == MP_QSTR_remove_done_callback ) {
394+ dest [0 ] = MP_OBJ_FROM_PTR (& task_remove_done_callback_obj );
395+ dest [1 ] = self_in ;
353396 } else if (attr == MP_QSTR_get_coro ) {
354397 dest [0 ] = MP_OBJ_FROM_PTR (& task_get_coro_obj );
355398 dest [1 ] = self_in ;
0 commit comments