update docs and benchmarks to include images directly to cut down on doc build warnings

add coroutine tests for new xmove copy and move constructors
cry tears because Lua does not kill the variables on the thread before killing the thread
This commit is contained in:
ThePhD 2017-09-12 19:15:23 -04:00
parent 8643dec9e5
commit fcdb471167
59 changed files with 28256 additions and 85 deletions

View File

@ -24,12 +24,19 @@ members
:caption: constructor: reference
reference(lua_State* L, int index = -1);
reference(lua_State* L, lua_nil_t);
reference(lua_State* L, absolute_index index);
reference(lua_State* L, raw_index index);
reference(lua_State* L, ref_index index);
template <typename Object>
reference(Object&& o);
template <typename Object>
reference(lua_State* L, Object&& o);
The first constructor creates a reference from the Lua stack at the specified index, saving it into the metatable registry. The second attemtps to register something that already exists in the registry. The third attempts to reference a pre-existing object and create a reference to it. These constructors are exposed on all types that derive from ``sol::reference``, meaning that you can grab tables, functions, and coroutines from the registry, stack, or from other objects easily.
Note that the last constructor, and the copy/move assignment operations, also have ``lua_xmove`` safety built into it. You can pin an object to a certain thread (or the main thread) by initializing it with ``sol::reference pinned(state, sol::lua_nil);``, or any ``sol::reference`` derived type.
.. code-block:: cpp
:caption: function: push referred-to element from the stack

View File

@ -18,18 +18,18 @@ Some developers used ``simple_usertype`` in older versions to have variables aut
The performance `seems to be good enough`_ (see below graphs as well) to not warn about any implications of having to serialize things at runtime. You do run the risk of using (slightly?) more memory, since variables and functions need to be stored differently and separately from the metatable data itself like with a regular ``usertype``. The goal here was to avoid compiler complaints about too-large usertypes (some individuals needed to register 190+ functions, and the compiler choked from the templated implementation of ``usertype``). As of Sol 2.14, this implementation has been heavily refactored to allow for all the same syntax and uses of usertype to apply here, with no caveats/exceptions.
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20member%20function%20calls%20(simple).png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20member%20function%20calls%20(simple).png
.. image:: /media/bench/lua_bench_graph_member_function_calls_(simple).png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_member_function_calls_(simple).png
:alt: bind several member functions to an object and call them in Lua code
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20userdata%20variable%20access%20(simple).png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20userdata%20variable%20access%20(simple).png
.. image:: /media/bench/lua_bench_graph_userdata_variable_access_(simple).png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_userdata_variable_access_(simple).png
:alt: bind a member variable to an object and modify it with Lua code
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20many%20userdata%20variables%20access%2C%20last%20registered%20(simple).png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20many%20userdata%20variables%20access%2C%20last%20registered%20(simple).png
.. image:: /media/bench/lua_bench_graph_many_userdata_variables_access_last_registered_(simple).png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_many_userdata_variables_access_last_registered_(simple).png
:alt: bind MANY member variables to an object and modify it with Lua code

View File

