Skip to content

Commit ff7a0c4

Browse files
authored
Merge pull request #823 from o-sdn-o/gui-bridge
Fix precompiled script reference counting
2 parents d2a5a6f + 26c5145 commit ff7a0c4

File tree

4 files changed

+79
-67
lines changed

4 files changed

+79
-67
lines changed

src/netxs/desktopio/application.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace netxs::app
2222

2323
namespace netxs::app::shared
2424
{
25-
static const auto version = "v2025.10.11";
25+
static const auto version = "v2025.10.12";
2626
static const auto repository = "https://github.com/directvt/vtm";
2727
static const auto usr_config = "~/.config/vtm/settings.xml"s;
2828
static const auto sys_config = "/etc/vtm/settings.xml"s;

src/netxs/desktopio/controls.hpp

Lines changed: 59 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -415,8 +415,7 @@ namespace netxs::events
415415
indexer.script_param = std::ref((T&)param);
416416

417417
auto error = faux;
418-
auto [ok, lua_fx_id] = push_function_id(script_body);
419-
if (ok)
418+
if (push_function_id(script_body))
420419
{
421420
if (::lua_rawget(lua, -2) == LUA_TFUNCTION) // It is precompiled.
422421
{
@@ -469,7 +468,19 @@ namespace netxs::events
469468
log(ansi::clr(yellowlt, shadow), "\n", prompt::lua, result);
470469
script.cmd = utf::concat(shadow, "\n", prompt::lua, result);
471470
}
472-
std::pair<bool, view> luna::push_function_id(view script_body)
471+
// Return the length of the stack top table.
472+
si32 luna::get_table_size()
473+
{
474+
auto count = 0;
475+
::lua_pushnil(lua); // Push nil to start the iteration.
476+
while (::lua_next(lua, -2) != 0)
477+
{
478+
count++; // Key is at -2, value at -1.
479+
::lua_pop(lua, 1); // Pop the value, leaving the key for the next iteration.
480+
}
481+
return count;
482+
}
483+
bool luna::push_function_id(view script_body)
473484
{
474485
::lua_settop(lua, 0);
475486
// Get a table of precompiled functions from the registry.
@@ -481,64 +492,67 @@ namespace netxs::events
481492
auto lua_fx_id = view{ memory_id, sizeof(script_id) };
482493
//if constexpr (debugmode) log("Function id='%%'", utf::debase437(lua_fx_id));
483494
::lua_pushlstring(lua, lua_fx_id.data(), lua_fx_id.size());
484-
return std::pair{ true, lua_fx_id };
495+
return true;
485496
}
486497
else
487498
{
488499
log("%%The table of precompiled functions is missing", prompt::lua);
489500
::lua_settop(lua, 0);
490-
return std::pair{ faux, view{} };
501+
return faux;
491502
}
492503
}
493-
bool luna::precompile_function(sptr<text>& script_body_ptr)
504+
void luna::precompile_function(sptr<std::pair<ui64, text>>& script_body_ptr)
494505
{
495-
auto precompiled = faux;
496-
if (script_body_ptr && script_body_ptr->size())
506+
if (script_body_ptr)
497507
{
498-
auto& script_body = *script_body_ptr;
499-
auto [ok, lua_fx_id] = push_function_id(script_body);
500-
if (ok)
508+
auto& [ref_count, script_body] = *script_body_ptr;
509+
if (script_body.size())
501510
{
502-
if (::lua_rawget(lua, -2) == LUA_TFUNCTION) // It is already precompiled.
511+
if (push_function_id(script_body))
503512
{
504-
//if constexpr (debugmode) log("The script is already precompiled");
505-
precompiled = true;
506-
}
507-
else // It is not precompiled yet.
508-
{
509-
::lua_pop(lua, 1); // Pop nil after the ::lua_rawget() call.
510-
::lua_pushlstring(lua, lua_fx_id.data(), lua_fx_id.size()); // Push fx id again.
511-
auto error = ::luaL_loadbuffer(lua, script_body.data(), script_body.size(), "precompilation");
512-
if (error)
513+
::lua_pushvalue(lua, -1); // Duplicate lua_fx_id string.
514+
if (::lua_rawget(lua, -3) == LUA_TFUNCTION) // It is already precompiled.
513515
{
514-
auto result = ::lua_tostring(lua, -1);
515-
log("%%Precompilation error: %msg%", prompt::lua, ansi::err(result));
516-
::lua_pop(lua, 1); // Pop error message from stack.
516+
//if constexpr (debugmode) log("The script is already precompiled");
517+
++ref_count;
517518
}
518-
else
519+
else // It is not precompiled yet.
519520
{
520-
//if constexpr (debugmode) log("Script precompilation is done");
521-
::lua_rawset(lua, -3);
522-
precompiled = true;
521+
::lua_pop(lua, 1); // Pop nil after the ::lua_rawget() call.
522+
auto error = ::luaL_loadbuffer(lua, script_body.data(), script_body.size(), "precompilation");
523+
if (error)
524+
{
525+
auto result = ::lua_tostring(lua, -1);
526+
log("%%Precompilation error: %msg%", prompt::lua, ansi::err(result));
527+
::lua_pop(lua, 1); // Pop error message from stack.
528+
}
529+
else
530+
{
531+
//if constexpr (debugmode) log("Script precompilation is done");
532+
::lua_rawset(lua, -3);
533+
//if constexpr (debugmode) log("Add: Precompiled function counter: %%", get_table_size());
534+
++ref_count;
535+
}
523536
}
537+
::lua_settop(lua, 0);
524538
}
525-
::lua_settop(lua, 0);
526539
}
527540
}
528-
return precompiled;
529541
}
530-
void luna::remove_function(sptr<text>& script_body_ptr)
542+
void luna::remove_function(sptr<std::pair<ui64, text>>& script_body_ptr)
531543
{
532-
if (script_body_ptr && script_body_ptr->size() && script_body_ptr.use_count() == 1)
544+
if (script_body_ptr)
533545
{
534-
auto& script_body = *script_body_ptr;
535-
auto [ok, lua_fx_id] = push_function_id(script_body);
536-
if (ok)
546+
auto& [ref_count, script_body] = *script_body_ptr;
547+
if (ref_count && --ref_count == 0)
537548
{
538-
::lua_pushnil(lua);
539-
::lua_rawset(lua, -3);
540-
::lua_settop(lua, 0);
541-
//if constexpr (debugmode) log("Function id='%%' removed", utf::debase437(lua_fx_id));
549+
if (push_function_id(script_body))
550+
{
551+
::lua_pushnil(lua);
552+
::lua_rawset(lua, -3); // Remove rec from the table (because of nil) and pop key and val from stack.
553+
//if constexpr (debugmode) log("Drop: Precompiled function counter: %%", get_table_size());
554+
::lua_settop(lua, 0);
555+
}
542556
}
543557
}
544558
}
@@ -591,18 +605,16 @@ namespace netxs::events
591605
if (lua) ::lua_close(lua);
592606
}
593607

