LINUX.ORG.RU

Встраивание ruby в C

 , , , ,


1

3

Проверяю чистоту встраивания ruby в C. Выходит: finalize() не производит полную очистку. Или чего-то не хватает при инициализации, или есть ещё что-то к finalize(), или bug?

Минимальный пример:

// test_embed_ruby.c
// gcc -Wall -g -o test_embed_ruby test_embed_ruby.c -I/usr/include/ruby-1.9.1 -I/usr/include/ruby-1.9.1/x86_64-linux -lruby-1.9.1

#include <stdio.h>
#include <ruby.h>

void call_ruby(void)
{
        printf("init...\n");
        ruby_init();

        printf("init_loadpath...\n");
        ruby_init_loadpath();

        printf("finalize...\n");
        ruby_finalize();
}

int main(int argc, char *argv[])
{
        printf("1\n");
        call_ruby();
        printf("2\n");
        call_ruby();

        return 0;
}
Падает на втором вызове ruby_init_loadpath(). Если закомментировать - на втором вызове ruby_finalize().

★★★★★

Ответ на: комментарий от gag

А отладчиком руби гонял? Рекомендую скачать последнюю версию и собрать её отдельно и с отладочной инфой.

Предполагаю, что ruby не очень ориентирован на множественное использование.

O02eg ★★★★★
()
Ответ на: комментарий от O02eg