@ -15,9 +15,18 @@ The majority of the members between ``state_view`` and :doc:`sol::table<table>`
``state_view`` is cheap to construct and creates 2 references to things in the ``lua_State*`` while it is alive: the global Lua table, and the Lua C Registry.
.. _state-automatic-handlers:
One last thing you should understand: constructing a ``sol::state`` does a few things behind-the-scenes for you, mostly to ensure compatibility. They are as follows:
* set a default panic handler with ``state_view::set_panic``
* set a default ``sol::protected_function`` handler with ``sol::protected_function::set_default_handler``, using a ``sol::reference`` to ``&sol::detail::default_traceback_error_handler`` as the default handler function
* register the state as the main thread (only does something for Lua 5.1, which does not have a way to get the main thread) using ``sol::stack::register_main_thread(L)``
* register the LuaJIT C function exception handler with ``stack::luajit_exception_handler(L)``
.. warning::
It is your responsibility to make sure ``sol::state_view`` goes out of scope before you call ``lua_close`` on a pre-existing state, or before ``sol::state`` goes out of scope and its destructor gets called. Failure to do so can result in intermittent crashes because the ``sol::state_view`` has outstanding references to an already-dead ``lua_State*``, and thusly will try to decrement the reference counts for the Lua Registry and the Global Table on a dead state. Please use ``{`` and ``}`` to create a new scope when you know you are going to call ``lua_close`` to specifically control the lifetime of an object.
It is your responsibility to make sure ``sol::state_view`` goes out of scope before you call ``lua_close`` on a pre-existing state, or before ``sol::state`` goes out of scope and its destructor gets called. Failure to do so can result in intermittent crashes because the ``sol::state_view`` has outstanding references to an already-dead ``lua_State*``, and thusly will try to decrement the reference counts for the Lua Registry and the Global Table on a dead state. Please use ``{`` and ``}`` to create a new scope, or other lifetime techniques, when you know you are going to call ``lua_close`` so that you have a chance to specifically control the lifetime of a ``sol::state_view`` object.
enumerations
------------

View File

@ -17,72 +17,72 @@ Note that Sol here makes use of its more performant variants (see :doc:`c_call<a
Bars go up to the average execution time. Lower is better. Reported times are for the desired operation run through `nonius`_. Results are sorted from top to bottom by best to worst. Note that there are error bars to show potential variance in performance: generally, same-sized errors bars plus very close average execution time implies no significant difference in speed, despite the vastly different abstraction techniques used.
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20member%20function%20calls.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20member%20function%20calls.png
.. image:: /media/bench/lua_bench_graph_member_function_calls.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_member_function_calls.png
:alt: bind several member functions to an object and call them in Lua code
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20userdata%20variable%20access.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20userdata%20variable%20access.png
.. image:: /media/bench/lua_bench_graph_userdata_variable_access.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_userdata_variable_access.png
:alt: bind a variable to an object and call it in Lua code
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20many%20userdata%20variables%20access.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20many%20userdata%20variables%20access.png
.. image:: /media/bench/lua_bench_graph_many_userdata_variables_access.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_many_userdata_variables_access.png
:alt: bind MANY variables to an object and call it in Lua code
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20c%20function%20through%20lua.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20c%20function%20through%20lua.png
.. image:: /media/bench/lua_bench_graph_c_function_through_lua.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_c_function_through_lua.png
:alt: retrieve a C function bound in Lua and call it from C++
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20stateful%20c%20function.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20stateful%20c%20function.png
.. image:: /media/bench/lua_bench_graph_stateful_c_function.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_stateful_c_function.png
:alt: bind a stateful C function (e.g., a mutable lambda), retrieve it, and call it from C++
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20c%20function.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20c%20function.png
.. image:: /media/bench/lua_bench_graph_c_function.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_c_function.png
:alt: call a C function through Lua code
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20lua%20function.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20lua%20function.png
.. image:: /media/bench/lua_bench_graph_lua_function.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_lua_function.png
:alt: retrieve a plain Lua function and call it from C++
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20multi%20return.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20multi%20return.png
.. image:: /media/bench/lua_bench_graph_multi_return.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_multi_return.png
:alt: return mutliple objects from C++ using std::tuple or through a library-defined mechanism
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20global%20get.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20global%20get.png
.. image:: /media/bench/lua_bench_graph_global_get.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_global_get.png
:alt: retrieve a value from the global table
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20global%20set.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20global%20set.png
.. image:: /media/bench/lua_bench_graph_global_set.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_global_set.png
:alt: set a value into the global table
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20table%20chained%20get.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20table%20chained%20get.png
.. image:: /media/bench/lua_bench_graph_table_chained_get.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_table_chained_get.png
:alt: measures the cost of doing consecutive lookups into a table that exists from C++; some libraries fail here because they do not do lazy evaluation or chaining properly
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20table%20get.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20table%20get.png
.. image:: /media/bench/lua_bench_graph_table_get.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_table_get.png
:alt: measures the cost of retrieving a value from a table in C++; this nests 1 level so as to not be equivalent to any measured global table get optimzations
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20table%20chained%20set.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20table%20chained%20set.png
.. image:: /media/bench/lua_bench_graph_table_chained_set.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_table_chained_set.png
:alt: measures the cost of doing consecutive lookups into a table that exists from C++ and setting the final value; some libraries fail here because they do not do lazy evaluation or chaining properly
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20table%20set.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20table%20set.png
.. image:: /media/bench/lua_bench_graph_table_set.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_table_set.png
:alt: measures the cost of setting a value into a table in C++; this nests 1 level so as to not be equivalent to any measured global table set optimzations
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20return%20userdata.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20return%20userdata.png
.. image:: /media/bench/lua_bench_graph_return_userdata.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_return_userdata.png
:alt: bind a C function which returns a custom class by-value and call it through Lua code
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20get%20optional.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20get%20optional.png
.. image:: /media/bench/lua_bench_graph_get_optional.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_get_optional.png
:alt: retrieve an item from a table that does not exist in Lua and check for its existence (testing the cost of the failure case)
.. image:: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20base%20from%20derived.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua%20bench%20graph%20-%20base%20from%20derived.png
.. image:: /media/bench/lua_bench_graph_base_from_derived.png
:target: https://raw.githubusercontent.com/ThePhD/lua-bench/master/lua%20-%20results/lua_bench_graph_base_from_derived.png
:alt: retrieve base class pointer out of Lua without knowing exact derived at compile-time, and have it be correct for multiple-inheritance

View File

@ -6,9 +6,9 @@ getting good final product out of sol2
supported compilers
-------------------
GCC 7.x is now out alongside Visual Studio 2017. This means that `sol2 release v2.18.1`_ is the current version of the code targeted at the older compilers not listed below. Newer code will be targeted at working with the following compilers and leveraging their features, possibly taking advantage of whatever C++17 features are made available by the compilers and standard libraries bundled by-default with them.
GCC 7.x is now out alongside Visual Studio 2017. This means that `sol2 release v2.18.2`_ is the current version of the code targeted at the older compilers not listed below. Newer code will be targeted at working with the following compilers and leveraging their features, possibly taking advantage of whatever C++17 features are made available by the compilers and standard libraries bundled by-default with them.
``v2.18.1`` supports:
``v2.18.2`` supports:
* VC++
- Visual Studio 2017
@ -47,7 +47,7 @@ MinGW's GCC version 7.x of the compiler fixes a long-standing derp in the <codec
Clang 3.4, 3.5 and 3.6 have many bugs we have run into when developing sol2 and that have negatively impacted users for a long time now.
We encourage all users to upgrade immediately. If you need old code for some reason, use `sol2 release v2.18.0`_: otherwise, always grab sol2's latest.
We encourage all users to upgrade immediately. If you need old code for some reason, use `sol2 release v2.18.2`_: otherwise, always grab sol2's latest.
feature support
@ -95,7 +95,6 @@ The next step for Sol from a developer standpoint is to formally make the librar
Hopefully, as things progress, we move things forward.
.. _sol2 release v2.18.1: https://github.com/ThePhD/sol2/releases/tag/v2.18.1
.. _OrfeasZ in this issue: https://github.com/ThePhD/sol2/issues/329#issuecomment-276824983
.. _sol2 release v2.18.2: https://github.com/ThePhD/sol2/releases/tag/v2.18.2
.. _issue describing preliminary steps can be found here: https://github.com/ThePhD/sol2/issues/436#issuecomment-312021508
.. _this issue here: https://github.com/ThePhD/sol2/issues/426

View File

@ -83,6 +83,7 @@ Iteration
Tables may have other junk on them that makes iterating through their numeric part difficult when using a bland ``for-each`` loop, or when calling sol's ``for_each`` function. Use a numeric look to iterate through a table. Iteration does not iterate in any defined order also: see :ref:`this note in the table documentation for more explanation<iteration_note>`.
.. _OrfeasZ in this issue: https://github.com/ThePhD/sol2/issues/329#issuecomment-276824983
.. _this issue for fixes to this behavior: https://github.com/ThePhD/sol2/issues/414#issuecomment-306839439
.. _this __stdcall issue report: https://github.com/ThePhD/sol2/issues/463
.. _the simple usertype example here: https://github.com/ThePhD/sol2/blob/develop/examples/usertype_simple.cpp#L45

View File

@ -3,7 +3,7 @@
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
.. image:: sol.png
.. image:: media/sol.png
:target: https://github.com/ThePhD/sol2
:alt: sol2 repository
@ -14,15 +14,6 @@ Sol |version|
When you need to hit the ground running with Lua and C++, `Sol`_ is the go-to framework for high-performance binding with an easy to use API.
.. image:: https://travis-ci.org/ThePhD/sol2.svg?branch=develop
:target: https://travis-ci.org/ThePhD/sol2
:alt: build status
.. image:: https://badges.gitter.im/chat-sol2/Lobby.svg
:target: https://gitter.im/chat-sol2/Lobby
:alt: chat about sol2 on gitter
get going:
----------

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 137 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

View File

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

View File

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 58 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -9,12 +9,12 @@ Okay, so the features don't convince you, the documentation doesn't convince you
`eevee`_ demonstrating the sheer code reduction by using sol2:
.. |before| image:: eevee_code_before.jpg
.. |before| image:: media/eevee_code_before.jpg
:target: https://twitter.com/eevee/status/762039984085798913
:alt: Plain C API
:align: middle
.. |after| image:: eevee_code_after.jpg
.. |after| image:: media/eevee_code_after.jpg
:target: https://twitter.com/eevee/status/762039984085798913
:alt: Now with sol2!
:align: middle

View File

@ -1,19 +1,26 @@
threading
=========
Lua has no thread safety. sol2 does not force thread safety bottlenecks anywhere.
Lua has no thread safety. sol does not force thread safety bottlenecks anywhere.
Assume any access or any call on Lua affects the whole global state (because it does, in a fair bit of cases). Therefore, every call to a state should be blocked off in C++ with some kind of access control. When you start hitting the same state from multiple threads, race conditions (data or instruction) can happen. Individual Lua coroutines might be able to run on separate C++-created threads without tanking the state utterly, since each Lua coroutine has the capability to run on an independent Lua thread which has its own stack, as well as some other associated bits and pieces that won't quite interfere with the global state.
To handle multithreaded environments, it is encouraged to either spawn mutliple Lua states for each thread you are working with and keep inter-state communication to synchronized serialization points. Using coroutines and Lua's threads might also buy you some concurrency and parallelism, but remember that Lua's threading technique is ultimately cooperative and requires explicit yielding and resuming (simplified as function calls for :doc:`sol::coroutine<api/coroutine>`).
getting the main thread
-----------------------
Lua 5.1 does not keep a reference to the main thread, therefore the user has to store it themselves. If you create a ``sol::state`` or follow the :ref:`steps for opening up compatibility and default handlers here<state-automatic-handlers>`, you can work with ``sol::main_thread`` to retrieve you the main thread, given a ``lua_State*`` that is either a full state or a thread: ``lua_state* Lmain = sol::main_thread( Lcoroutine )``; This function will always work in Lua 5.2 and above: in Lua 5.1, if you do not follow the ``sol::state`` instructions and do not pass a fallback ``lua_State*`` to the function, this function may not work properly and return ``nullptr``.
working with multiple Lua threads
---------------------------------
You can mitigate some of the pressure of using coroutines and threading by using the ``lua_xmove`` constructors that sol implements. Simply keep a reference to your ``sol::state_view`` or ``sol::state`` or the target ``lua_State*`` pointer, and pass it into the constructor along with the object you want to copy. For example:
You can mitigate some of the pressure of using coroutines and threading by using the ``lua_xmove`` constructors that sol implements. Simply keep a reference to your ``sol::state_view`` or ``sol::state`` or the target ``lua_State*`` pointer, and pass it into the constructor along with the object you want to copy.
.. codeblock:: cpp
Note that copy and move assignment operators -- when you create a :doc:`sol::reference<api/reference>`-derived type like ``sol::table`` or ``sol::function`` -- also have the ``lua_xmove`` functionality built in: just make sure to initialize your types with ``sol::function f(target_state, sol::lua_nil_t);`` to lock that type onto that thread when using a copy assignment or move assignment operator. Below is an example of using the pinning thread:
.. code-block:: cpp
:caption: transfer from state function
:name: state-transfer

View File

@ -645,7 +645,7 @@ Some more things you can do/read about:
* :doc:`the usertypes page<../usertypes>` lists the huge amount of features for functions
- :doc:`unique usertype traits<../api/unique_usertype_traits>` allows you to specialize handle/RAII types from other libraries frameworks, like boost and Unreal, to work with Sol. Allows custom smart pointers, custom handles and others
* :doc:`the containers page<../containers>` gives full information about handling everything about container-like usertypes
* :doc:`the functions page<../functions.rst>` lists a myriad of features for functions
* :doc:`the functions page<../functions>` lists a myriad of features for functions
- :doc:`variadic arguments<../api/variadic_args>` in functions with ``sol::variadic_args``.
- also comes with :doc:`variadic_results<../api/variadic_results>` for returning multiple differently-typed arguments
- :doc:`this_state<../api/this_state>` to get the current ``lua_State*``, alongside other transparent argument types

View File

@ -24,9 +24,10 @@ If you're already using lua and you just want to use ``sol`` in some places, you
You may also want to call ``require`` and supply a string of a script file or something that returns an object that you set equal to something in C++. For that, you can use the :ref:`require functionality<state-require-function>`.
Remember that Sol can be as lightweight as you want it: almost all of Sol's Lua types take the ``lua_State*`` argument and then a second ``int index`` stack index argument, meaning you can use :doc:`tables<../api/table>`, :doc:`lua functions<../api/function>`, :doc:`coroutines<../api/coroutine>`, and other reference-derived objects that expose the proper constructor for your use. You can also set :doc:`usertypes<../api/usertype>` and other things you need without changing your entire architecture.
Remember that Sol can be as lightweight as you want it: almost all of Sol's Lua types take the ``lua_State*`` argument and then a second ``int index`` stack index argument, meaning you can use :doc:`tables<../api/table>`, :doc:`lua functions<../api/function>`, :doc:`coroutines<../api/coroutine>`, and other reference-derived objects that expose the proper constructor for your use. You can also set :doc:`usertypes<../api/usertype>` and other things you need without changing your entire architecture in one go.
Note that you can also make non-standard pointer and reference types with custom reference counting and such also play nice with the system. See :doc:`unique_usertype_traits\<T><../api/unique_usertype_traits>` to see how! Custom types is also mentioned in the :doc:`customization tutorial<customization>`.
There are a few things that creating a ``sol::state`` does for you. You can read about it :ref:`in the sol::state docs<state-automatic-handlers>` and call those functions directly if you need them.
.. _create a DLL that loads some Lua module: https://github.com/ThePhD/sol2/tree/develop/examples/require_dll_example

View File

@ -31,8 +31,8 @@
namespace sol {
namespace detail {
inline const char (&default_handler_name())[11] {
static const char name[11] = "sol.\xF0\x9F\x94\xA9";
inline const char (&default_handler_name())[9] {
static const char name[9] = "sol.\xF0\x9F\x94\xA9";
return name;
}

View File

@ -187,10 +187,10 @@ namespace sol {
deref();
}
reference(reference&& o) noexcept {
luastate = o.luastate;
ref = o.ref;
reference(const reference& o) noexcept : luastate(o.luastate), ref(o.copy()) {
}
reference(reference&& o) noexcept : luastate(o.luastate), ref(o.ref) {
o.luastate = nullptr;
o.ref = LUA_NOREF;
}
@ -199,8 +199,24 @@ namespace sol {
if (valid()) {
deref();
}
luastate = o.luastate;
ref = o.ref;
if (lua_state() != o.lua_state() && lua_state() != nullptr) {
// different state (different threads???)
if (o.lua_state() != nullptr) {
// both are valid but different?
o.push(lua_state());
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
return *this;
}
else {
luastate = o.luastate;
ref = o.ref;
}
}
else {
// same state, or this state is nullptr
luastate = o.luastate;
ref = o.ref;
}
o.luastate = nullptr;
o.ref = LUA_NOREF;
@ -208,14 +224,24 @@ namespace sol {
return *this;
}
reference(const reference& o) noexcept {
luastate = o.luastate;
ref = o.copy();
}
reference& operator=(const reference& o) noexcept {
if (valid()) {
deref();
}
if (lua_state() != o.lua_state() && lua_state() != nullptr) {
// different state (different threads???)
if (o.lua_state() != nullptr) {
// both are valid but different?
o.push(lua_state());
ref = luaL_ref(lua_state(), LUA_REGISTRYINDEX);
}
else {
luastate = o.luastate;
ref = o.ref;
}
return *this;
}
luastate = o.luastate;
deref();
ref = o.copy();
return *this;
}

View File

@ -228,6 +228,9 @@ namespace sol {
inline void luajit_exception_handler(lua_State* L, int(*handler)(lua_State*, lua_CFunction) = detail::c_trampoline) {
#ifdef SOL_LUAJIT
if (L == nullptr) {
return;
}
lua_pushlightuserdata(L, (void*)handler);
auto pn = pop_n(L, 1);
luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_ON);
@ -239,6 +242,9 @@ namespace sol {
inline void luajit_exception_off(lua_State* L) {
#ifdef SOL_LUAJIT
if (L == nullptr) {
return;
}
luaJIT_setmode(L, -1, LUAJIT_MODE_WRAPCFUNC | LUAJIT_MODE_OFF);
#else
(void)L;

View File

@ -102,6 +102,11 @@ namespace sol {
void reserve(std::basic_string<T, Tr, Al>& arr, std::size_t hint) {
arr.reserve(hint);
}
inline const char(&default_main_thread_name())[9]{
static const char name[9] = "sol.\xF0\x9F\x93\x8C";
return name;
}
} // detail
namespace stack {

View File

@ -23,6 +23,7 @@
#define SOL_STATE_HPP
#include "state_view.hpp"
#include "thread.hpp"
namespace sol {
@ -70,7 +71,8 @@ namespace sol {
state_view(unique_base::get()) {
set_panic(panic);
lua_CFunction f = c_call<decltype(&detail::default_traceback_error_handler), &detail::default_traceback_error_handler>;
sol::protected_function::set_default_handler(sol::object(lua_state(), in_place, f));
protected_function::set_default_handler(sol::object(lua_state(), in_place, f));
stack::register_main_thread(unique_base::get());
stack::luajit_exception_handler(unique_base::get());
}
@ -78,7 +80,8 @@ namespace sol {
state_view(unique_base::get()) {
set_panic(panic);
lua_CFunction f = c_call<decltype(&detail::default_traceback_error_handler), &detail::default_traceback_error_handler>;
sol::protected_function::set_default_handler(sol::object(lua_state(), in_place, f));
protected_function::set_default_handler(sol::object(lua_state(), in_place, f));
stack::register_main_thread(unique_base::get());
stack::luajit_exception_handler(unique_base::get());
}

View File

@ -37,7 +37,6 @@ namespace sol {
};
namespace stack {
template <>
struct pusher<lua_thread_state> {
int push(lua_State*, lua_thread_state lts) {
@ -69,10 +68,28 @@ namespace sol {
}
};
}
inline void register_main_thread(lua_State* L) {
#if SOL_LUA_VERSION < 502
if (L == nullptr) {
lua_pushnil(L);
lua_setglobal(L, detail::default_main_thread_name());
return;
}
lua_pushthread(L);
lua_setglobal(L, detail::default_main_thread_name());
#endif
}
} // stack
#if SOL_LUA_VERSION < 502
inline lua_State* main_thread(lua_State*, lua_State* backup_if_unsupported = nullptr) {
inline lua_State* main_thread(lua_State* L, lua_State* backup_if_unsupported = nullptr) {
if (L == nullptr)
return backup_if_unsupported;
lua_getglobal(L, detail::default_main_thread_name());
auto pp = stack::pop_n(L, 1);
if (type_of(L, -1) == type::thread) {
return lua_tothread(L, -1);
}
return backup_if_unsupported;
}
#else

View File

@ -3,7 +3,7 @@
#include <catch.hpp>
#include <sol.hpp>
TEST_CASE("threading/coroutines", "ensure calling a coroutine works") {
TEST_CASE("coroutines/threading", "ensure calling a coroutine works") {
const auto& script = R"(counter = 20
function loop()
@ -32,7 +32,7 @@ end
REQUIRE(counter == 30);
}
TEST_CASE("threading/new thread coroutines", "ensure calling a coroutine works when the work is put on a different thread") {
TEST_CASE("coroutines/new thread coroutines", "ensure calling a coroutine works when the work is put on a different thread") {
const auto& script = R"(counter = 20
function loop()
@ -107,3 +107,88 @@ end
}
}
}
TEST_CASE("coroutines/implicit transfer", "check that copy and move assignment constructors implicitly shift things around") {
const std::string code = R"(
-- main thread - L1
-- co - L2
-- co2 - L3
x = co_test.new("x")
local co = coroutine.wrap(
function()
local t = co_test.new("t")
local co2 = coroutine.wrap(
function()
local t2 = { "SOME_TABLE" }
t:copy_store(t2) -- t2 = [L3], t.obj = [L2]
end
)
co2()
co2 = nil
collectgarbage() -- t2 ref in t remains valid!
x:store(t:get()) -- t.obj = [L2], x.obj = [L1]
end
)
co()
collectgarbage()
collectgarbage()
co = nil
)";
struct co_test {
std::string identifier;
sol::reference obj;
co_test(sol::this_state L, std::string id) : identifier(id), obj(L, sol::lua_nil) {
}
void store(sol::table ref) {
obj = std::move(ref);
}
void copy_store(sol::table ref) {
obj = ref;
}
sol::reference get() {
return obj;
}
~co_test() {
}
};
sol::state lua;
lua.open_libraries(sol::lib::coroutine, sol::lib::base);
lua.new_usertype<co_test>("co_test",
sol::constructors<co_test(sol::this_state, std::string)>(),
"store", &co_test::store,
"copy_store", &co_test::copy_store,
"get", &co_test::get
);
auto r = lua.safe_script(code);
REQUIRE(r.valid());
co_test& ct = lua["x"];
lua_State* Lmain1 = lua.lua_state();
lua_State* Lmain2 = sol::main_thread(lua);
lua_State* Lmain3 = ct.get().lua_state();
REQUIRE(Lmain1 == Lmain2);
REQUIRE(Lmain1 == Lmain3);
sol::table t = ct.get();
REQUIRE(t.size() == 1);
std::string s = t[1];
REQUIRE(s == "SOME_TABLE");
}