Porównaj commity

..

1 Commity

Autor SHA1 Wiadomość Data
Angus Gratton dc2a7ee4b2
Merge fd7bc4f12b into 49ce7a6075 2024-04-22 21:13:04 +08:00
18 zmienionych plików z 33 dodań i 512 usunięć

Wyświetl plik

@ -156,7 +156,7 @@ static MP_DEFINE_CONST_OBJ_TYPE(
// Task class
// This is the core asyncio context with cur_task, _task_queue and CancelledError.
mp_obj_t mp_asyncio_context = MP_OBJ_NULL;
static mp_obj_t asyncio_context = MP_OBJ_NULL;
static mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 2, false);
@ -168,7 +168,7 @@ static mp_obj_t task_make_new(const mp_obj_type_t *type, size_t n_args, size_t n
self->state = TASK_STATE_RUNNING_NOT_WAITED_ON;
self->ph_key = MP_OBJ_NEW_SMALL_INT(0);
if (n_args == 2) {
mp_asyncio_context = args[1];
asyncio_context = args[1];
}
return MP_OBJ_FROM_PTR(self);
}
@ -186,7 +186,7 @@ static mp_obj_t task_cancel(mp_obj_t self_in) {
return mp_const_false;
}
// Can't cancel self (not supported yet).
mp_obj_t cur_task = mp_obj_dict_get(mp_asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
mp_obj_t cur_task = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
if (self_in == cur_task) {
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("can't cancel self"));
}
@ -195,7 +195,7 @@ static mp_obj_t task_cancel(mp_obj_t self_in) {
self = MP_OBJ_TO_PTR(self->data);
}
mp_obj_t _task_queue = mp_obj_dict_get(mp_asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR__task_queue));
mp_obj_t _task_queue = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR__task_queue));
// Reschedule Task as a cancelled task.
mp_obj_t dest[3];
@ -218,7 +218,7 @@ static mp_obj_t task_cancel(mp_obj_t self_in) {
task_queue_push(2, dest);
}
self->data = mp_obj_dict_get(mp_asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_CancelledError));
self->data = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_CancelledError));
return mp_const_true;
}
@ -278,7 +278,7 @@ static mp_obj_t task_iternext(mp_obj_t self_in) {
nlr_raise(self->data);
} else {
// Put calling task on waiting queue.
mp_obj_t cur_task = mp_obj_dict_get(mp_asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
mp_obj_t cur_task = mp_obj_dict_get(asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
mp_obj_t args[2] = { self->state, cur_task };
task_queue_push(2, args);
// Set calling task's data to this task that it waits on, to double-link it.

Wyświetl plik

@ -22,9 +22,6 @@ BUILD ?= build-$(VARIANT)
include ../../py/mkenv.mk
include $(VARIANT_DIR)/mpconfigvariant.mk
# Use the default frozen manifest, variants may override this.
FROZEN_MANIFEST ?= variants/manifest.py
# Qstr definitions (must come before including py.mk).
QSTR_DEFS = qstrdefsport.h

Wyświetl plik

@ -38,7 +38,7 @@ export async function loadMicroPython(options) {
{ heapsize: 1024 * 1024, linebuffer: true },
options,
);
let Module = {};
const Module = {};
Module.locateFile = (path, scriptDirectory) =>
url || scriptDirectory + path;
Module._textDecoder = new TextDecoder();
@ -83,7 +83,11 @@ export async function loadMicroPython(options) {
Module.stderr = (c) => stderr(new Uint8Array([c]));
}
}
Module = await _createMicroPythonModule(Module);
const moduleLoaded = new Promise((r) => {
Module.postRun = r;
});
_createMicroPythonModule(Module);
await moduleLoaded;
globalThis.Module = Module;
proxy_js_init();
const pyimport = (name) => {
@ -127,31 +131,23 @@ export async function loadMicroPython(options) {
},
pyimport: pyimport,
runPython(code) {
const len = Module.lengthBytesUTF8(code);
const buf = Module._malloc(len + 1);
Module.stringToUTF8(code, buf, len + 1);
const value = Module._malloc(3 * 4);
Module.ccall(
"mp_js_do_exec",
"number",
["pointer", "number", "pointer"],
[buf, len, value],
["string", "pointer"],
[code, value],
);
Module._free(buf);
return proxy_convert_mp_to_js_obj_jsside_with_free(value);
},
runPythonAsync(code) {
const len = Module.lengthBytesUTF8(code);
const buf = Module._malloc(len + 1);
Module.stringToUTF8(code, buf, len + 1);
const value = Module._malloc(3 * 4);
Module.ccall(
"mp_js_do_exec_async",
"number",
["pointer", "number", "pointer"],
[buf, len, value],
["string", "pointer"],
[code, value],
);
Module._free(buf);
return proxy_convert_mp_to_js_obj_jsside_with_free(value);
},
replInit() {
@ -228,16 +224,6 @@ async function runCLI() {
}
});
} else {
// If the script to run ends with a running of the asyncio main loop, then inject
// a simple `asyncio.run` hook that starts the main task. This is primarily to
// support running the standard asyncio tests.
if (contents.endsWith("asyncio.run(main())\n")) {
const asyncio = mp.pyimport("asyncio");
asyncio.run = async (task) => {
await asyncio.create_task(task);
};
}
try {
mp.runPython(contents);
} catch (error) {

Wyświetl plik

@ -1,9 +0,0 @@
# MicroPython asyncio module, for use with webassembly port
# MIT license; Copyright (c) 2024 Damien P. George
from .core import *
from .funcs import wait_for, wait_for_ms, gather
from .event import Event
from .lock import Lock
__version__ = (3, 0, 0)

Wyświetl plik

@ -1,249 +0,0 @@
# MicroPython asyncio module, for use with webassembly port
# MIT license; Copyright (c) 2019-2024 Damien P. George
from time import ticks_ms as ticks, ticks_diff, ticks_add
import sys, js, jsffi
# Import TaskQueue and Task from built-in C code.
from _asyncio import TaskQueue, Task
################################################################################
# Exceptions
class CancelledError(BaseException):
pass
class TimeoutError(Exception):
pass
# Used when calling Loop.call_exception_handler.
_exc_context = {"message": "Task exception wasn't retrieved", "exception": None, "future": None}
################################################################################
# Sleep functions
# "Yield" once, then raise StopIteration
class SingletonGenerator:
def __init__(self):
self.state = None
self.exc = StopIteration()
def __iter__(self):
return self
def __next__(self):
if self.state is not None:
_task_queue.push(cur_task, self.state)
self.state = None
return None
else:
self.exc.__traceback__ = None
raise self.exc
# Pause task execution for the given time (integer in milliseconds, uPy extension)
# Use a SingletonGenerator to do it without allocating on the heap
def sleep_ms(t, sgen=SingletonGenerator()):
if cur_task is None:
# Support top-level asyncio.sleep, via a JavaScript Promise.
return jsffi.async_timeout_ms(t)
assert sgen.state is None
sgen.state = ticks_add(ticks(), max(0, t))
return sgen
# Pause task execution for the given time (in seconds)
def sleep(t):
return sleep_ms(int(t * 1000))
################################################################################
# Main run loop
asyncio_timer = None
class ThenableEvent:
def __init__(self, thenable):
self.result = None # Result of the thenable
self.waiting = None # Task waiting on completion of this thenable
thenable.then(self.set)
def set(self, value):
# Thenable/Promise is fulfilled, set result and schedule any waiting task.
self.result = value
if self.waiting:
_task_queue.push(self.waiting)
self.waiting = None
_schedule_run_iter(0)
def remove(self, task):
self.waiting = None
# async
def wait(self):
# Set the calling task as the task waiting on this thenable.
self.waiting = cur_task
# Set calling task's data to this object so it can be removed if needed.
cur_task.data = self
# Wait for the thenable to fulfill.
yield
# Return the result of the thenable.
return self.result
# Ensure the awaitable is a task
def _promote_to_task(aw):
return aw if isinstance(aw, Task) else create_task(aw)
def _schedule_run_iter(dt):
global asyncio_timer
if asyncio_timer is not None:
js.clearTimeout(asyncio_timer)
asyncio_timer = js.setTimeout(_run_iter, dt)
def _run_iter():
global cur_task
excs_all = (CancelledError, Exception) # To prevent heap allocation in loop
excs_stop = (CancelledError, StopIteration) # To prevent heap allocation in loop
while True:
# Wait until the head of _task_queue is ready to run
t = _task_queue.peek()
if t:
# A task waiting on _task_queue; "ph_key" is time to schedule task at
dt = max(0, ticks_diff(t.ph_key, ticks()))
else:
# No tasks can be woken so finished running
cur_task = None
return
if dt > 0:
# schedule to call again later
cur_task = None
_schedule_run_iter(dt)
return
# Get next task to run and continue it
t = _task_queue.pop()
cur_task = t
try:
# Continue running the coroutine, it's responsible for rescheduling itself
exc = t.data
if not exc:
t.coro.send(None)
else:
# If the task is finished and on the run queue and gets here, then it
# had an exception and was not await'ed on. Throwing into it now will
# raise StopIteration and the code below will catch this and run the
# call_exception_handler function.
t.data = None
t.coro.throw(exc)
except excs_all as er:
# Check the task is not on any event queue
assert t.data is None
# This task is done.
if t.state:
# Task was running but is now finished.
waiting = False
if t.state is True:
# "None" indicates that the task is complete and not await'ed on (yet).
t.state = None
elif callable(t.state):
# The task has a callback registered to be called on completion.
t.state(t, er)
t.state = False
waiting = True
else:
# Schedule any other tasks waiting on the completion of this task.
while t.state.peek():
_task_queue.push(t.state.pop())
waiting = True
# "False" indicates that the task is complete and has been await'ed on.
t.state = False
if not waiting and not isinstance(er, excs_stop):
# An exception ended this detached task, so queue it for later
# execution to handle the uncaught exception if no other task retrieves
# the exception in the meantime (this is handled by Task.throw).
_task_queue.push(t)
# Save return value of coro to pass up to caller.
t.data = er
elif t.state is None:
# Task is already finished and nothing await'ed on the task,
# so call the exception handler.
# Save exception raised by the coro for later use.
t.data = exc
# Create exception context and call the exception handler.
_exc_context["exception"] = exc
_exc_context["future"] = t
Loop.call_exception_handler(_exc_context)
# Create and schedule a new task from a coroutine.
def create_task(coro):
if not hasattr(coro, "send"):
raise TypeError("coroutine expected")
t = Task(coro, globals())
_task_queue.push(t)
_schedule_run_iter(0)
return t
################################################################################
# Event loop wrapper
cur_task = None
class Loop:
_exc_handler = None
def create_task(coro):
return create_task(coro)
def close():
pass
def set_exception_handler(handler):
Loop._exc_handler = handler
def get_exception_handler():
return Loop._exc_handler
def default_exception_handler(loop, context):
print(context["message"], file=sys.stderr)
print("future:", context["future"], "coro=", context["future"].coro, file=sys.stderr)
sys.print_exception(context["exception"], sys.stderr)
def call_exception_handler(context):
(Loop._exc_handler or Loop.default_exception_handler)(Loop, context)
def get_event_loop():
return Loop
def current_task():
if cur_task is None:
raise RuntimeError("no running event loop")
return cur_task
def new_event_loop():
global _task_queue
_task_queue = TaskQueue() # TaskQueue of Task instances.
return Loop
# Initialise default event loop.
new_event_loop()

Wyświetl plik

@ -104,7 +104,7 @@ void mp_js_do_import(const char *name, uint32_t *out) {
}
}
void mp_js_do_exec(const char *src, size_t len, uint32_t *out) {
void mp_js_do_exec(const char *src, uint32_t *out) {
// Collect at the top-level, where there are no root pointers from stack/registers.
gc_collect_start();
gc_collect_end();
@ -112,7 +112,7 @@ void mp_js_do_exec(const char *src, size_t len, uint32_t *out) {
mp_parse_input_kind_t input_kind = MP_PARSE_FILE_INPUT;
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_lexer_t *lex = mp_lexer_new_from_str_len_dedent(MP_QSTR__lt_stdin_gt_, src, len, 0);
mp_lexer_t *lex = mp_lexer_new_from_str_len_dedent(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
qstr source_name = lex->source_name;
mp_parse_tree_t parse_tree = mp_parse(lex, input_kind);
mp_obj_t module_fun = mp_compile(&parse_tree, source_name, false);
@ -125,9 +125,9 @@ void mp_js_do_exec(const char *src, size_t len, uint32_t *out) {
}
}
void mp_js_do_exec_async(const char *src, size_t len, uint32_t *out) {
void mp_js_do_exec_async(const char *src, uint32_t *out) {
mp_compile_allow_top_level_await = true;
mp_js_do_exec(src, len, out);
mp_js_do_exec(src, out);
mp_compile_allow_top_level_await = false;
}

Wyświetl plik

@ -61,27 +61,12 @@ static mp_obj_t mp_jsffi_to_js(mp_obj_t arg) {
}
static MP_DEFINE_CONST_FUN_OBJ_1(mp_jsffi_to_js_obj, mp_jsffi_to_js);
// *FORMAT-OFF*
EM_JS(void, promise_with_timeout_ms, (double ms, uint32_t * out), {
const ret = new Promise((resolve) => setTimeout(resolve, ms));
proxy_convert_js_to_mp_obj_jsside(ret, out);
});
// *FORMAT-ON*
static mp_obj_t mp_jsffi_async_timeout_ms(mp_obj_t arg) {
uint32_t out[PVN];
promise_with_timeout_ms(mp_obj_get_float_to_d(arg), out);
return proxy_convert_js_to_mp_obj_cside(out);
}
static MP_DEFINE_CONST_FUN_OBJ_1(mp_jsffi_async_timeout_ms_obj, mp_jsffi_async_timeout_ms);
static const mp_rom_map_elem_t mp_module_jsffi_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_jsffi) },
{ MP_ROM_QSTR(MP_QSTR_JsProxy), MP_ROM_PTR(&mp_type_jsproxy) },
{ MP_ROM_QSTR(MP_QSTR_create_proxy), MP_ROM_PTR(&mp_jsffi_create_proxy_obj) },
{ MP_ROM_QSTR(MP_QSTR_to_js), MP_ROM_PTR(&mp_jsffi_to_js_obj) },
{ MP_ROM_QSTR(MP_QSTR_async_timeout_ms), MP_ROM_PTR(&mp_jsffi_async_timeout_ms_obj) },
};
static MP_DEFINE_CONST_DICT(mp_module_jsffi_globals, mp_module_jsffi_globals_table);

Wyświetl plik

@ -346,12 +346,6 @@ typedef struct _jsproxy_gen_t {
mp_vm_return_kind_t jsproxy_gen_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) {
jsproxy_gen_t *self = MP_OBJ_TO_PTR(self_in);
if (throw_value) {
*ret_val = throw_value;
return MP_VM_RETURN_EXCEPTION;
}
switch (self->state) {
case JSOBJ_GEN_STATE_WAITING:
self->state = JSOBJ_GEN_STATE_COMPLETED;
@ -474,29 +468,9 @@ static mp_obj_t jsproxy_new_gen(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
/******************************************************************************/
#if MICROPY_PY_ASYNCIO
extern mp_obj_t mp_asyncio_context;
#endif
static mp_obj_t jsproxy_getiter(mp_obj_t self_in, mp_obj_iter_buf_t *iter_buf) {
mp_obj_jsproxy_t *self = MP_OBJ_TO_PTR(self_in);
if (has_attr(self->ref, "then")) {
#if MICROPY_PY_ASYNCIO
// When asyncio is running and the caller here is a task, wrap the JavaScript
// thenable in a ThenableEvent, and get the task to wait on that event. This
// decouples the task from the thenable and allows cancelling the task.
if (mp_asyncio_context != MP_OBJ_NULL) {
mp_obj_t cur_task = mp_obj_dict_get(mp_asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_cur_task));
if (cur_task != mp_const_none) {
mp_obj_t thenable_event_class = mp_obj_dict_get(mp_asyncio_context, MP_OBJ_NEW_QSTR(MP_QSTR_ThenableEvent));
mp_obj_t thenable_event = mp_call_function_1(thenable_event_class, self_in);
mp_obj_t dest[2];
mp_load_method(thenable_event, MP_QSTR_wait, dest);
mp_obj_t wait_gen = mp_call_method_n_kw(0, 0, dest);
return mp_getiter(wait_gen, iter_buf);
}
}
#endif
return jsproxy_new_gen(self_in, iter_buf);
} else {
return jsproxy_new_it(self_in, iter_buf);

Wyświetl plik

@ -296,11 +296,10 @@ EM_JS(void, js_then_resolve, (uint32_t * ret_value, uint32_t * resolve, uint32_t
resolve_js(ret_value_js);
});
EM_JS(void, js_then_reject, (uint32_t * ret_value, uint32_t * resolve, uint32_t * reject), {
const ret_value_js = proxy_convert_mp_to_js_obj_jsside(ret_value);
EM_JS(void, js_then_reject, (uint32_t * resolve, uint32_t * reject), {
const resolve_js = proxy_convert_mp_to_js_obj_jsside(resolve);
const reject_js = proxy_convert_mp_to_js_obj_jsside(reject);
reject_js(ret_value_js);
reject_js(null);
});
// *FORMAT-OFF*
@ -308,34 +307,14 @@ EM_JS(void, js_then_continue, (int jsref, uint32_t * py_resume, uint32_t * resol
const py_resume_js = proxy_convert_mp_to_js_obj_jsside(py_resume);
const resolve_js = proxy_convert_mp_to_js_obj_jsside(resolve);
const reject_js = proxy_convert_mp_to_js_obj_jsside(reject);
const ret = proxy_js_ref[jsref].then(
(result) => {
// The Promise is fulfilled on the JavaScript side. Take the result and
// send it to the encapsulating generator on the Python side, so it
// becomes the result of the "yield from" that deferred to this Promise.
py_resume_js(result, null, resolve_js, reject_js);
},
(reason) => {
// The Promise is rejected on the JavaScript side. Take the reason and
// throw it into the encapsulating generator on the Python side.
py_resume_js(null, reason, resolve_js, reject_js);
},
);
const ret = proxy_js_ref[jsref].then((x) => {py_resume_js(x, resolve_js, reject_js);}, reject_js);
proxy_convert_js_to_mp_obj_jsside(ret, out);
});
// *FORMAT-ON*
static mp_obj_t proxy_resume_execute(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t resolve, mp_obj_t reject) {
if (throw_value != MP_OBJ_NULL && throw_value != mp_const_none) {
if (send_value == mp_const_none) {
send_value = MP_OBJ_NULL;
}
} else {
throw_value = MP_OBJ_NULL;
}
static mp_obj_t proxy_resume_execute(mp_obj_t self_in, mp_obj_t value, mp_obj_t resolve, mp_obj_t reject) {
mp_obj_t ret_value;
mp_vm_return_kind_t ret_kind = mp_resume(self_in, send_value, throw_value, &ret_value);
mp_vm_return_kind_t ret_kind = mp_resume(self_in, value, MP_OBJ_NULL, &ret_value);
uint32_t out_resolve[PVN];
uint32_t out_reject[PVN];
@ -356,19 +335,17 @@ static mp_obj_t proxy_resume_execute(mp_obj_t self_in, mp_obj_t send_value, mp_o
uint32_t out[PVN];
js_then_continue(ref, out_py_resume, out_resolve, out_reject, out);
return proxy_convert_js_to_mp_obj_cside(out);
} else { // ret_kind == MP_VM_RETURN_EXCEPTION;
// Pass the exception through as an object to reject the promise (don't raise/throw it).
uint32_t out_ret_value[PVN];
proxy_convert_mp_to_js_obj_cside(ret_value, out_ret_value);
js_then_reject(out_ret_value, out_resolve, out_reject);
return mp_const_none;
} else {
// MP_VM_RETURN_EXCEPTION;
js_then_reject(out_resolve, out_reject);
nlr_raise(ret_value);
}
}
static mp_obj_t resume_fun(size_t n_args, const mp_obj_t *args) {
return proxy_resume_execute(args[0], args[1], args[2], args[3], args[4]);
return proxy_resume_execute(args[0], args[1], args[2], args[3]);
}
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(resume_obj, 5, 5, resume_fun);
static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(resume_obj, 4, 4, resume_fun);
void proxy_c_to_js_resume(uint32_t c_ref, uint32_t *args) {
nlr_buf_t nlr;
@ -376,7 +353,7 @@ void proxy_c_to_js_resume(uint32_t c_ref, uint32_t *args) {
mp_obj_t obj = proxy_c_get_obj(c_ref);
mp_obj_t resolve = proxy_convert_js_to_mp_obj_cside(args + 1 * 3);
mp_obj_t reject = proxy_convert_js_to_mp_obj_cside(args + 2 * 3);
mp_obj_t ret = proxy_resume_execute(obj, mp_const_none, mp_const_none, resolve, reject);
mp_obj_t ret = proxy_resume_execute(obj, mp_const_none, resolve, reject);
nlr_pop();
return proxy_convert_mp_to_js_obj_cside(ret, args);
} else {

Wyświetl plik

@ -1,24 +0,0 @@
# The asyncio package is built from the standard implementation but with the
# core scheduler replaced with a custom scheduler that uses the JavaScript
# runtime (with setTimeout an Promise's) to contrtol the scheduling.
package(
"asyncio",
(
"event.py",
"funcs.py",
"lock.py",
),
base_path="$(MPY_DIR)/extmod",
opt=3,
)
package(
"asyncio",
(
"__init__.py",
"core.py",
),
base_path="$(PORT_DIR)",
opt=3,
)

Wyświetl plik

@ -1,5 +1,3 @@
include("$(PORT_DIR)/variants/manifest.py")
require("abc")
require("base64")
require("collections")

Wyświetl plik

@ -587,12 +587,6 @@
/*****************************************************************************/
/* Python internal features */
// Use a special long jump in nlrthumb.c, which may be necessary if nlr.o and
// nlrthumb.o are linked far apart from each other.
#ifndef MICROPY_NLR_THUMB_USE_LONG_JUMP
#define MICROPY_NLR_THUMB_USE_LONG_JUMP (0)
#endif
// Whether to enable import of external modules
// When disabled, only importing of built-in modules is supported
// When enabled, a port must implement mp_import_stat (among other things)

Wyświetl plik

@ -38,14 +38,6 @@
__attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) {
// If you get a linker error here, indicating that a relocation doesn't
// fit, try the following (in that order):
//
// 1. Ensure that nlr.o nlrthumb.o are linked closely together, i.e.
// there aren't too many other files between them in the linker list
// (PY_CORE_O_BASENAME in py/py.mk)
// 2. Set -DMICROPY_NLR_THUMB_USE_LONG_JUMP=1 during the build
//
__asm volatile (
"str r4, [r0, #12] \n" // store r4 into nlr_buf
"str r5, [r0, #16] \n" // store r5 into nlr_buf
@ -79,7 +71,7 @@ __attribute__((naked)) unsigned int nlr_push(nlr_buf_t *nlr) {
"str lr, [r0, #8] \n" // store lr into nlr_buf
#endif
#if MICROPY_NLR_THUMB_USE_LONG_JUMP
#if !defined(__thumb2__)
"ldr r1, nlr_push_tail_var \n"
"bx r1 \n" // do the rest in C
".align 2 \n"

Wyświetl plik

@ -1,44 +0,0 @@
// Test asyncio.create_task(), and tasks waiting on a Promise.
const mp = await (await import(process.argv[2])).loadMicroPython();
globalThis.p0 = new Promise((resolve, reject) => {
resolve(123);
});
globalThis.p1 = new Promise((resolve, reject) => {
setTimeout(() => {
console.log("setTimeout resolved");
resolve(456);
}, 200);
});
mp.runPython(`
import js
import asyncio
async def task(id, promise):
print("task start", id)
print("task await", id, await promise)
print("task await", id, await promise)
print("task end", id)
print("start")
t1 = asyncio.create_task(task(1, js.p0))
t2 = asyncio.create_task(task(2, js.p1))
print("t1", t1.done(), t2.done())
print("end")
`);
// Wait for p1 to fulfill so t2 can continue.
await globalThis.p1;
// Wait a little longer so t2 can complete.
await new Promise((resolve, reject) => {
setTimeout(resolve, 10);
});
mp.runPython(`
print("restart")
print("t1", t1.done(), t2.done())
`);

Wyświetl plik

@ -1,14 +0,0 @@
start
t1 False False
end
task start 1
task start 2
task await 1 123
task await 1 123
task end 1
setTimeout resolved
task await 2 456
task await 2 456
task end 2
restart
t1 True True

Wyświetl plik

@ -1,25 +0,0 @@
// Test asyncio.sleep(), both at the top level and within a task.
const mp = await (await import(process.argv[2])).loadMicroPython();
await mp.runPythonAsync(`
import time
import asyncio
print("main start")
t0 = time.time()
await asyncio.sleep(0.25)
dt = time.time() - t0
print(0.2 <= dt <= 0.3)
async def task():
print("task start")
t0 = time.time()
await asyncio.sleep(0.25)
dt = time.time() - t0
print(0.2 <= dt <= 0.3)
print("task end")
asyncio.create_task(task())
print("main end")
`);

Wyświetl plik

@ -1,6 +0,0 @@
main start
True
main end
task start
True
task end

Wyświetl plik

@ -681,17 +681,6 @@ def run_tests(pyb, tests, args, result_dir, num_threads=1):
elif args.target == "webassembly":
skip_tests.add("basics/string_format_modulo.py") # can't print nulls to stdout
skip_tests.add("basics/string_strip.py") # can't print nulls to stdout
skip_tests.add("extmod/asyncio_basic2.py")
skip_tests.add("extmod/asyncio_cancel_self.py")
skip_tests.add("extmod/asyncio_current_task.py")
skip_tests.add("extmod/asyncio_exception.py")
skip_tests.add("extmod/asyncio_gather_finished_early.py")
skip_tests.add("extmod/asyncio_get_event_loop.py")
skip_tests.add("extmod/asyncio_heaplock.py")
skip_tests.add("extmod/asyncio_loop_stop.py")
skip_tests.add("extmod/asyncio_new_event_loop.py")
skip_tests.add("extmod/asyncio_threadsafeflag.py")
skip_tests.add("extmod/asyncio_wait_for_fwd.py")
skip_tests.add("extmod/binascii_a2b_base64.py")
skip_tests.add("extmod/re_stack_overflow.py")
skip_tests.add("extmod/time_res.py")