Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HACK: fix await wait(0) #262

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pybricks/common/pb_type_device.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ void *pb_type_device_get_data_blocking(mp_obj_t self_in, uint8_t mode) {
* @return True if operation is complete (device ready),
* false otherwise.
*/
static bool pb_pup_device_test_completion(mp_obj_t self_in, uint32_t end_time) {
static bool pb_pup_device_test_completion(mp_obj_t self_in, uint32_t *end_time) {
pb_type_device_obj_base_t *sensor = MP_OBJ_TO_PTR(self_in);
pbio_error_t err = pbdrv_legodev_is_ready(sensor->legodev);
if (err == PBIO_ERROR_AGAIN) {
Expand Down
2 changes: 1 addition & 1 deletion pybricks/common/pb_type_motor.c
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ static mp_obj_t pb_type_Motor_hold(mp_obj_t self_in) {
}
static MP_DEFINE_CONST_FUN_OBJ_1(pb_type_Motor_hold_obj, pb_type_Motor_hold);

static bool pb_type_Motor_test_completion(mp_obj_t self_in, uint32_t end_time) {
static bool pb_type_Motor_test_completion(mp_obj_t self_in, uint32_t *end_time) {
pb_type_Motor_obj_t *self = MP_OBJ_TO_PTR(self_in);
// Handle I/O exceptions like port unplugged.
if (!pbio_servo_update_loop_is_running(self->srv)) {
Expand Down
4 changes: 2 additions & 2 deletions pybricks/common/pb_type_speaker.c
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ static mp_obj_t pb_type_Speaker_make_new(const mp_obj_type_t *type, size_t n_arg
return MP_OBJ_FROM_PTR(self);
}

static bool pb_type_Speaker_beep_test_completion(mp_obj_t self_in, uint32_t end_time) {
static bool pb_type_Speaker_beep_test_completion(mp_obj_t self_in, uint32_t *end_time) {
pb_type_Speaker_obj_t *self = MP_OBJ_TO_PTR(self_in);
if (mp_hal_ticks_ms() - self->beep_end_time < (uint32_t)INT32_MAX) {
pb_type_Speaker_stop_beep();
Expand Down Expand Up @@ -337,7 +337,7 @@ static void pb_type_Speaker_play_note(pb_type_Speaker_obj_t *self, mp_obj_t obj,
self->beep_end_time = release ? time_now + 7 * duration / 8 : time_now + duration;
}

static bool pb_type_Speaker_notes_test_completion(mp_obj_t self_in, uint32_t end_time) {
static bool pb_type_Speaker_notes_test_completion(mp_obj_t self_in, uint32_t *end_time) {
pb_type_Speaker_obj_t *self = MP_OBJ_TO_PTR(self_in);

bool release_done = mp_hal_ticks_ms() - self->release_end_time < (uint32_t)INT32_MAX;
Expand Down
2 changes: 1 addition & 1 deletion pybricks/robotics/pb_type_drivebase.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ static mp_obj_t pb_type_DriveBase_make_new(const mp_obj_type_t *type, size_t n_a
return MP_OBJ_FROM_PTR(self);
}

static bool pb_type_DriveBase_test_completion(mp_obj_t self_in, uint32_t end_time) {
static bool pb_type_DriveBase_test_completion(mp_obj_t self_in, uint32_t *end_time) {

pb_type_DriveBase_obj_t *self = MP_OBJ_TO_PTR(self_in);

Expand Down
31 changes: 27 additions & 4 deletions pybricks/tools/pb_module_tools.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,18 @@ void pb_module_tools_assert_blocking(void) {
// us share the same code with other awaitables. It also minimizes allocation.
MP_REGISTER_ROOT_POINTER(mp_obj_t wait_awaitables);

static bool pb_module_tools_wait_test_completion(mp_obj_t obj, uint32_t end_time) {
return mp_hal_ticks_ms() - end_time < UINT32_MAX / 2;
static bool pb_module_tools_wait_one(mp_obj_t obj, uint32_t *end_time) {
// yield only on the first iteration.
if (*end_time == pb_type_awaitable_end_time_none) {
(*end_time)++;
return false;
}

return true;
}

static bool pb_module_tools_wait_test_completion(mp_obj_t obj, uint32_t *end_time) {
return mp_hal_ticks_ms() - *end_time < UINT32_MAX / 2;
}

static mp_obj_t pb_module_tools_wait(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
Expand All @@ -71,8 +81,21 @@ static mp_obj_t pb_module_tools_wait(size_t n_args, const mp_obj_t *pos_args, mp
// test completion state in iteration loop.
time = pbio_int_math_bind(time, 0, INT32_MAX >> 2);

// Special case to emulate CPython asyncio.sleep(0) where we ensure that
// the task yields exactly once.
if (time == 0) {
return pb_type_awaitable_await_or_wait(
MP_OBJ_NULL,
MP_STATE_PORT(wait_awaitables),
pb_type_awaitable_end_time_none,
pb_module_tools_wait_one,
pb_type_awaitable_return_none,
pb_type_awaitable_cancel_none,
PB_TYPE_AWAITABLE_OPT_NONE);
}

return pb_type_awaitable_await_or_wait(
NULL, // wait functions are not associated with an object
MP_OBJ_NULL, // wait functions are not associated with an object
MP_STATE_PORT(wait_awaitables),
mp_hal_ticks_ms() + time,
pb_module_tools_wait_test_completion,
Expand Down Expand Up @@ -133,7 +156,7 @@ void pb_module_tools_pbio_task_do_blocking(pbio_task_t *task, mp_int_t timeout)
// here instead of with each Bluetooth-related MicroPython object.
MP_REGISTER_ROOT_POINTER(mp_obj_t pbio_task_awaitables);

static bool pb_module_tools_pbio_task_test_completion(mp_obj_t obj, uint32_t end_time) {
static bool pb_module_tools_pbio_task_test_completion(mp_obj_t obj, uint32_t *end_time) {
pbio_task_t *task = MP_OBJ_TO_PTR(obj);

// Keep going if not done yet.
Expand Down
6 changes: 3 additions & 3 deletions pybricks/tools/pb_type_awaitable.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ static mp_obj_t pb_type_awaitable_iternext(mp_obj_t self_in) {
}

// Keep going if not completed by returning None.
if (!self->test_completion(self->obj, self->end_time)) {
if (!self->test_completion(self->obj, &self->end_time)) {
return mp_const_none;
}

Expand Down Expand Up @@ -127,7 +127,7 @@ static pb_type_awaitable_obj_t *pb_type_awaitable_get(mp_obj_t awaitables_in) {
* checker. This allows MicroPython to handle completion during the next call
* to iternext.
*/
static bool pb_type_awaitable_completed(mp_obj_t self_in, uint32_t start_time) {
static bool pb_type_awaitable_completed(mp_obj_t self_in, uint32_t *end_time) {
return true;
}

Expand Down Expand Up @@ -219,7 +219,7 @@ mp_obj_t pb_type_awaitable_await_or_wait(
}

// Outside run loop, block until the operation is complete.
while (test_completion_func && !test_completion_func(obj, end_time)) {
while (test_completion_func && !test_completion_func(obj, &end_time)) {
mp_hal_delay_ms(1);
}
if (!return_value_func) {
Expand Down
4 changes: 2 additions & 2 deletions pybricks/tools/pb_type_awaitable.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ typedef struct _pb_type_awaitable_obj_t pb_type_awaitable_obj_t;
* below, which always stops the relevant hardware (i.e. always coast).
*
* @param [in] obj The object associated with this awaitable.
* @param [in] start_time The time when the awaitable was created.
* @param [in] end_time Can be used by the callback for timeouts, etc.
* @return True if operation is complete, False otherwise.
*/
typedef bool (*pb_type_awaitable_test_completion_t)(mp_obj_t obj, uint32_t end_time);
typedef bool (*pb_type_awaitable_test_completion_t)(mp_obj_t obj, uint32_t *end_time);

/**
* Gets the return value of the awaitable. If it always returns None, providing
Expand Down
Loading