gudzpoz / luajava

Lua for Java on Windows, Mac OS X, Linux, Android. 5.1, 5.2, 5.3, 5.4, LuaJ or LuaJIT.
https://gudzpoz.github.io/luajava/
Other
122 stars 14 forks source link

How do call coroutine.yield() from java #158

Closed orange451 closed 5 months ago

orange451 commented 5 months ago

I am trying to make a set of nice sandboxed functions to play around with in lua, but controlled from java.

To start, I want to create a wait() function, which yields the current coroutine for a given amount of time, then resumes. I want this to be controlled from Java side, so that there is no additional lua code that needs to be defined for each script that runs. My current implementation looks like this:

            main_env.register("wait", (env)-> {
                // Get input
                double sleepTimeSeconds = (double) env.get().toJavaObject();

                // Tell scheduler to wake back up later
                long sleepTimeMillis = (long) (sleepTimeSeconds * 1000);
                scheduler.add(new LuaJavaThreadYield(env, System.currentTimeMillis() + sleepTimeMillis));

                // yield the coroutine
                long timeNow = System.currentTimeMillis();
                env.getGlobal("coroutine");
                env.getField(-1, "yield");
                System.out.println("Output: " + env.pCall(0, 1) + " " + env.toString(-1));

                // return how much time passed
                long elapsed = System.currentTimeMillis() - timeNow;
                env.push(elapsed/1000d);
                return 1;
            });

However, this produces the following error:

attempt to yield across a C-call boundary

Is there any way to achieve this? It would be very nice in my project to just be able to write lua like this:

print("Test1")
wait(1)
print("Test2")
orange451 commented 5 months ago

Sorry if this is supposed to go in "Discussions" section.

gudzpoz commented 5 months ago

No, you can't call coroutine.yield() from Java. To yield from a coroutine, Lua needs to somehow save the whole calling stack in order to restore execution afterwards. Since it has no idea about C stack or Java stacks, it cannot save them without possibly crashing the whole program, and thus calling from C (or Java) is prohibited by Lua. You may still achieve what you want with a bit of additional lua code of course, e.g., function wait(sec) coroutine.yield("wait", sec) end (whose yielded values may then be processed by your scheduler calling coroutine.resume, which can be in pure Java).