Skip to content

Commit 7ba45e6

Browse files
TaskManager: without new thread works but blocks REPL
aiorepl (asyncio REPL) works but it's pretty limited It's probably fine for production, but it means the user has to sys.exit() in aiorepl before landing on the real interactive REPL, with asyncio tasks stopped.
1 parent c0b9f68 commit 7ba45e6

File tree

4 files changed

+44
-14
lines changed

4 files changed

+44
-14
lines changed

internal_filesystem/builtin/apps/com.micropythonos.appstore/assets/appstore.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,10 +130,14 @@ async def download_icons(self):
130130
print("Downloading icons...")
131131
for app in self.apps:
132132
if not self.has_foreground():
133-
print(f"App is stopping, aborting icon downloads.")
133+
print(f"App is stopping, aborting icon downloads.") # maybe this can continue? but then update_ui_threadsafe is needed
134134
break
135-
#if not app.icon_data:
136-
app.icon_data = await self.download_url(app.icon_url)
135+
if not app.icon_data:
136+
try:
137+
app.icon_data = await TaskManager.wait_for(self.download_url(app.icon_url), 5) # max 5 seconds per icon
138+
except Exception as e:
139+
print(f"Download of {app.icon_url} got exception: {e}")
140+
continue
137141
if app.icon_data:
138142
print("download_icons has icon_data, showing it...")
139143
image_icon_widget = None
@@ -146,7 +150,7 @@ async def download_icons(self):
146150
'data_size': len(app.icon_data),
147151
'data': app.icon_data
148152
})
149-
self.update_ui_threadsafe_if_foreground(image_icon_widget.set_src, image_dsc) # error: 'App' object has no attribute 'image'
153+
self.update_ui_threadsafe_if_foreground(image_icon_widget.set_src, image_dsc) # add update_ui_threadsafe() for background?
150154
print("Finished downloading icons.")
151155

152156
def show_app_detail(self, app):
@@ -156,7 +160,7 @@ def show_app_detail(self, app):
156160

157161
async def download_url(self, url):
158162
print(f"Downloading {url}")
159-
#await TaskManager.sleep(1)
163+
#await TaskManager.sleep(4) # test slowness
160164
try:
161165
async with self.aiohttp_session.get(url) as response:
162166
if response.status >= 200 and response.status < 400:

internal_filesystem/lib/mpos/main.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,6 @@ def custom_exception_handler(e):
7272
# This will throw an exception if there is already a "/builtin" folder present
7373
print("main.py: WARNING: could not import/run freezefs_mount_builtin: ", e)
7474

75-
mpos.TaskManager()
76-
7775
try:
7876
from mpos.net.wifi_service import WifiService
7977
_thread.stack_size(mpos.apps.good_stack_size())
@@ -89,11 +87,31 @@ def custom_exception_handler(e):
8987
if auto_start_app and launcher_app.fullname != auto_start_app:
9088
mpos.apps.start_app(auto_start_app)
9189

92-
if not started_launcher:
93-
print(f"WARNING: launcher {launcher_app} failed to start, not cancelling OTA update rollback")
94-
else:
90+
# Create limited aiorepl because it's better than nothing:
91+
import aiorepl
92+
print("Starting very limited asyncio REPL task. Use sys.exit() to stop all asyncio tasks and go to real REPL...")
93+
mpos.TaskManager.create_task(aiorepl.task()) # only gets started when mpos.TaskManager() is created
94+
95+
async def ota_rollback_cancel():
9596
try:
9697
import ota.rollback
9798
ota.rollback.cancel()
9899
except Exception as e:
99100
print("main.py: warning: could not mark this update as valid:", e)
101+
102+
if not started_launcher:
103+
print(f"WARNING: launcher {launcher_app} failed to start, not cancelling OTA update rollback")
104+
else:
105+
mpos.TaskManager.create_task(ota_rollback_cancel()) # only gets started when mpos.TaskManager() is created
106+
107+
while True:
108+
try:
109+
mpos.TaskManager() # do this at the end because it doesn't return
110+
except KeyboardInterrupt as k:
111+
print(f"mpos.TaskManager() got KeyboardInterrupt, falling back to REPL shell...") # only works if no aiorepl is running
112+
break
113+
except Exception as e:
114+
print(f"mpos.TaskManager() got exception: {e}")
115+
print("Restarting mpos.TaskManager() after 10 seconds...")
116+
import time
117+
time.sleep(10)

internal_filesystem/lib/mpos/task_manager.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@ class TaskManager:
88

99
def __init__(self):
1010
print("TaskManager starting asyncio_thread")
11-
_thread.stack_size(mpos.apps.good_stack_size()) # tiny stack size of 1024 is fine for tasks that do nothing but for real-world usage, it needs more
12-
_thread.start_new_thread(asyncio.run, (self._asyncio_thread(), ))
11+
# tiny stack size of 1024 is fine for tasks that do nothing
12+
# but for real-world usage, it needs more:
13+
#_thread.stack_size(mpos.apps.good_stack_size())
14+
#_thread.start_new_thread(asyncio.run, (self._asyncio_thread(100), ))
15+
asyncio.run(self._asyncio_thread(10)) # this actually works, but it blocks the real REPL (aiorepl works, but that's limited)
1316

14-
async def _asyncio_thread(self):
17+
async def _asyncio_thread(self, ms_to_sleep):
1518
print("asyncio_thread started")
1619
while True:
1720
#print("asyncio_thread tick")
18-
await asyncio.sleep_ms(100) # This delay determines how quickly new tasks can be started, so keep it below human reaction speed
21+
await asyncio.sleep_ms(ms_to_sleep) # This delay determines how quickly new tasks can be started, so keep it below human reaction speed
1922
print("WARNING: asyncio_thread exited, this shouldn't happen because now asyncio.create_task() won't work anymore!")
2023

2124
@classmethod
@@ -38,3 +41,7 @@ def sleep(s):
3841
@staticmethod
3942
def notify_event():
4043
return asyncio.Event()
44+
45+
@staticmethod
46+
def wait_for(awaitable, timeout):
47+
return asyncio.wait_for(awaitable, timeout)

internal_filesystem/lib/mpos/ui/topmenu.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import lvgl as lv
22

33
import mpos.ui
4+
import mpos.time
45
import mpos.battery_voltage
56
from .display import (get_display_width, get_display_height)
67
from .util import (get_foreground_app)

0 commit comments

Comments
 (0)