Да, похоже там (http://www.ruby-forum.com/topic/100843) более 5ти лет никого не волнует, что руби не убирает за собой. Год назад снова напомнили (http://www.ruby-forum.com/topic/1341373), а руби-кор просто игнорирует (http://www.ruby-forum.com/topic/1345927)! Странно.

Ну, мы, мужики, конечно программеры, но женщин-программисток нам бывает явно не хватает.

gag ★★★★★
() автор топика
Ответ на: комментарий от O02eg

И аналогично у перла: https://rt.perl.org/rt3/Public/Bug/Display.html?id=64326. Вот смеёмся «это не баг - это фича». А даже в матёром перле - на полном серьёзе.

char *a;
a = (char*) malloc(8 * sizeof(char));
free(a);
a = (char*) malloc(8 * sizeof(char));
free(a); // SEGFAULT
Выглядит абсурдно, да?

А ведь делать clean up можно только один раз ( (с) 2009 Dave Mitchell <davem @at iabyn.com> )!

P.S. Мне в принципе всё равно, какие интерпретаторы встраивать для скриптинга. Хотелось бы побольше, но надёжно. Остаётся проверить dlopen/dlclose.

gag ★★★★★
() автор топика
Ответ на: комментарий от gag

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

O02eg ★★★★★
()
Ответ на: комментарий от O02eg

Бывают часто случаи, когда что-то является избытком, чем-то дополнительным - согласен.

Но malloc/free, new/delete, open/close, { / } в C/C++, initialize/finalize, init/deinit & Co. - это, как бы, само собой разумеющееся, как дверь, которую можно отпирать и запирать так, что замок не заклинивает. Т.е. после соотв. очистки должно восстанавливаться прежнее состояние, а не всё ломаться.

Если после finalize нельзя больше вызвать initialize, так можно было бы вообще не делать вводящий в заблуждение finalize, и просто сказать: «а, ОС за нас уберёт».

gag ★★★★★
() автор топика
Ответ на: комментарий от O02eg

Даже dlopen/dlclose не спасают ситуацию (пробовал для перла). Т.е. интерпретатор должен жить до конца или умереть на всё время исполнения программы. Вместо подгрузки/выгрузки по надобности.

gag ★★★★★
() автор топика

в качестве workaround могу предложить форкать процесс с интерпретатором. Но вообще задача интересная, надо будет посмотреть.

anonymous
()
Ответ на: комментарий от anonymous

Форкать не хотелось бы, потому что мне нужна портабельность.

Вот просто не верится: dlclose() просто делает либу недоступной, а не освобождает все связанные с ней ресурсы, выходит?

gag ★★★★★
() автор топика
Ответ на: комментарий от gag

dlclose() просто делает либу недоступной, а не освобождает все связанные с ней ресурсы, выходит?

А с чего ты решил, что руби и перл связывают используемые ресурсы с собой, а не с программой?

O02eg ★★★★★
()
Ответ на: комментарий от O02eg

Да, тут лучше ничего не подразумевать, если точно сам не проверял. Поиск по «c runtime environment» ничего очевидно не предлагает, чтобы понять, что этот finalize/term в нём поганить может (и зачем).

gag ★★★★★
() автор топика
Ответ на: комментарий от tensai_cirno

Да я до реентрантности ещё даже вовсе не добрался. Не работает банальный последовательный код типа start/stop.

Попробуй mruby еще.

Попробую, спасибо за ссылку! Эх, свежий проект. В дебиане ещё ни в каком виде нет - это минус.

gag ★★★★★
() автор топика
Ответ на: комментарий от red_eyed_peguin

Э, а разве питон по встраиваемости должен как-то отличаться от перла?

Я вот как раз ruby пробую как доп. альтернативу привычным perl & python.

Вот Lua тоже уже попробовал. Там close() для state тоже чистит не всё за собой. Т.е. если скрипт подгружает модули, то я исхожу из того, что после close - всё, все модули выгружаются, и после open() - девственное состояние, модули можно грузить снова те же без проблем. Пока опыт говорит об обратном.

Scheme(guile)? Это поэкзотичней для меня. Но если встраиваются - то что - не мне же на нём программировать - можно попробовать.

gag ★★★★★
() автор топика
Ответ на: комментарий от gag

Да я до реентрантности ещё даже вовсе не добрался. Не работает банальный последовательный код типа start/stop.

Инициализируешь рантайм, грузишь код, дёргаешь код по мере надобности. Сворачиваешь рантайм вместе с закрытием приложения.

Попробую, спасибо за ссылку! Эх, свежий проект. В дебиане ещё ни в каком виде нет - это минус.

Проект совсем свежий, его нигде ни в каком виде нету пока.

tensai_cirno ★★★★★
()
Ответ на: комментарий от tensai_cirno

Инициализируешь рантайм, грузишь код, дёргаешь код по мере надобности. Сворачиваешь рантайм вместе с закрытием приложения.

Если хочется использовать перл или оригинальный руби - другого выхода пока не нашёл. С питоном ситуация получше. У луа вообще проблемы с запуском под gdb - прога вдруг останавливается - и всё - gdb сообщает, что потерял её, поток.

Но я пытаюсь сейчас найти причину сложности проведения чистого останова интерпретатора и повторного запуска. Что он там манипулирует в C runtime environment? Где вообще об этом можно почитать?

gag ★★★★★
() автор топика
Ответ на: комментарий от gag

Но я пытаюсь сейчас найти причину сложности проведения чистого останова интерпретатора и повторного запуска. Что он там манипулирует в C runtime environment? Где вообще об этом можно почитать?

Dunno. Не может чисто остановиться. Попробуй один раз сделать finalize, и запустить под валгриндом, посмотреть, всю ли память освобождает, может еще что-то держит.

С почитать очень большие проблемы, потому что оно есть, и много, но оно всё на японском и не переведено. Взять тот же Ruby Hacking Guide.

http://rhg.rubyforge.org/

tensai_cirno ★★★★★
()
Ответ на: комментарий от tensai_cirno

всю ли память освобождает

Только possibly lost при вызове pthread_create(). А вот по второму кругу всё хуже.

Тем временем обнаружил, что при dlclose() деструктор моей либы вызывается, а вот деструктор в libperl5.14.so не-а. Т.е. нужно сам перл dlopen'уть. Если б он был честно написан, без всяких макросов, а так, что-то я сомневаюсь, что это реально. Вообще как-то странно выходит: если моя либа слинкована с ещё чем-то, что я могу выгрузить свою либу, а те динамически слинкованные по-прежнему висят. Как зомби, которые снова оживают после того, как я снова подгрузил свою либу. Не понятно.

А вот с руби можно попробовать. Кстати, установил libruby-dbg в дебиан. А там внутри не лежит .so, только какие-то .debug (которые внутри похоже .so). Тем не менее строчки из исходников ruby не отображаются.

gag ★★★★★
() автор топика
Ответ на: комментарий от O02eg

См. выше. Выходит, что освободиться от динамичски слинкованных библиотек, которые были подгружены либой, загруженной по dlopen(), нельзя? Т.е. это же shared object, которые могут ещё кем-то использоваться. По dlclose() моей либы, выходит не происходит декремент ссылки на libperl.so. Это можно сделать как-нибудь вручную?

gag ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.