594-
script_ref::script_ref(auth& indexer, context_t& context, sptr<text> script_body_ptr)
608+
script_ref::script_ref(auth& indexer, context_t& context, sptr<std::pair<ui64, text>> script_body_ptr)
595609
: indexer{ indexer },
596610
context{ context },
597-
script_body_ptr{ script_body_ptr },
598-
precompiled{ indexer.luafx.precompile_function(script_body_ptr) }
599-
{ }
611+
script_body_ptr{ script_body_ptr }
612+
{
613+
indexer.luafx.precompile_function(script_body_ptr);
614+
}
600615
script_ref::~script_ref()
601616
{
602-
if (precompiled)
603-
{
604-
indexer.luafx.remove_function(script_body_ptr);
605-
}
617+
indexer.luafx.remove_function(script_body_ptr);
606618
}
607619

608620
auth::auth(bool use_timer)

src/netxs/desktopio/events.hpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,10 @@ namespace netxs::events
169169
text run(context_t& context, view script_body, Arg&& param = {});
170170
text run_script(ui::base& object, view script_body);
171171
void run_ext_script(ui::base& object, auto& script);
172-
std::pair<bool, view> push_function_id(view script_body);
173-
bool precompile_function(sptr<text>& script_body_ptr);
174-
void remove_function(sptr<text>& script_body_ptr);
172+
si32 get_table_size();
173+
bool push_function_id(view script_body);
174+
void precompile_function(sptr<std::pair<ui64, text>>& script_body_ptr);
175+
void remove_function(sptr<std::pair<ui64, text>>& script_body_ptr);
175176

