asyncio test fixes and asyncio library updates
This commit is contained in:
parent
843fdbb250
commit
bfccb77ec1
@ -383,6 +383,6 @@ const mp_obj_module_t mp_module_uselect = {
|
|||||||
.globals = (mp_obj_dict_t *)&mp_module_select_globals,
|
.globals = (mp_obj_dict_t *)&mp_module_select_globals,
|
||||||
};
|
};
|
||||||
|
|
||||||
MP_REGISTER_MODULE(MP_QSTR_uselect, mp_module_uselect);
|
MP_REGISTER_MODULE(MP_QSTR_select, mp_module_uselect);
|
||||||
|
|
||||||
#endif // MICROPY_PY_USELECT
|
#endif // MICROPY_PY_USELECT
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 596cc896e5c8815caa2a6f405560833193848149
|
Subproject commit 510d4a3bb9326a31105622fe1905301a4f543a2c
|
@ -36,6 +36,7 @@
|
|||||||
|
|
||||||
// CIRCUITPY
|
// CIRCUITPY
|
||||||
#define CIRCUITPY_MICROPYTHON_ADVANCED (1)
|
#define CIRCUITPY_MICROPYTHON_ADVANCED (1)
|
||||||
|
#define MICROPY_PY_ASYNC_AWAIT (1)
|
||||||
|
|
||||||
// If the variant did not set a feature level then configure a set of features.
|
// If the variant did not set a feature level then configure a set of features.
|
||||||
#ifndef MICROPY_CONFIG_ROM_LEVEL
|
#ifndef MICROPY_CONFIG_ROM_LEVEL
|
||||||
|
@ -191,6 +191,7 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, const mp_module
|
|||||||
if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) {
|
if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) {
|
||||||
((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_native_gen_wrap;
|
((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_native_gen_wrap;
|
||||||
}
|
}
|
||||||
|
// CIRCUITPY: no support for mp_type_native_coro_wrap, native coroutine objects (yet).
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if MICROPY_EMIT_INLINE_ASM
|
#if MICROPY_EMIT_INLINE_ASM
|
||||||
@ -203,7 +204,11 @@ mp_obj_t mp_make_function_from_raw_code(const mp_raw_code_t *rc, const mp_module
|
|||||||
assert(rc->kind == MP_CODE_BYTECODE);
|
assert(rc->kind == MP_CODE_BYTECODE);
|
||||||
fun = mp_obj_new_fun_bc(def_args, rc->fun_data, context, rc->children);
|
fun = mp_obj_new_fun_bc(def_args, rc->fun_data, context, rc->children);
|
||||||
// check for generator functions and if so change the type of the object
|
// check for generator functions and if so change the type of the object
|
||||||
if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) {
|
// A generator is MP_SCOPE_FLAG_ASYNC | MP_SCOPE_FLAG_GENERATOR,
|
||||||
|
// so check for ASYNC first.
|
||||||
|
if ((rc->scope_flags & MP_SCOPE_FLAG_ASYNC) != 0) {
|
||||||
|
((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_coro_wrap;
|
||||||
|
} else if ((rc->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) {
|
||||||
((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_gen_wrap;
|
((mp_obj_base_t *)MP_OBJ_TO_PTR(fun))->type = &mp_type_gen_wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
py/obj.h
4
py/obj.h
@ -738,6 +738,10 @@ extern const mp_obj_type_t mp_type_super;
|
|||||||
extern const mp_obj_type_t mp_type_gen_wrap;
|
extern const mp_obj_type_t mp_type_gen_wrap;
|
||||||
extern const mp_obj_type_t mp_type_native_gen_wrap;
|
extern const mp_obj_type_t mp_type_native_gen_wrap;
|
||||||
extern const mp_obj_type_t mp_type_gen_instance;
|
extern const mp_obj_type_t mp_type_gen_instance;
|
||||||
|
// CIRCUITPY
|
||||||
|
extern const mp_obj_type_t mp_type_coro_wrap;
|
||||||
|
// CIRCUITPY
|
||||||
|
extern const mp_obj_type_t mp_type_coro_instance;
|
||||||
extern const mp_obj_type_t mp_type_fun_builtin_0;
|
extern const mp_obj_type_t mp_type_fun_builtin_0;
|
||||||
extern const mp_obj_type_t mp_type_fun_builtin_1;
|
extern const mp_obj_type_t mp_type_fun_builtin_1;
|
||||||
extern const mp_obj_type_t mp_type_fun_builtin_2;
|
extern const mp_obj_type_t mp_type_fun_builtin_2;
|
||||||
|
@ -55,23 +55,23 @@ typedef struct _mp_obj_gen_instance_t {
|
|||||||
// mp_const_none: Not-running, no exception.
|
// mp_const_none: Not-running, no exception.
|
||||||
// MP_OBJ_NULL: Running, no exception.
|
// MP_OBJ_NULL: Running, no exception.
|
||||||
// other: Not running, pending exception.
|
// other: Not running, pending exception.
|
||||||
bool coroutine_generator;
|
|
||||||
mp_obj_t pend_exc;
|
mp_obj_t pend_exc;
|
||||||
mp_code_state_t code_state;
|
mp_code_state_t code_state;
|
||||||
} mp_obj_gen_instance_t;
|
} mp_obj_gen_instance_t;
|
||||||
|
|
||||||
STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
STATIC mp_obj_t gen_wrap_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||||
// A generating function is just a bytecode function with type mp_type_gen_wrap
|
// A generating or coroutine function is just a bytecode function
|
||||||
|
// with type mp_type_gen_wrap or mp_type_coro_wrap.
|
||||||
mp_obj_fun_bc_t *self_fun = MP_OBJ_TO_PTR(self_in);
|
mp_obj_fun_bc_t *self_fun = MP_OBJ_TO_PTR(self_in);
|
||||||
|
|
||||||
// bytecode prelude: get state size and exception stack size
|
// bytecode prelude: get state size and exception stack size
|
||||||
const uint8_t *ip = self_fun->bytecode;
|
const uint8_t *ip = self_fun->bytecode;
|
||||||
MP_BC_PRELUDE_SIG_DECODE(ip);
|
MP_BC_PRELUDE_SIG_DECODE(ip);
|
||||||
|
|
||||||
// allocate the generator object, with room for local stack and exception stack
|
// allocate the generator or coroutine object, with room for local stack and exception stack
|
||||||
mp_obj_gen_instance_t *o = mp_obj_malloc_var(mp_obj_gen_instance_t, byte,
|
mp_obj_gen_instance_t *o = mp_obj_malloc_var(mp_obj_gen_instance_t, byte,
|
||||||
n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t),
|
n_state * sizeof(mp_obj_t) + n_exc_stack * sizeof(mp_exc_stack_t),
|
||||||
&mp_type_gen_instance);
|
self_fun->base.type == &mp_type_gen_wrap ? &mp_type_gen_instance : &mp_type_coro_instance);
|
||||||
|
|
||||||
o->pend_exc = mp_const_none;
|
o->pend_exc = mp_const_none;
|
||||||
o->code_state.fun_bc = self_fun;
|
o->code_state.fun_bc = self_fun;
|
||||||
@ -93,6 +93,19 @@ const mp_obj_type_t mp_type_gen_wrap = {
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const mp_obj_type_t mp_type_coro_wrap = {
|
||||||
|
{ &mp_type_type },
|
||||||
|
.flags = MP_TYPE_FLAG_BINDS_SELF | MP_TYPE_FLAG_EXTENDED,
|
||||||
|
.name = MP_QSTR_coroutine,
|
||||||
|
#if MICROPY_PY_FUNCTION_ATTRS
|
||||||
|
.attr = mp_obj_fun_bc_attr,
|
||||||
|
#endif
|
||||||
|
MP_TYPE_EXTENDED_FIELDS(
|
||||||
|
.call = gen_wrap_call,
|
||||||
|
.unary_op = mp_generic_unary_op,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
// native generator wrapper
|
// native generator wrapper
|
||||||
|
|
||||||
@ -167,20 +180,26 @@ const mp_obj_type_t mp_type_native_gen_wrap = {
|
|||||||
STATIC void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
STATIC void gen_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||||
(void)kind;
|
(void)kind;
|
||||||
mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
#if MICROPY_PY_ASYNC_AWAIT
|
|
||||||
if (self->coroutine_generator) {
|
|
||||||
mp_printf(print, "<%q object '%q' at %p>", MP_QSTR_coroutine, mp_obj_fun_get_name(MP_OBJ_FROM_PTR(self->code_state.fun_bc)), self);
|
|
||||||
} else {
|
|
||||||
mp_printf(print, "<%q object '%q' at %p>", MP_QSTR_generator, mp_obj_fun_get_name(MP_OBJ_FROM_PTR(self->code_state.fun_bc)), self);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
mp_printf(print, "<generator object '%q' at %p>", mp_obj_fun_get_name(MP_OBJ_FROM_PTR(self->code_state.fun_bc)), self);
|
mp_printf(print, "<generator object '%q' at %p>", mp_obj_fun_get_name(MP_OBJ_FROM_PTR(self->code_state.fun_bc)), self);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CIRCUITPY
|
||||||
|
#if MICROPY_PY_ASYNC_AWAIT
|
||||||
|
STATIC void coro_instance_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||||
|
(void)kind;
|
||||||
|
mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
mp_printf(print, "<coroutine object '%q' at %p>", mp_obj_fun_get_name(MP_OBJ_FROM_PTR(self->code_state.fun_bc)), self);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) {
|
mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) {
|
||||||
MP_STACK_CHECK();
|
MP_STACK_CHECK();
|
||||||
mp_check_self(mp_obj_is_type(self_in, &mp_type_gen_instance));
|
// CIRCUITPY
|
||||||
|
// note that self may have as its type either gen or coro,
|
||||||
|
// both of which are stored as an mp_obj_gen_instance_t .
|
||||||
|
mp_check_self(
|
||||||
|
mp_obj_is_type(self_in, &mp_type_gen_instance) ||
|
||||||
|
mp_obj_is_type(self_in, &mp_type_coro_instance));
|
||||||
mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);
|
mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
if (self->code_state.ip == 0) {
|
if (self->code_state.ip == 0) {
|
||||||
// Trying to resume an already stopped generator.
|
// Trying to resume an already stopped generator.
|
||||||
@ -188,7 +207,6 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
|
|||||||
*ret_val = mp_const_none;
|
*ret_val = mp_const_none;
|
||||||
return MP_VM_RETURN_NORMAL;
|
return MP_VM_RETURN_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the generator cannot be reentered during execution
|
// Ensure the generator cannot be reentered during execution
|
||||||
if (self->pend_exc == MP_OBJ_NULL) {
|
if (self->pend_exc == MP_OBJ_NULL) {
|
||||||
mp_raise_ValueError(MP_ERROR_TEXT("generator already executing"));
|
mp_raise_ValueError(MP_ERROR_TEXT("generator already executing"));
|
||||||
@ -285,6 +303,7 @@ mp_vm_return_kind_t mp_obj_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_
|
|||||||
STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, bool raise_stop_iteration) {
|
STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, bool raise_stop_iteration) {
|
||||||
mp_obj_t ret;
|
mp_obj_t ret;
|
||||||
switch (mp_obj_gen_resume(self_in, send_value, throw_value, &ret)) {
|
switch (mp_obj_gen_resume(self_in, send_value, throw_value, &ret)) {
|
||||||
|
|
||||||
case MP_VM_RETURN_NORMAL:
|
case MP_VM_RETURN_NORMAL:
|
||||||
default:
|
default:
|
||||||
// A normal return is a StopIteration, either raise it or return
|
// A normal return is a StopIteration, either raise it or return
|
||||||
@ -307,12 +326,6 @@ STATIC mp_obj_t gen_resume_and_raise(mp_obj_t self_in, mp_obj_t send_value, mp_o
|
|||||||
}
|
}
|
||||||
|
|
||||||
STATIC mp_obj_t gen_instance_iternext(mp_obj_t self_in) {
|
STATIC mp_obj_t gen_instance_iternext(mp_obj_t self_in) {
|
||||||
#if MICROPY_PY_ASYNC_AWAIT
|
|
||||||
mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);
|
|
||||||
if (self->coroutine_generator) {
|
|
||||||
mp_raise_TypeError(MP_ERROR_TEXT("'coroutine' object is not an iterator"));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return gen_resume_and_raise(self_in, mp_const_none, MP_OBJ_NULL, false);
|
return gen_resume_and_raise(self_in, mp_const_none, MP_OBJ_NULL, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,21 +335,12 @@ STATIC mp_obj_t gen_instance_send(mp_obj_t self_in, mp_obj_t send_value) {
|
|||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_send_obj, gen_instance_send);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(gen_instance_send_obj, gen_instance_send);
|
||||||
|
|
||||||
#if MICROPY_PY_ASYNC_AWAIT
|
#if MICROPY_PY_ASYNC_AWAIT
|
||||||
STATIC mp_obj_t gen_instance_await(mp_obj_t self_in) {
|
STATIC mp_obj_t coro_instance_await(mp_obj_t self_in) {
|
||||||
mp_obj_gen_instance_t *self = MP_OBJ_TO_PTR(self_in);
|
return self_in;
|
||||||
if (!self->coroutine_generator) {
|
|
||||||
// Pretend like a generator does not have this coroutine behavior.
|
|
||||||
// Pay no attention to the dir() behind the curtain
|
|
||||||
mp_raise_msg_varg(&mp_type_AttributeError, MP_ERROR_TEXT("type object '%q' has no attribute '%q'"),
|
|
||||||
MP_QSTR_generator, MP_QSTR___await__);
|
|
||||||
}
|
|
||||||
// You can directly call send on a coroutine generator or you can __await__ then send on the return of that.
|
|
||||||
return self;
|
|
||||||
}
|
}
|
||||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(gen_instance_await_obj, gen_instance_await);
|
STATIC MP_DEFINE_CONST_FUN_OBJ_1(coro_instance_await_obj, coro_instance_await);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
STATIC mp_obj_t gen_instance_close(mp_obj_t self_in);
|
|
||||||
STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) {
|
STATIC mp_obj_t gen_instance_throw(size_t n_args, const mp_obj_t *args) {
|
||||||
// The signature of this function is: throw(type[, value[, traceback]])
|
// The signature of this function is: throw(type[, value[, traceback]])
|
||||||
// CPython will pass all given arguments through the call chain and process them
|
// CPython will pass all given arguments through the call chain and process them
|
||||||
@ -408,9 +412,6 @@ STATIC const mp_rom_map_elem_t gen_instance_locals_dict_table[] = {
|
|||||||
#if MICROPY_PY_GENERATOR_PEND_THROW
|
#if MICROPY_PY_GENERATOR_PEND_THROW
|
||||||
{ MP_ROM_QSTR(MP_QSTR_pend_throw), MP_ROM_PTR(&gen_instance_pend_throw_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_pend_throw), MP_ROM_PTR(&gen_instance_pend_throw_obj) },
|
||||||
#endif
|
#endif
|
||||||
#if MICROPY_PY_ASYNC_AWAIT
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR___await__), MP_ROM_PTR(&gen_instance_await_obj) },
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC MP_DEFINE_CONST_DICT(gen_instance_locals_dict, gen_instance_locals_dict_table);
|
STATIC MP_DEFINE_CONST_DICT(gen_instance_locals_dict, gen_instance_locals_dict_table);
|
||||||
@ -427,3 +428,35 @@ const mp_obj_type_t mp_type_gen_instance = {
|
|||||||
.iternext = gen_instance_iternext,
|
.iternext = gen_instance_iternext,
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if MICROPY_PY_ASYNC_AWAIT
|
||||||
|
// CIRCUITPY
|
||||||
|
// coroutine instance locals dict and type
|
||||||
|
// same as generator, but with addition of __await()__.
|
||||||
|
STATIC const mp_rom_map_elem_t coro_instance_locals_dict_table[] = {
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&gen_instance_close_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&gen_instance_send_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_throw), MP_ROM_PTR(&gen_instance_throw_obj) },
|
||||||
|
#if MICROPY_PY_GENERATOR_PEND_THROW
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_pend_throw), MP_ROM_PTR(&gen_instance_pend_throw_obj) },
|
||||||
|
#endif
|
||||||
|
#if MICROPY_PY_ASYNC_AWAIT
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR___await__), MP_ROM_PTR(&coro_instance_await_obj) },
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
STATIC MP_DEFINE_CONST_DICT(coro_instance_locals_dict, coro_instance_locals_dict_table);
|
||||||
|
|
||||||
|
const mp_obj_type_t mp_type_coro_instance = {
|
||||||
|
{ &mp_type_type },
|
||||||
|
.flags = MP_TYPE_FLAG_EXTENDED,
|
||||||
|
.name = MP_QSTR_coroutine,
|
||||||
|
.print = coro_instance_print,
|
||||||
|
.locals_dict = (mp_obj_dict_t *)&coro_instance_locals_dict,
|
||||||
|
MP_TYPE_EXTENDED_FIELDS(
|
||||||
|
.unary_op = mp_generic_unary_op,
|
||||||
|
.getiter = mp_identity_getiter,
|
||||||
|
.iternext = gen_instance_iternext,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
@ -1415,7 +1415,8 @@ mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t th
|
|||||||
assert((send_value != MP_OBJ_NULL) ^ (throw_value != MP_OBJ_NULL));
|
assert((send_value != MP_OBJ_NULL) ^ (throw_value != MP_OBJ_NULL));
|
||||||
const mp_obj_type_t *type = mp_obj_get_type(self_in);
|
const mp_obj_type_t *type = mp_obj_get_type(self_in);
|
||||||
|
|
||||||
if (type == &mp_type_gen_instance) {
|
// CIRCUITPY distinguishes generators and coroutines.
|
||||||
|
if (type == &mp_type_gen_instance || type == &mp_type_coro_instance) {
|
||||||
return mp_obj_gen_resume(self_in, send_value, throw_value, ret_val);
|
return mp_obj_gen_resume(self_in, send_value, throw_value, ret_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
79
tests/extmod/uasyncio_threadsafeflag.py
Normal file
79
tests/extmod/uasyncio_threadsafeflag.py
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
# Test Event class
|
||||||
|
|
||||||
|
try:
|
||||||
|
import uasyncio as asyncio
|
||||||
|
except ImportError:
|
||||||
|
print("SKIP")
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
|
|
||||||
|
import micropython
|
||||||
|
|
||||||
|
try:
|
||||||
|
micropython.schedule
|
||||||
|
except AttributeError:
|
||||||
|
print("SKIP")
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Unix port can't select/poll on user-defined types.
|
||||||
|
import uselect as select
|
||||||
|
|
||||||
|
poller = select.poll()
|
||||||
|
poller.register(asyncio.ThreadSafeFlag())
|
||||||
|
except TypeError:
|
||||||
|
print("SKIP")
|
||||||
|
raise SystemExit
|
||||||
|
|
||||||
|
|
||||||
|
async def task(id, flag):
|
||||||
|
print("task", id)
|
||||||
|
await flag.wait()
|
||||||
|
print("task", id, "done")
|
||||||
|
|
||||||
|
|
||||||
|
def set_from_schedule(flag):
|
||||||
|
print("schedule")
|
||||||
|
flag.set()
|
||||||
|
print("schedule done")
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
flag = asyncio.ThreadSafeFlag()
|
||||||
|
|
||||||
|
# Set the flag from within the loop.
|
||||||
|
t = asyncio.create_task(task(1, flag))
|
||||||
|
print("yield")
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
print("set event")
|
||||||
|
flag.set()
|
||||||
|
print("yield")
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
print("wait task")
|
||||||
|
await t
|
||||||
|
|
||||||
|
# Set the flag from scheduler context.
|
||||||
|
print("----")
|
||||||
|
t = asyncio.create_task(task(2, flag))
|
||||||
|
print("yield")
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
print("set event")
|
||||||
|
micropython.schedule(set_from_schedule, flag)
|
||||||
|
print("yield")
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
print("wait task")
|
||||||
|
await t
|
||||||
|
|
||||||
|
# Flag already set.
|
||||||
|
print("----")
|
||||||
|
print("set event")
|
||||||
|
flag.set()
|
||||||
|
t = asyncio.create_task(task(3, flag))
|
||||||
|
print("yield")
|
||||||
|
await asyncio.sleep(0)
|
||||||
|
print("wait task")
|
||||||
|
await t
|
||||||
|
|
||||||
|
|
||||||
|
asyncio.run(main())
|
21
tests/extmod/uasyncio_threadsafeflag.py.exp
Normal file
21
tests/extmod/uasyncio_threadsafeflag.py.exp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
yield
|
||||||
|
task 1
|
||||||
|
set event
|
||||||
|
yield
|
||||||
|
wait task
|
||||||
|
task 1 done
|
||||||
|
----
|
||||||
|
yield
|
||||||
|
task 2
|
||||||
|
set event
|
||||||
|
yield
|
||||||
|
schedule
|
||||||
|
schedule done
|
||||||
|
wait task
|
||||||
|
task 2 done
|
||||||
|
----
|
||||||
|
set event
|
||||||
|
yield
|
||||||
|
task 3
|
||||||
|
task 3 done
|
||||||
|
wait task
|
@ -1,14 +0,0 @@
|
|||||||
b'ping'
|
|
||||||
b'ping'
|
|
||||||
b'\x81\x04pong'
|
|
||||||
b'pingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingpingping'
|
|
||||||
b'\x81~\x00\x80pongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpongpong'
|
|
||||||
b'\x00\x00\x00\x00'
|
|
||||||
b''
|
|
||||||
b'\x81\x02\x88\x00'
|
|
||||||
b'ping'
|
|
||||||
b'pong'
|
|
||||||
0
|
|
||||||
1
|
|
||||||
2
|
|
||||||
ioctl: EINVAL: True
|
|
Loading…
Reference in New Issue
Block a user