воспроизвести можно так: 1. создаем dll, в ней линкуемся с lua53.dll. 2. в luaopen_... создаем новый инстанс lua vm при помощи luaL_newstate() 3. инициализируем его при помощи luaL_openlibs() получаем исключение "multiple Lua VMs detected. Expected 5.3 instead of 0.0"
что-то вы там не доделали, исправьте, пожалуйста. спасибо.
даже еще веселее: lua_version() для инстанса, передаваемого в luaopen_ возвращает значение 0.0 (должна, очевидно, 5.3), а для создаваемого нового инстанса luaL_newstate() - luaversion() возвращает мусорное значение (должна так же возвращать 5.3).
Хехе, чудеса. Ошибочка происходит, когда в программе оказываются два луа из разных длл или из экзешника и длл. Сравниваем, как было в 8.3. Весь луа экспортировала qlua.dll, а lua5.1.dll была просто проксей (28 кб размер, кода там нет очевидно). В 8.5 qlua.dll ничего не экспортирует, кроме двух функций плагина, а экспортирует все как раз lua53.dll и, судя по размеру, весь код в ней тоже сидит. Вот так мы и получаем два экземпляра луа в одном процессе.
в квике нет возможности указать, в луа-машине какой версии запускать квик. в luaopen уже передается некий стейт, он должен быть версии 5.3 (или, на худой конец, 5.1). полагаю, что lua5.1.dll - это та же lua 5.3 только захаченная таким образом, чтобы библиотеки пользователей воспринимали ее как 5.1. так вот. если даже ничего в luaopen_ не делать, а вызвать lua_version() из подгруженной lua53.dll, то все равно, результат ее работы никак не должен быть 0.0.
rst9 написал: если даже ничего в luaopen_ не делать, а вызвать lua_version() из подгруженной lua53.dll, то все равно, результат ее работы никак не должен быть 0.0.
Дык, насколько понимаю, дело в том, что вы вызываете lua_version() из прилинкованной к вашей длл lua53.dll. Квик до запуска скрипта уже загрузил qlua.dll и запустил машину оттуда, и весь стейт там, а функции из lua53.dll будут работать постольку, поскольку не трогают глобальных переменных луа. Как раз lua_newstate() их трогает, и трогает не те.
Anton написал: Хехе, чудеса. Ошибочка происходит, когда в программе оказываются два луа из разных длл или из экзешника и длл.
вы можете в одном процессе, экзешнике, dll, что угодно, иметь все луа-машины всех версий одновременно. проблемы будут, если вы создадите стейт при помощи одних функций (скажем, из lua5.1.dll), а будете пытаться манипулировать им при помощи других (например, из lua53.dll).
в данном случае, похоже, стейт просто покоррапчен. мусор, возвращаемый lua_version() тому свидетельство.
rst9 написал: проблемы будут, если вы создадите стейт при помощи одних функций (скажем, из lua5.1.dll), а будете пытаться манипулировать им при помощи других (например, из lua53.dll).
Об этом и речь, только еще шире, одни функции из 53 и другие функции из 53, одинаковые до байта, но в разных модулях.
Anton написал: Дык, насколько понимаю, дело в том, что вы вызываете lua_version() из прилинкованной к вашей длл lua53.dll. Квик до запуска скрипта уже загрузил qlua.dll и запустил машину оттуда, и весь стейт там, а функции из lua53.dll будут работать постольку, поскольку не трогают глобальных переменных луа. Как раз lua_newstate() их трогает, и трогает не те .
забудьте про luaL_newstate(). есть скрипт, который мы запускаем в квике. он считает себя версией 5.3 (message(_VERSION, 1) выдает "Lua 5.3"). дальше require грузит mylib.dll, которая из lua53.dll вызывает lua_version(). результат: 0.0. это ошибка.
и нет никаких "глобальных переменных lua". вся lua инкапсулирована в стейт. luaL_newstate() создает вообще отдельный стейт, который никак не связан с другими стейтами. он будет той версии, которой соответствует вызываемая luaL_newstate(). и для этого создаваемого вами стейта, вы должны использовать функции этой версии. можете попробовать взять generic Lua5.1, создать свою mylib.dll, которая, будучи вызвана из скрипта, загрузит generic либу lua5.3 и создаст стейт 5.3 и запустит в нем что-то еще. у вас все будет работать до тех пор, пока вы для каждого стейта будете использовать его "родное" api. для первого 5.1, для второго 5.3.
_VERSION это как раз глобальная константа, она зашита в длл намертво и всегда такая, какой была при компиляции, чего на нее смотреть. Вот lua_version куда интереснее.
Конкретно ошибка "multiple Lua VMs detected" вылезает в результате того, что УКАЗАТЕЛЬ на версию в стейте не равен УКАЗАТЕЛЮ на глобальную версию. На самом деле она не такая и глобальная, статическая переменная внутри самой lua_version(). В каком случае указатель на статическую переменную внутри функции может быть не равен указателю на ту же статическую переменную внутри той же функции? Когда это ДВЕ РАЗНЫХ ФУНКЦИИ. Из разных модулей, например. См. сорцы luaL_checkversion_ и lua_version.
В то же время все не так просто, как я выше написал, то есть от самой идеи я не отказываюсь, но обойти косяк, не линкуя lua5.3.dll, а подгрузив ее динамически, я не смог, результат тот же. Откуда следует, что в квике и без нас УЖЕ два экземпляра каким-то образом.
Впрочем, есть еще один вариант - это когда один из указателей равен NULL. Статический не может быть NULL, значит, NULL в стейте. Смотрим внутрь lua_newstate, она сразу же ставит version в NULL и устанавливает ее только после того, как вся инициализация стейта прошла без ошибок. Это происходит в функции f_luaopen и там тупо нет варианта не установить версию, либо одна из вызванных функций выкинула ошибку, lua_nestate ее поймала и тут же прибила стейт и вернула NULL, либо все прошло хорошо и версия установлена перед выходом из f_luaopen. Отсюда вывод - одна из функций инициализации ошибку таки выкинула, но lua_newstate ее не поймала. Упс, это ровно то, о чем я писал не далее как вчера. То есть природа косяка та же самая, видимо.
Anton написал: _VERSION это как раз глобальная константа, она зашита в длл намертво и всегда такая, какой была при компиляции, чего на нее смотреть. Вот lua_version куда интереснее. Конкретно ошибка "multiple Lua VMs detected" вылезает в результате того, что УКАЗАТЕЛЬ на версию в стейте не равен УКАЗАТЕЛЮ на глобальную версию. На самом деле она не такая и глобальная, статическая переменная внутри самой lua_version(). В каком случае указатель на статическую переменную внутри функции может быть не равен указателю на ту же статическую переменную внутри той же функции? Когда это ДВЕ РАЗНЫХ ФУНКЦИИ. Из разных модулей, например. См. сорцы luaL_checkversion_ и lua_version .
Учим си с Оленем Бобом: 1. lua_version() возвращает G(L)->version; которое есть некое поле внутри приватной структуры L, это поле указатель на double. 2. в luaL_checkversion_() видите там такие звездочки в операции сравнения? это называется разыменование...
Учим lua с Оленем Бобом: 1. _VERSION это никакая не глобальная константа. В языке lua вообще нет констант. Это переменная внутри lua-vm, вот ее инициализация:
/* set global _VERSION */ lua_pushliteral(L, LUA_VERSION); lua_setfield(L, -2, "_VERSION");
и это является аналогом lua_version(), только для скриптов.
Так каким образом lua_version() вернет нам 0.0? Самый простой ответ, в случае, если структура L, или ее части (см. макрос G(L)) имеют другой layout, это может случиться, если версии lua кардинально различаются, например. Но возможны и любые другие варианты.
Далее. Из квика можно полностью удалить lua5.1.dll и квик 8.5 будет нормально работать. но проблема остается.
Все это говорит о том, что ваша теория про "разные модули" не совсем верна.
rst9 написал: Все это говорит о том, что ваша теория про "разные модули" не совсем верна.
Я уже выше написал, что она неверна в данном случае. Если все работает как надо, она - единственный вариант, но в данном случае стейт не инициализирован, в version NULL, и если не хачили lua_newstate, то это может быть только путем игнора ошибки при инициализации.
ps: очевидно, что код на сайте lua и код, используемый в квике - разный. потому, что сообщение имеет вид "multiple Lua VMs detected. Expected 5.3 instead of 0.0". так, что мы вообще не знаем, что там за код.
Но можем предполагать, что половина сорцев собрана как си, а половина как плюсы, поэтому где-то вылетают лонгджампы, а где-то ожидаются эксепшены. Конкретно в lua53.dll я увидел одни джампы. В то же время в qlua.dll код явно плюсовый. Очевидно, поскольку это плюсы, LUAI_THROW и LUAI_TRY определены как плюсовые, через эксепшены. А lua53.dll делает джампы. Вот ничего и не ловится. Арке стоит убедиться, что все сорцы луа компилируются как плюсы, а не как си (/TP для компилятора).
это может случиться, если L создан не lua53.dll. если мы физически удалим lua5.1.dll, то и не кодом внутри lua5.1.dll. а это значит, что там адский ад какой-то.
rst9 написал: в mylib в функции luaopen_mylib() вызываем lua_version(L), с переданным в luaopen_mylib L, из lua53.dll. ее результат равен 0.0. не 5.3 и не 5.1.
Упорный вы какой. Это УКАЗАТЕЛЬ. Функция lua_version() ВОЗВРАЩАЕТ УКАЗАТЕЛЬ. Не 5.3, не 5.1, а УКАЗАТЕЛЬ.
в дельфи неправильно объявлена lua_version. итого. у нас есть стейт, который передается в luaopen. он 503. мы создаем новый стейт, который тоже оказывается 503. вызываем luaL_openlibs() получаем странное "multiple Lua VMs detected. Expected 5.3 instead of 0.0". очевидно, это не эта ветка:
if (v != lua_version(NULL)) luaL_error(L, "multiple Lua VMs detected");
В общем, luaL_openlibs со стейтом из мейна работает, с новым стейтом выбрасывает исключение, через SEH оно отлавливается, там код какой-то длинный (плюсовое?). Если дать ему улететь, квиком вылавливается уже не оно, а 0x05 (ACCESS VIOLATION). Я продолжаю считать, что по крайней мере внешние проявления вызваны смешиванием лонгджампов с эксепшенами, а уж что там изначально за ошибка, надо рыть. Без символов голый асм ковырять как-то тоскливо очень, оставим арке арково.
Примитивная dll в OnAllTrade просто дергать напр getInfoParam("VERSION") и больше вообще ничего, никаких эксепшенов, но после коннекта и получения прим 50-100 тыс тиков валится:
Critical error ACCESS_VIOLATION in script...
Что это за беда такая может быть?...
Если в OnAllTrade вообще ничего не делать, пустышка, то не падает. Но такой способ обхода проблемы не очень подходит :)
Latrop написал: Critical error ACCESS_VIOLATION in script
Это теперь так ошибки обрабатываются ) Надеюсь, поправят скоро.
А по существу - должна по идее какая-то ошибка случаться, но воспроизвести не удалось, перезаказал твс, догрузилась до текущего момента и ничего не упало. Вот таким вот образом пробовал
Господа, а у вас вызов функций Квика через lua_call из своих потоков с новым состоянием вообще работет?
Создаю новое состояние через lua_newthread(L), передаю его с свой поток, созданный через _beginthreadex, из этого потока вызываю функцию через lua_call. И ничего не проиходит - на верхушке стека остается название функции. Если вызывать lua_call из потоков Квика (с его состоянием), все в порядке.
Раньше свою длл нужно было с qlua.dll линковать, как раз что-то с потоками было связано. Теперь в ней нет функций, прилинковал свою длл к lua53.dll.
quio написал: Раньше свою длл нужно было с qlua.dll линковать
Вообще-то с lua5.1.dll от квика, насчет qlua.dll кто-то дезу пустил и так и пошло. Впрочем, работало тоже.
Цитата
quio написал: Создаю новое состояние через lua_newthread(L), передаю его с свой поток, созданный через _beginthreadex, из этого потока вызываю функцию через lua_call. И ничего не проиходит
quio написал: Создаю новое состояние через lua_newthread(L), передаю его с свой поток, созданный через _beginthreadex, из этого потока вызываю функцию через lua_call.
это плохая идея. а еще она не имеет ничего общего с, поднятым мной, вопросом арке по поводу конкретного бага.
quio написал: "Потокобезопасные функции для работы с таблицами Lua" ссылка именно на qlua.dll
не надо искать тайные смыслы там, где их нет. в первых версиях квика (довольно долго) с поддержкой lua вообще не было никакой lua5.1.dll, а была только qlua.dll. по-этому в доке указана она. хелп просто не меняли.
Цитата
quio написал: Да вот проблема похоже во вновь создаваемых состояниях.
вообще ничего общего. кроме того, то как вы пытаетесь использовать корутины - это зло.
Назвал этого франкенштейна QLuaCheckVersion. Вызовы его натыканы в самых неожиданных местах, в luaL_newmetatable например. И в том числе во всех luaopen_*. Видимо, как-то связано с присутствием lua5.1.dll и попыткой обеспечить совместимость. Но самое смешное вот в чем: весь луа таки собран с лонгджампами, теперь это стопроцентно известно, но вот этот довесок кидает исключение, единственное во всей длл.
quio написал: Создаю новое состояние через lua_newthread(L), передаю его с свой поток, созданный через _beginthreadex, из этого потока вызываю функцию через lua_call. И ничего не проиходит - на верхушке стека остается название функции. Если вызывать lua_call из потоков Квика (с его состоянием), все в порядке.
Здравствуйте! Проблема изучается. Постараемся в ближайшее время дать ответ.
Latrop написал: Примитивная dll в OnAllTrade просто дергать напр getInfoParam("VERSION") и больше вообще ничего, никаких эксепшенов, но после коннекта и получения прим 50-100 тыс тиков валится:
Critical error ACCESS_VIOLATION in script...
Что это за беда такая может быть?...
Если в OnAllTrade вообще ничего не делать, пустышка, то не падает. Но такой способ обхода проблемы не очень подходит :)
Здравствуйте! Проблема изучается. Постараемся в ближайшее время дать ответ.
rst9 написал: даже еще веселее: lua_version() для инстанса, передаваемого в luaopen_ возвращает значение 0.0 (должна, очевидно, 5.3), а для создаваемого нового инстанса luaL_newstate() - luaversion() возвращает мусорное значение (должна так же возвращать 5.3).
Здравствуйте! Проблема изучается. Постараемся в ближайшее время дать ответ.
Anton написал: Но самое смешное вот в чем: весь луа таки собран с лонгджампами, теперь это стопроцентно известно, но вот этот довесок кидает исключение, единственное во всей длл.
это, само по себе, не является проблемой. это, что называется, the way things are.
rst9 написал: это, само по себе, не является проблемой.
Увы и ах, является. Функция вызывается из других функций луа (которые собраны как сишные) и кидает исключение, кроме того, какие-то функции квика по-любому должны вызываться внутри qlua, а они внезапно плюсовые и тоже могут кидать исключения. Луа ждет лонгджампа, исключение пролетит мимо него и будет поймано уже квиком над луа, то есть вся обработка ошибок луа тупо отключается. Не думаю, что так хотели, просто просмотрели. Старый-то луа с эксепшенами был собран и все было хорошо. Вот прям сейчас добавить /TP всем луа-файлам и все соберется без проблем, дело буквально на десять минут, и тогда уже можно дальше смотреть, что еще не так, потому что сейчас дальше смотреть незачем, сейчас любая ошибка повышается до полного краха луа-машины.
Anton написал: Луа ждет лонгджампа, исключение пролетит мимо него и будет поймано уже квиком над луа, то есть вся обработка ошибок луа тупо отключается.
плевать они на это хотели. при завершении скрипта квик извещает программу, ждет 5 секунд, и если тред не завершился, то делает kill и и освобождает занятую lua-vm память. на то, что lua что-то там ждет - плевать. это тот же случай. если это возникло - тупо все стопим и освобождаем, на ошметки плевать. вполне в стиле.
Не совсем так, ждет сколько скажут в OnStop. А в целом такой подход "сгорел сарай гори и хата" неправильный, тогда можно вообще не морочиться, натыкать абортов повсюду и все. Все ж я исхожу из того, что хотели как лучше, назвался хостом - давай уже обеспечь, что хост не крэшится и не течет из-за косяков в загружаемом коде.
Latrop написал: Critical error ACCESS_VIOLATION in script
Это теперь так ошибки обрабатываются ) Надеюсь, поправят скоро.
А по существу - должна по идее какая-то ошибка случаться, но воспроизвести не удалось, перезаказал твс, догрузилась до текущего момента и ничего не упало. Вот таким вот образом пробовал
Огромный респект за проверку! Дало повод не грешить на lua, а разобраться глубже и найти проблему. Это сборщик мусора мою функцию прибирал таким образом.
Latrop написал: Примитивная dll в OnAllTrade просто дергать напр getInfoParam("VERSION") и больше вообще ничего, никаких эксепшенов, но после коннекта и получения прим 50-100 тыс тиков валится:
Critical error ACCESS_VIOLATION in script...
Что это за беда такая может быть?...
Если в OnAllTrade вообще ничего не делать, пустышка, то не падает. Но такой способ обхода проблемы не очень подходит :)
Здравствуйте! Проблема изучается. Постараемся в ближайшее время дать ответ.
Одна "Проблема изучается" минус. По этой части можно уже не изучать :)
Anton написал: Все ж я исхожу из того, что хотели как лучше
именно по-этому это и сделано так. lua - это все же си библиотека. и расширения, которые для нее пишутся, в основном, подразумевают что все это в стиле си. возможно, хотели сохранить это, мы не узнаем. в любом случае - несовместимый с кодом lua-state - это нечто, что вряд ли можно корректно обработать внутри lua.
Сомневаюсь. Тогда бы из QLuaCheckVersion сделали лонгджамп, а не throw ) Думаю, упустили из виду впопыхах. Старый-то собирали плюсами и не думали о таких высоких материях. Тем более сям по барабану на эксепшены, а вот плюсам на лонгджампы нет, очевидно же, какой вариант стоит выбрать.
Добавлю еще один пунктик в пользу эксепшенов. Они - zero-cost, в отличие от лонгджампов. На первый взгляд, много ли их там... но вспоминаем lua_pcall и как часто ее используют.
rst9 написал: воспроизвести можно так: 1. создаем dll, в ней линкуемся с lua53.dll. 2. в luaopen_... создаем новый инстанс lua vm при помощи luaL_newstate() 3. инициализируем его при помощи luaL_openlibs() получаем исключение "multiple Lua VMs detected. Expected 5.3 instead of 0.0"
что-то вы там не доделали, исправьте, пожалуйста. спасибо.
Добрый день,
Действительно, есть ошибка загрузки lua53.dll в сторонние приложения. Мы исправим её в ближайшем обновлении ПО. Приносим извинения за доставленные неудобства.
quio написал: Господа, а у вас вызов функций Квика через lua_call из своих потоков с новым состоянием вообще работет?
Создаю новое состояние через lua_newthread(L), передаю его с свой поток, созданный через _beginthreadex, из этого потока вызываю функцию через lua_call. И ничего не проиходит - на верхушке стека остается название функции. Если вызывать lua_call из потоков Квика (с его состоянием), все в порядке.
Раньше свою длл нужно было с qlua.dll линковать, как раз что-то с потоками было связано. Теперь в ней нет функций, прилинковал свою длл к lua53.dll.
Добрый день,
В Lua машине 5.3.5 нет такой функции как lua_call (). Есть её аналог lua_callk. Используйте ее. Либо добавьте в свой код что то вроде этого: #define lua_call(L,n,r) lua_callk(L, (n), ®, 0, NULL)