176177
luna(auth& indexer);
177178
~luna();
@@ -181,14 +182,13 @@ namespace netxs::events
181182
{
182183
auth& indexer; // script_ref: Global object indexer.
183184
std::reference_wrapper<context_t> context; // script_ref: Hierarchical location index of the script owner.
184-
sptr<text> script_body_ptr; // script_ref: Script body sptr.
185-
bool precompiled{}; // script_ref: .
185+
sptr<std::pair<ui64, text>> script_body_ptr; // script_ref: Script body sptr.
186186

187187
static text to_string(context_t& context);
188188

189-
script_ref(auth& indexer, context_t& context, sptr<text> script_body_ptr);
190-
script_ref(auth& indexer, context_t& context, auto&& script_body_ptr)
191-
: script_ref{ indexer, context, ptr::shared<text>(script_body_ptr) }
189+
script_ref(auth& indexer, context_t& context, sptr<std::pair<ui64, text>> script_body_ptr);
190+
script_ref(auth& indexer, context_t& context, auto&& script_body)
191+
: script_ref{ indexer, context, ptr::shared(std::pair<ui64, text>{ 0, script_body }) }
192192
{ }
193193
~script_ref();
194194
};
@@ -227,8 +227,8 @@ namespace netxs::events
227227
{
228228
if (script_ptr && script_ptr->script_body_ptr)
229229
{
230-
auto& context = script_ptr->context;
231-
auto& script_body = *(script_ptr->script_body_ptr);
230+
auto& context = script_ptr->context;
231+
auto& [ref_count, script_body] = *(script_ptr->script_body_ptr);
232232
luafx.run(context, script_body, param);
233233
}
234234
else if (auto& proc = get_inst<Arg>())

src/netxs/desktopio/input.hpp

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2117,9 +2117,9 @@ namespace netxs::input
21172117
{
21182118
struct binding_t
21192119
{
2120-
text chord;
2121-
txts sources; // Event source list.
2122-
netxs::sptr<text> script_ptr;
2120+
text chord;
2121+
txts sources; // Event source list.
2122+
netxs::sptr<std::pair<ui64, text>> script_ptr;
21232123
};
21242124
using vector = std::vector<binding_t>;
21252125

@@ -2167,20 +2167,20 @@ namespace netxs::input
21672167
{
21682168
if (sources.empty())
21692169
{
2170-
//log("Set handler for event_id:%% script: %%", event_id, ansi::hi(*(script_ptr->script_body_ptr)));
2170+
//log("Set handler for event_id:%% script: %%", event_id, ansi::hi(script_ptr->script_body_ptr->second));
21712171
boss.bell::submit_generic(tier_id, event_id, script_ptr);
21722172
}
21732173
else //todo revise: too hacky
21742174
{
2175-
//log("Deferred setting handler on '%target%' for script: ", sources.front(), ansi::hi(*(script_ptr->script_body_ptr)));
2175+
//log("Deferred setting handler on '%target%' for script: ", sources.front(), ansi::hi(script_ptr->script_body_ptr->second));
21762176
auto& indexer = boss.indexer;
21772177
indexer._null_gear_sptr->ui::base::enqueue([&, id = boss.id, tier_id, event_id, sources, script_ptr](auto& /*gear_0*/) // Subscribe on sources (with boss.sensors).
21782178
{
21792179
if (auto boss_ptr = indexer._null_gear_sptr->getref(id)) // The boss may already be deleted.
21802180
{
21812181
for (auto& src_name : sources)
21822182
{
2183-
//log("Set handler on '%target%' for script: ", src_name, ansi::hi(*(script_ptr->script_body_ptr)));
2183+
//log("Set handler on '%target%' for script: ", src_name, ansi::hi(script_ptr->script_body_ptr->second));
21842184
if (auto target_ptr = indexer.get_target(boss_ptr->scripting_context, src_name))
21852185
{
21862186
target_ptr->bell::submit_generic(tier_id, event_id, boss_ptr->sensors, script_ptr);
@@ -2203,7 +2203,7 @@ namespace netxs::input
22032203
if (chords.size())
22042204
{
22052205
auto script_ptr = ptr::shared<script_ref>(boss.indexer, boss.scripting_context, script_body);
2206-
auto reset_handler = !(script_ptr->script_body_ptr && script_ptr->script_body_ptr->size());
2206+
auto reset_handler = !(script_ptr->script_body_ptr && script_ptr->script_body_ptr->second.size());
22072207
for (auto& binary_chord : chords) if (binary_chord.size()) // Scripts always store their sensors at the boss side, since the lifetime of base::scripting_context depends on the boss.
22082208
{
22092209
auto k = (byte)binary_chord.front();
@@ -2258,7 +2258,7 @@ namespace netxs::input
22582258
{
22592259
//todo revise
22602260
//auto script_context = config.settings::push_context(script_ptr);
2261-
auto script_body_ptr = ptr::shared(config.settings::take_value(script_ptr));
2261+
auto script_body_ptr = ptr::shared(std::pair<ui64, text>{ 0, config.settings::take_value(script_ptr) });
22622262
auto on_ptr_list = config.settings::take_ptr_list_of(script_ptr, "on");
22632263
for (auto event_ptr : on_ptr_list)
22642264
{
@@ -2268,7 +2268,7 @@ namespace netxs::input
22682268
//{
22692269
// for (auto& sourse : sources)
22702270
// {
2271-
// log("chord='%%' \tpreview=%% source='%%' script=%%", on_rec, (si32)preview, source, ansi::hi(*script_body_ptr));
2271+
// log("chord='%%' \tpreview=%% source='%%' script=%%", on_rec, (si32)preview, source, ansi::hi(script_body_ptr->second));
22722272
// }
22732273
//}
22742274
bindings.push_back({ .chord = std::move(on_rec), .sources = std::move(sources), .script_ptr = script_body_ptr });

0 commit comments

Comments
 (0)