Skip to content
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

Callbacks? #58

Closed
EToreo opened this issue Apr 15, 2016 · 14 comments
Closed

Callbacks? #58

EToreo opened this issue Apr 15, 2016 · 14 comments

Comments

@EToreo
Copy link

EToreo commented Apr 15, 2016

I don't know where to ask this, please point me to a better location if you are offended having it here.

I have been trying to introduce myself to binding my own functions into lua. I have a (from what I can tell) very complicated end-goal read on StackOverflow if interested.

I need to be able to take a callback from lua so I can do asynchronous things before passing back into lua with a result.

// works great
lua.set_function("print", [](const char *  y){ std::cout << y << std::endl; });

// what I need and don't know how to do...
lua.set_function("getUser", [](int id, luaFncPointer cb)
{
/* ... */
// async operation on database, io, etc.
/* ... */
 });
-- user written lua script
getUser(1, function(err, user)
   if err then
      print('Error', err)
   else
      print('Found user with id', user.id)
   end
end)

Do you have some examples I could look at or suggestions on what to do?

@ThePhD
Copy link
Owner

ThePhD commented Apr 15, 2016

You can replace luaFncPointer cb with one of 2 types: std::function<ReturnType(Arguments...)> OR sol::function. sol::function is the most flexible (can pass it different number of args and stuff, while std::function has a fixed signature).

Code would look like...

lua.set_function("print", [](const char *  y){ std::cout << y << std::endl; });
lua.set_function("getUser", [](int id, sol::function cb)
{
/* ... */
cb( 24, some_ptr, ... ); // whatever you like
/* ... */
 });

Sorry about not having a place this is clear: I gotta pump up the docs to be a LOT more specific with this stuff so that people get the proper guidance.

@EToreo
Copy link
Author

EToreo commented Apr 15, 2016

This is great! But how do I return null or empty to the first argument of the lua callback?

lua.set_function("getUser", [](int id, sol::function cb)
{
    cb(NULL, "THE USER");
});

@ThePhD
Copy link
Owner

ThePhD commented Apr 15, 2016

NULL is a macro from the C standard that, in C++, usually resolves to 0. This will push an integer, which isn't what you want: try doing cb( sol::nil, "THE USER" ) or cb( nullptr, "THE USER" )

@EToreo
Copy link
Author

EToreo commented Apr 15, 2016

Thank you!

@EToreo EToreo closed this as completed Apr 15, 2016
@EToreo
Copy link
Author

EToreo commented Apr 15, 2016

Will sol::function take ellipsis?

@ThePhD
Copy link
Owner

ThePhD commented Apr 16, 2016

No, it won't take ellipses, but you can feed it as many arguments as you like.

@EToreo
Copy link
Author

EToreo commented Apr 29, 2016

@ThePhD Thanks for all your help. I'm really enjoying your library. I have one more big question for you...

I am trying to call a sol::function callback from an asynchronous thread. My lua.set_function("getUser" [&](int id, sol::function gotUserDataCb {...}) has to asynchronously ask nodejs for some information, and in that response (using uv_queue_work, uv_after_work_cb, etc) I need to execute gotUserDataCb passing the data I received on the worker thread. My issue is: that causes a segmentation fault. I think this is because the sol::state goes out of scope long before getUser tries to respond.

Do you have any tips here? Am I on the correct track, should I try to find a way to keep the sol::state from going out of scope (make it a pointer and manually delete it)?

@ThePhD
Copy link
Owner

ThePhD commented Apr 29, 2016

You need to shift the lifetime of the sol::state you set that function on. Move its scope up your application's stack a bit, so it will last. Make it a shared_ptr if you really need to keep it alive. There's no reason to manually track the lieftime with those kind of tools.

@EToreo
Copy link
Author

EToreo commented Apr 29, 2016

I took your suggestion and made it a shared pointer (moving the sol::state up in scope can't be done in my case). I am now getting an exception thrown from sol->script:

terminate called after throwing an instance of 'sol::error'
what(): lua: error: attempt to call a nil value

(The lua script is the same as the original posting in this issue.)

@ThePhD
Copy link
Owner

ThePhD commented Apr 29, 2016

That could happen from a number of things. I have no idea what would be the problem, and I'm not sure I can reason about how your entire application stack sets up things.

@EToreo
Copy link
Author

EToreo commented Apr 30, 2016

Fair enough. I think the problem is that the actually sol::function gotUserDataCb is being called after lua->script is done executing. Is there a lua lock offered by sol? I have head mention of locking and unlocking in other discussions about lua hooks.

@EToreo
Copy link
Author

EToreo commented May 2, 2016

@ThePhD hey, I just wanted to say thank you. I got where I needed to go with the help of your library and advice. To solve the last problem I was having I had to implement lua_lock and lua_unlock in a custom lua build and bind that custom built lua library and header files into my program along with sol2. I now have a fully functioning bridge between nodejs and lua.

@ThePhD
Copy link
Owner

ThePhD commented May 2, 2016

Nice! If you think there's a nice way to do lua_lock that can be added to sol2, feel free to open up another Bikeshed issue.

@EToreo
Copy link
Author

EToreo commented May 2, 2016

I appreciate your willingness but I doubt there is a way to do this. The lua team seems adamant that tread locking be a custom modification and build. The locking and unlocking functions are not even public, they expect you to modify the lua internal lua_state struct and interact with your modification. So, I really don't think there is a way to wrap customization like that.

If I think of something while I am cleaning up my experiment for prime-time, I will let you know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants