Доступ к lightuserdata из C - PullRequest
2 голосов
/ 01 апреля 2019

Я использую Lua в системе с очень ограниченными ресурсами в сочетании с C.

Библиотека, которую я использую, создает некоторые ссылки (как указатели) на объекты, которые она создает, что полезно для последующего доступа к этим объектам. Чтобы предоставить функциональность этой библиотеки Lua, при создании такого объекта эта ссылка возвращается в сценарий Lua.

Пользователь имеет возможность сохранить эту ссылку по своему вкусу, поскольку это делает последующие звонки очень удобными.

Примеры случаев:

ref = MyLib.createObject("some", arguments)
local ref = MyLib.createObject("some", arguments)
table_of_refs[45] = MyLib.createObject("some", arguments)
-- etc...

К сожалению, эти ссылки могут быть уничтожены вне области действия сценария Lua (изнутри C). Таким образом, эти ссылки могут стать недействительными.

Пока что мой код может без проблем обрабатывать эти недействительные ссылки. Все эти указатели проверяются перед фактическим использованием в библиотеке, поэтому код безопасен.

Однако это немного сбивает с толку с точки зрения пользователя Lua, поскольку невозможно определить, действительна ли эта ссылка или нет (это не очень важно, но все же я хочу улучшить ее) .

Я хочу следующее. Я хочу перебрать из C все lightuserdata, которые хранит Lua. Если lightuserdatum больше не действителен, установите его на ноль. Таким образом, при следующем использовании переменная будет либо действительной, либо нулевой, предоставляя пользователям гораздо лучший API.

Есть ли способ достичь этого? Могу ли я выполнить итерацию из C всех lightuserdata, о которых знает Lua (независимо от того, где они хранятся, локальные / глобальные / таблицы и т. Д.), И изменить их?

Ответы [ 2 ]

2 голосов
/ 01 апреля 2019

Нет способа получить доступ к локальным переменным lua из C. Поэтому, даже если вы выполняли итерацию по определенному типу объекта lua, у вас не было бы доступа хотя бы к одной области (локальным переменным).

Вы можете перебирать все в глобальной таблице, как показано в ответе Макса здесь: Проходить по всем глобальным переменным Lua в C ++

Если вы проверяли lua_islightuserdataа затем сравните значение lightuserdata с указателем, который вы удаляете, вы сможете распознать, какие глобальные значения вы хотите.

lua_pushglobaltable(L); 
lua_pushnil(L);    
while (lua_next(L,-2) != 0) 
{
    if (lua_islightuserdata(L, -1))
    {
        //TODO: compare against the lightuserdata pointer value you are looking for
        void* mypointer = lua_touserdata(state, -1);

        name = lua_tostring(L,-2);  // Get key(-2) name
        //TODO: do whatever with the value; probably set to nil by name in the global table
    }
    lua_pop(L,1);
}
lua_pop(L,1); 

Если вы хотите найти их в таблицах, выпридется включить дополнительную проверку lua_istable, а затем рекурсивно перебирать значения таблицы таким же образом.

...
else if (lua_istable(L, -1)
{
    //TODO: iterate each value in the table searching for lightuserdata
    // or tables with further levels of recursion
}
...

Я думаю, однако, было бы гораздо более прямым предоставить метод с именем "isValid "на MyLib, который возвращает, является ли значение все еще действительным или нет перед его использованием.

local ref = MyLib.createObject("some", arguments)
...
local isvalid = MyLib.isValid(ref)

Тогда вы не ограничены локальной областью действия.Кроме того, предполагая, что в любом случае вы будете выполнять нулевую проверку в своем коде lua (чтобы увидеть, изменилось ли значение из-под вас), это в принципе ничего не стоит с точки зрения кода.

0 голосов
/ 02 апреля 2019

Я думаю, вы уже ошиблись в концепции.

Как получается, что созданный объект может быть уничтожен изнутри C?Это был сценарий Lua, который инициировал создание, поэтому также должен быть сценарий Lua, который запускает уничтожение.

Вместо того, чтобы уничтожать объект, вы можете просто установить флаг, указывающий недопустимое состояние объекта.Вы могли бы дополнительно реализовать механизм обратного вызова, чтобы библиотека C могла информировать скрипт Lua о недействительных объектах.

Если требуется сохранить много данных и вы хотите иметь возможность повторно использовать память, как тольковозможно, тогда объект Lua может быть просто оберткой вокруг указателя на истинные данные.Затем вы можете самостоятельно удалить данные и установить указатель на NULL, что в то же время будет служить признаком недействительности.

Имейте в виду, что проверка достоверности указателя только по значению указателя может привести к серьезным ошибкам:

SomeStruct* ptr = malloc(sizeof(SomeStruct));
// don't forget if(!ptr) error handling

SomeStruct* copy = ptr; // here C only, but might be stored in Lua!

SomeStruct* newPtr = malloc(sizeof(SomeStruct));
// by accident same address re-used as ptr once had!!!

if(isValid(copy))
{
    // but the struct originally referenced died long ago...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...