From f4b0527c7d11b3a95d44b880cbdd4aae2d58ca8d Mon Sep 17 00:00:00 2001 From: Benoit Germain Date: Mon, 15 Apr 2024 14:39:05 +0200 Subject: C++ migration: deep userdata API rework. bye bye idfunc, hello DeepFactory --- docs/index.html | 39 +++++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 14 deletions(-) (limited to 'docs/index.html') diff --git a/docs/index.html b/docs/index.html index 3e535a6..67eccd5 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1683,34 +1683,45 @@ int luaD_new_clonable(lua_State* L)
  1. - Provide an identity function for your userdata, in C. This function is used for creation and deletion of your deep userdata (the shared resource), and for making metatables for the state-specific proxies for accessing it. The prototype is -
    	void* idfunc(lua_State* L, DeepOp op_);
    - op_ can be one of: + Provide a factory for your userdata. This object is used for creation and deletion of your deep userdata (the shared resource), and for making metatables for the state-specific proxies for accessing it. The prototype is +
    +class MyDeepFactory : public DeepFactory
    +{
    +	private:
    +
    +	DeepPrelude* newDeepObjectInternal(lua_State* L) const override;
    +	void deleteDeepObjectInternal(lua_State* L, DeepPrelude* o_) const override;
    +	void createMetatable(lua_State* L) const override;
    +	char const* moduleName() const override;
    +};
    +
    +static MyDeepFactory g_MyDeepFactory;
    +
      -
    • DeepOp::New: requests the creation of a new object, whose pointer is returned. Said object must derive from DeepPrelude.
    • -
    • DeepOp::Delete: receives this same pointer on the stack as a light userdata, and should cleanup the object.
    • -
    • DeepOp::Metatable: should build a metatable for the object. Don't cache the metatable yourself, Lanes takes care of it (DeepOp::Metatable should only be invoked once per state). Just push the metatable on the stack.
    • -
    • DeepOp::Module: requests the name of the module that exports the idfunc, to be returned. It is necessary so that Lanes can require it in any lane state that receives a userdata. This is to prevent crashes in situations where the module could be unloaded while the idfunc pointer is still held.
    • +
    • newDeepObjectInternal: requests the creation of a new object, whose pointer is returned. Said object must derive from DeepPrelude.
    • +
    • deleteDeepObjectInternal: should cleanup the object.
    • +
    • createMetatable: should build a metatable for the object. Don't cache the metatable yourself, Lanes takes care of it (createMetatable should only be invoked once per state). Just push the metatable on the stack.
    • +
    • moduleName: requests the name of the module that exports the factory, to be returned. It is necessary so that Lanes can require it in any lane state that receives a userdata. This is to prevent crashes in situations where the module could be unloaded while the factory pointer is still held.
    - Take a look at linda_id in lanes.cpp or deep_test_id in deep_test.cpp. + Take a look at LindaFactory in linda.cpp or MyDeepFactory in deep_test.cpp.
  2. Include "deep.h" and either link against Lanes or statically compile compat.cpp deep.cpp tools.cpp universe.cpp into your module if you want to avoid a runtime dependency for users that will use your module without Lanes. -
  3. Instanciate your userdata using luaG_newdeepuserdata(), instead of the regular lua_newuserdata(). Given an idfunc, it sets up the support structures and returns a state-specific proxy userdata for accessing your data. This proxy can also be copied over to other lanes.
  4. -
  5. Accessing the deep userdata from your C code, use luaG_todeep() instead of the regular lua_touserdata().
  6. +
  7. Instanciate your userdata using yourFactoryObject.pushDeepUserdata()(), instead of the regular lua_newuserdata(). Given a factory, it sets up the support structures and returns a state-specific proxy userdata for accessing your data. This proxy can also be copied over to other lanes.
  8. +
  9. Accessing the deep userdata from your C code, use yourFactoryObject.toDeep() instead of the regular lua_touserdata().

- Deep userdata management will take care of tying to __gc methods, and doing reference counting to see how many proxies are still there for accessing the data. Once there are none, the data will be freed through a call to the idfunc you provided. + Deep userdata management will take care of tying to __gc methods, and doing reference counting to see how many proxies are still there for accessing the data. Once there are none, the data will be freed through a call to the factory you provided.

- Deep userdata in transit inside keeper states (sent in a linda but not yet consumed) don't call idfunc(DeepOp::Delete) and aren't considered by reference counting. The rationale is the following: + Deep userdata in transit inside keeper states (sent in a linda but not yet consumed) don't call deleteDeepObjectInternal and aren't considered by reference counting. The rationale is the following:
If some non-keeper state holds a deep userdata for some deep object, then even if the keeper collects its own deep userdata, it shouldn't be cleaned up since the refcount is not 0.
- OTOH, if a keeper state holds the last deep userdata for some deep object, then no lane can do actual work with it. Deep userdata's idfunc() is never called from a keeper state. + OTOH, if a keeper state holds the last deep userdata for some deep object, then no lane can do actual work with it. Deep userdata's factory() interface is never accessed from a keeper state.
- Therefore, Lanes can just call idfunc(DeepOp::Delete) when the last non-keeper-held deep userdata is collected, as long as it doesn't do the same in a keeper state after that, since any remaining deep userdata in keeper states now hold stale pointers. + Therefore, Lanes can just call deleteDeepObjectInternal when the last non-keeper-held deep userdata is collected, as long as it doesn't do the same in a keeper state after that, since any remaining deep userdata in keeper states now hold stale pointers.

-- cgit v1.2.3-55-g6feb