Left here for archival purposes.

User avatar
By dromic
#24717 Hi,

I noticed a little bug regarding uart.on function, here's a code snippet demonstrating it

Code: Select alllocal function func(data)
   print(coroutine.status(active_thread))
   if data:find("stop") then
      print(coroutine.resume(active_thread))
   end
end


-- helper to successfuly restore the first thread
local function uart_helper()
   uart.on("data", "\r", func, 1)
end


-- function that can resume
local function good_function()
   local helper_thread = coroutine.create(uart_helper)
   coroutine.resume(helper_thread)
   coroutine.yield()
   print("this is good_function and i'm going back to main_thread")
   coroutine.resume(main_thread)
end


-- broken function which will report that it is already alive when attempted to resume
local function broken_function()
   uart.on("data", "\r", func, 1)
   coroutine.yield()
   print("this is broken_function and i'm going back to main_thread")
   coroutine.resume(main_thread)
end



function main()
   first_thread = coroutine.create(good_function)
   second_thread = coroutine.create(broken_function)
   
   active_thread = first_thread
   print("i'm starting the first_thread using good_function")
   coroutine.resume(first_thread)
   coroutine.yield()
   print("im back from first_thread using good_function")
   
   active_thread = second_thread
   print("i'm starting the second_thread using broken_function")
   coroutine.resume(second_thread)
   coroutine.yield()
   print("i'm back from second_thread using broken_function")
end

main_thread = coroutine.create(main)
return main_thread


this starts two threads, one wraps the uart.on function in another (third) thread, the other calls it in itself. On uart event, the callback function (func) prints out the coroutine.status of the currently active thread and if the user wrote "stop" in the interpreter it resumes the thread and returns back to main thread. The interesting part is that the uart.on function misrepresents the status of the second thread as it reports it to be "running" on every uart event, and thus fails to resume it:

Code: Select all> =stop
running
false   cannot resume running coroutine


whereas if you ask the interpreter it will report "suspended"

Code: Select all> =coroutine.status(active_thread)
running -- response from uart.on callback
suspended -- response from interpreter



here's the entire serial input/output

Code: Select all> coroutine.resume(dofile("test.lua"))
i'm starting the first_thread using good_function
> =
suspended
> =
suspended
> =coroutine.status(active_thread)
suspended
suspended
> =stop
suspended
this is good_function and i'm going back to main_thread
im back from first_thread using good_function
i'm starting the second_thread using broken_function
true
nil
> =
running
> =
running
> =coroutine.status(active_thread)
running
suspended
> =
running
> =stop
running
false   cannot resume running coroutine
nil
> =coroutine.resume(active_thread)
running
this is broken_function and i'm going back to main_thread
i'm back from second_thread using broken_function
true
> =
running
> =
running
> =coroutine.status(active_thread)
running
dead
>


The lines prefixed by prompt, >, are user input.
The version of the firmware is nodemcu_integer_0.9.6-dev_20150704

I suspect that other event driven functions, such as conn:on, might behave similarly, but I haven't tested it yet.
User avatar
By TerryE
#24852 The Lua coroutine paradigm and the SDK task/event paradigm cut across each other. I am not event sure that nodeMCU libraries have been properly tested to be Lua state reentrant. There be demons down this path!

Honestly I'd stay away from using coroutining. It's a guaranteed way of shooting yourself in the foot.
User avatar
By dromic
#25353 I completely agree, however, the task was sending something via UART and then doing something with the response (from a 3rd device), I didn't find a better way than to yield from a coroutine and then wait for it to be resumed by the uart.on. Any thoughts?

That being said, so far the workaround (wrapping the uart.on in its own coroutine) works great.