Как я могу передать объект Perl 6 через обратный вызов Nativecall?

Я работаю с интерфейсом NativeCall.

Библиотека будет вызывать мою функцию обратного вызова несколько раз.

Это нормально работает. Я могу просто объявить свой обратный вызов с правильной подписью, передать его как обратный вызов &, и библиотека вызовет подпрограмму нормально.

У него также есть возможность установить указатель void * полезной нагрузки на все, что я хочу, и он будет включать это в вызов моей функции обратного вызова.

Могу ли я спрятать Perl Str, например, в полезной нагрузке и успешно передать его туда и обратно?

sub set_userdata(Pointer) returns int32 is native { ... }

sub set_callback(&callback(Pointer $userdata --> int32)) returns int32 is native { ... }

sub callback(Pointer $userdata) returns int32 {
    my Str $mystring = ???
    ...
}

my Str $my-userdata-string;

set_userdata(???);
set_callback(&callback);

Похоже, это могло бы работать с некоторыми заклинаниями привязки, "is rw", nativecast () и / или .deref.


person Curt Tilmes    schedule 12.04.2017    source источник
comment
Нет принятого ответа, надеясь, что OP может помочь читателям узнать, какой из ответов ниже был / наиболее полезен. Спасибо.   -  person jubilatious1    schedule 01.01.2021


Ответы (2)


В таком случае вы можете использовать только собственное представление (например, CStruct, CArray и CPointer) или, альтернативно, Blob. Вы также несете ответственность за то, чтобы сохранить ссылку на то, что вы передаете как userdata вживую, и с точки зрения Perl 6, чтобы сборщик мусора не возвращал память, переданную функции C.

Управление памятью - это причина, по которой вы не можете передать какой-либо старый объект Perl 6 функции C: GC не может узнать, доступен ли объект через некоторую структуру данных C, которую он не может проанализировать. В виртуальной машине, такой как MoarVM, объекты перемещаются в памяти с течением времени как часть процесса сборки мусора, а это означает, что код C может иметь устаревший указатель.

Альтернативная стратегия - не передавать указатель вообще, а вместо этого передавать целое число и использовать его для индексации в массиве объектов. (Вот как привязка libuv внутри MoarVM отслеживает обратные вызовы уровня виртуальной машины, fwiw.)

person Jonathan Worthington    schedule 13.04.2017
comment
Мне нравится идея индексации статического массива, которым я управляю на стороне Perl. Тогда один обратный вызов может просто захватить с ним нужный объект. Спасибо! - person Curt Tilmes; 13.04.2017

Я обошел это, просто проигнорировав пользовательские данные и создав новое закрытие, ссылающееся на объект Perl напрямую для каждой функции обратного вызова. Поскольку каждый раз, когда я устанавливаю обратный вызов, создается новое закрытие, я думаю, что со временем это приведет к утечке памяти.

person Curt Tilmes    schedule 13.04.2017
comment
Несмотря на то, что Джонатан Уортингтон придумал лучший подход, я думаю, что было бы здорово увидеть в этом ответе сокращенный пример вашей попытки, поскольку люди могли бы обсудить, имеет ли ваше решение достоинства и действительно ли утечка памяти. В конце концов, это обучающий сайт. - person Jarrod Funnell; 14.04.2017