-
Notifications
You must be signed in to change notification settings - Fork 3.1k
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
Lua 5.1 to 5.3 realignement phase 1 #2836
Conversation
And the Pipe version of the telnet server. This one is actually usable. I was pasting the following to test out the marshalling r=debug.getregistry()
function list(name, t)
if #name < 15 and (name == '_G' or t ~= _G) then
print(name,t)
for k,v in pairs(t) do
local name = name..'.'..k
if type(v):sub(-5) == 'table' and name:sub(1,8) ~= '_G.r.std' then
list(name, v)
else
print(name,v)
end
end
end
end
list("_G",_G) It kept running out of memory, until I twigged was also enumerating |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Phew! That's a lot of changes!
Over all looks really good! There are a few serious questions I have (in the comments above), but for the most part the comments are for grunt-work cleanup.
The input handling of course looks different on the esp32, but there's nothing here that makes me concerned that it'll cause issues on that side. A bit of integration work and platform adjustments, but should be pretty easy (famous last words, I know).
|
||
/**DEBUG**/extern void dbg_printf(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); | ||
|
||
static void input_handler(platform_task_param_t flag, uint8 priority); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
task_prio_t
?
app/driver/input.c
Outdated
|
||
/* | ||
** input_handler at high-priority is a system post task used to process pending Rx | ||
** data on UART0. The flag is used as a latch to stops the interrupt handler posting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/stops/stop/
int lua_main (void); | ||
static bool input_readline(void); | ||
|
||
static void input_handler(platform_task_param_t flag, uint8 priority) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
task_prio_t
lua_main(); | ||
return; | ||
} | ||
ins.input_sig_flag = flag & 0x1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd quite prefer a symbolic name here. Even if the lack of one is my fault so far >.>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's now a 0/1 field so this is once where I think that a symbolic isn't really needed.
static void input_handler(platform_task_param_t flag, uint8 priority) { | ||
(void) priority; | ||
if (!ins.data) { | ||
lua_main(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the advantage of doing the init here, rather than when establishing this task handler?
** Note that pipes also support the undocumented length and tostring operators | ||
** for debugging puposes, so if p is a pipe then #p[1] gives the effective | ||
** length of pipe slot 1 and printing p[1] gives its contents | ||
** Note that pipe tables also support the undocumented length and tostring |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it's no longer undocumented! ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documented as in readthedocs general documentation. Anyone reading this is digging around in the pipe internals anyway.
#define CB_QUIESCENT 4 | ||
/* | ||
** Note that nothing precludes the Lua CB function from itself writing to the | ||
** pipe and in this case this routine will call itself recursively. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Recursively, or merely retasking itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Recursively vs retasking. I leave it to you to propose alternative wording.
The real point here was that node.output() used to be a minefield as it was really breaking the VM architectural assumptions in that the print base function was never intended to embed a Lua CB, so doing a print
inside this Lua CB code could trash the whole runtime environment and PANIC the processor.
Because the output interface now uses pipes and the tasking mechanism we now comply with the architecture and there is actually nothing stopping the output CB doing a print.
lua_rawgeti(L, LUA_REGISTRYINDEX, uart_receive_rf); | ||
lua_pushlstring(L, buf, len); | ||
lua_call(L, 1, 0); | ||
return !run_input; | ||
luaN_call(L, 1, 0, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So here for example, I believe if the call fails we've just littered the stack with an error message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This actually touches on a more systemic issue in that all CB action routines should always balance the stack from entry to return but we don't have any guidance / quality check / coding pattern to ensure this and failure to do so leads to resource leakage that will ultimately exhaust memory. We need to address this wider issue, IMO.
However as to this specific point, we need to decide the stack rules for luaN_call()
. IMO we have two options:
- It follows the
lua_pcall()
convention of returning 1 argument and an error status if the called routine throws an error, or - It dummies the
lua_call()
of returningnresults
arguments (which might be nil in the case of an error) and an error status.
IIRC, there only one use in the modules library where the library routine accepts any result from the Lua CB, and all that typically happens is that the wrapper function returns control to the SDK on return from the CB. I think that we should go for easy of migration to luaN_call()
and that adopting option 2 will best achieve this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My vote would be for #2 as well. If there are any instances where a module is actually interested in the error message, they can use lua_pcall()
for that. For everyone else, I think the simplicity of lua_call()
behaviour will give us the most robust outcome.
app/modules/uart.c
Outdated
{ | ||
need_len = ( uint16_t )luaL_checkinteger( L, stack ); | ||
data_len = luaL_checkinteger( L, stack ); | ||
luaL_argcheck(L, data_len >= 0 && data_len <= 255, stack, "wrong arg range"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not LUA_MAXINPUT
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dunno. Ask Zeroday why he used 255. All I did was to recode the existing validation logic to use luaL_argcheck()
whilst getting rid of some warnings.
The actual UART input buffer is allocated with input_setup()
and this is called in lua.c
using LUA_MAXINPUT
so I agree that this would be a better symbolic value. So updated.
app/modules/uart.c
Outdated
if (lua_type(L, stack) == LUA_TFUNCTION || lua_type(L, stack) == LUA_TLIGHTFUNCTION){ | ||
if ( lua_isnumber(L, stack+1) ){ | ||
run = lua_tointeger(L, stack+1); | ||
if (lua_isfunction(L, stack) || lua_islightfunction(L, stack)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe you added a nice lua_isanyfunction(L, stack)
macro above.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup, but I'll be doing all of these as a separate sweep.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted. And thumbs up.
Oh, and Travis is unhappy with you. :) |
@jmattsson, you can blame @marcelstoer and @galjonsfigur and #2790 for this one 😄 This does a As to your other comments, I will go through them and do a separate consolidated reply for most as this will probably be the most readable for you and others. |
@TerryE I just looked at the Travis log and lint check does not break the build - it only spills lots of warnings, but because of
|
Reasoning behind some of these changes:
I'll fix the minor review points that you also picked up. Thanks :) |
When Travis is happy, I'll be happy. This is a very nice (and large) improvement - thanks for all the work Terry! |
Thanks Jonny for all of the feedback. I've tried to action most of your comments except for a few where I've given my reasons. As I say in the title, this is only phase 1. We've got a few more steps to go. However now that you've taken off #2838, I'll be pausing further work here until #2838 is landed and then I can rebase this against the new However as a general comment we've had 3 committers contributing to this review and one other monitoring on the sidelines, so unless any of the others chip in with objections, I now view this broadly acceptable as a general canon of work, so I will round this off and merge it in immediately after the next master drop. |
These changes look good and are a significant step forward. Thanks a lot Terry! Can't formally approve atm with the android client here 😐 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
I've just rebaselined against the current |
@jmattsson @devsaurus @nwf, I have another big batch of changes pending tidying up the modules. I suspect that it is going to be another couple of weeks before we eventually do the next master drops and are positioned to merge this PR. That will mean another month before we also review and do the module changes as well. Would there be any advantage also to rolling in the module changes into this PR? That way we can drop a couple of weeks from the timeline. |
Why? Most issues in https://github.com/nodemcu/nodemcu-firmware/milestone/13 are either completed or close to completion. If it's any help we can drop some PRs from the milestone and snap to master next week. What's your preference? |
Marcel whenever you, Gregor and Nathaniel can make the cut ... but if these are joined, then I can roll on the prep work. It's really up to the reviews as to whether they think this rolled up patch will be too big to review. |
I'd prefer a second PR for the next round of clean-up, it'd be a lot easier to review. Nothing stopping you from just branching off from this PR branch and continuing work though. |
OK will do it that way. Just have to rebase twice. |
Might not need any more rebasing. This one is looking all green at the moment, so unless there's something conflicting going in soon it should just be a couple of squash-n-merges :) |
I've got my |
@TerryE can you please update or close all the referenced issues if necessary. |
On my TODO list 😄 |
Done. #2808 carried forward to next PR. All others are closed. |
See #2033, #2787 #2802 #2803 #2808 and #2823
dev
branch rather than formaster
.docs/*
.Overview
My aim here is to make the
app/lua53
interface with the platform and other libraries as clean as possible, and since all of the other directories are going to be shared, it is just simpler to backport this tidying into theapp/lua
code hierarchy. This PR makes the first tranche of these changes to achieve this alignment.This has ended up pretty large change and it does change the feel of the Lua interpreter:
Detailed changes
lua/lua.c
. Strip out all dead code left over from the eLua and core versions but not used in NodeMCU (e.g standard Lua supports command line arguments but we don't use them so there's no point in having all of these argument decoding functions. Tidy up how startup and how the input loop is handled using the task interface. (Pasting bulk content into Putty etc. not longer overruns the input buffer).app/lua/lnodemcu.c
. The NodeMCU extensions to the Lua API are now located in 3 API files:lflash.c
for LFS (lauN_*()
calls),lrotables.c
for ROTables (lauF_*()
calls) andlnodemcu.c
for other extension (for otherlauN_*()
calls). The current items in this last category include Lua task handling and catch-all panic handling. The newluaN_call()
variant establishes a PANIC call handler that usesluaN_posttask()
to send the error traceback to the stdout pipe. Note that the error reporter defaults to using the baseprint
function to send the error to stdout, but I plan add anode.setatpanic()
API call in a subsuquent PR to allow production system to establish an alternative logging function for logging such panic errors.lua/lua.h
. Add entries forluaN_posttask()
andluaN_call()
as these functions are used as part of the core Lua VM. New any variantslua_isanyfunction(L,n)
andlua_isanytable(L,n)
to hide the type test differences between the Lua 5.1 and 5.3 APIs. (Note that these are used inpipe.c
anduart.c
, but will also be adopted in a later PR for all modules.)lua/lbaselib.c
. Stderr-type errors now use the baseprint
function and this callsc_puts()
rather thandbg_printf()
as the latter is really only for debugging and bypassesnode.output()
redirection. (It was this change to usedbg_printf()
that broke telnet).Task Library. This functionality has now been moved into the platform core. See RFC Why have different coding standards for ESP32 and EP8266 modules? #2811 (comment) for background to this. Note that I have temproarily retained a
task.h
header that remaps the old interface to the platform calling conventions so that modules using the task interface don't need recoding except that the modules that use the taksk inferface have the#include "task.h"
hoisted in the include order. TheluaX_
functions now include the Lua call interface.app/module/pipe.c
add the ability to bind a Lua CB function atpipe.create()
to read and empty the pipe.app/module/node.c
thenode.output()
function now takes a piper reader as an argument. The field output writes to astdout
pipe and the output reader is now executed as a separate task. This means thatnode.output()
works fine from the interactive session and thestdin
andstdout
pipes handle of the field marshalling automatically.Make for
lua
now includes-Wall
plus minor fixes to lua files to remove-Wall
warnings. The one non-trivial change here is thatapp/platform/vfs.h
previously usedstatic
declarations in this header which genrated compiler warnings when these should should have beenstatic inline
. Plus thelflash.c
changes also picked up by Johny on theesp32
branch. Also includes fixing some operator precedence issues because of lack of extra guard parentheses in some define macros indriver/rotary.c
anddriver/spi.c
Move the driver file
receive.c
toinput.c
plus enchancements, and ditto for its header. The old file didn't actually do the UART receive handling as this had been moved intolua.c
. I've moved the receive handling back and since it does all of the line input handling for the UART0, I decided to rename it toinput.c
as this better reflects its purpose.The driver file
uart.c
has had its initialisation binding split into two parts:uart_init()
which is called fromuser_main.c
anduart_init_task()
which is called from theinput.c
driver as part of Lua startup to enable input delivery..gdbinit some minor enhancements to this remote GDB macro set fro API developers
Notes
This is a large change because of all of the interdependencies. I suggest we flush out the pending PRs that we want to do in the next master drop, and merge this immediately after.