getSecurityInfo из dll

Страницы: 1
RSS
getSecurityInfo из dll, Периодически подвешивает Quik
 
С НГ, форумчане !

Из своей dll вызываю в цикле запрос getSecurityInfo
"
lua_getglobal(global_lua_state, "getSecurityInfo");
lua_pushstring(global_lua_state, class_code);
lua_pushstring(global_lua_state, sec_code);lua_call(global_lua_state, 2, 1);
"

собственно, по всем тикерам в одном цикле. И сейчас вдруг, иногда, в непредсказуемые моменты подвисает lua_call и, соответственно, подвешивает и сам Quik. Версия 5.3.5. Этом у меня тут что-то напутано или что еще может быть - куда копать ?
 
Разобрался, подвисало все иногда из-за включенной в dll обработке OnParam. Очевидно, в некоторые моменты происходит одновременные манипуляции со стэком в
lua_State из-за чего и сбой. Тогда получается, что нужно в разных потоках обрабатывать свои команды и quik события ? Или еще какие варианты ?
 
Цитата
BVladimir написал:
Очевидно, в некоторые моменты происходит одновременные манипуляции со стэком в lua_State из-за чего и сбой.
Именно. Не надо  сохранять стейт в глобальную переменную, в каждом колбеке (включая мейн)  надо использовать тот стейт, что в эту функцию передан.
 
Цитата
Anton написал:
Именно. Не надо  сохранять стейт в глобальную переменную, в каждом колбеке (включая мейн)  надо использовать тот стейт, что в эту функцию передан.
А как тогда правильно самому функции quik вызывать ? lua_newthread ?
 
Цитата
BVladimir написал:
самому функции quik вызывать
Ну вообще-то длл это просто набор функций, своей жизнью она по дизайну не живет. Соответственно любая деятельность происходит в ответ на колбек, а в колбек стейт передается. Если заводится свой поток в длл, который будет дергать луа, нужно, да, создать для него стейт через lua_newthread, я показывал как-то как именно. Но тут имейте в виду, что ваш поток должен завершиться при любом раскладе (нажата кнопка стоп, завершился мейн по своей инициативе, квик прибил скрипт за ошибку) до того, как квик прибьет объект скрипта, иначе выхватите акцесс виолейшен и обвалите весь квик.
 
Цитата
Anton написал:
Если заводится свой поток в длл, который будет дергать луа, нужно, да, создать для него стейт через lua_newthread
А что, есть возможность без нового потока "дергать" lua_State ? Просто у меня общая dll и для связи с quik и для связи с моей прогой. И из своей проги просто отправлял команду в dll, где по WaitForMultipleObjects как раз через ранее сохраненный глобальный lua_State, dll отправляла команду в quik.
 
Цитата
BVladimir написал:
есть возможность без нового потока "дергать" lua_State ?
Конечно, вам уже квик создал поток для мейна и стейт для него (почти таким же куском кода, как по ссылке выше я показывал). WaitForMultipleObjects вполне может быть в мейне, и использовать для дерганья луа он должен стейт, переданный в мейн. Также можно завести событие (CreateEvent) и добавить его в список ожидаемых объектов в мейне, и в колбеке OnStop ставить его (SetEvent), мейн в этом случае пойдет на выход вместо очередной итерации ожидания. Может быть, как-то посигналив вашей проге сначала, что банкет окончен. А в обратную сторону, как понимаю, из колбеков, используйте стейты, передаваемые в эти колбеки. Есть еще вариант создать в мейне очередь сообщений и использовать виндовые сообщения вместо объектов синхронизации. Оно малость медленнее (несущественно), но может быть проще в некотором смысле, т.к. получается по сути готовый конечный автомат и запутаться в нем меньше шансов.
 
Цитата
Anton написал:
WaitForMultipleObjects вполне может быть в мейне
Не ожидал. Я как раз отдельный поток выделил - типа сервер где обрабатывается WaitForMultipleObjects. А если все в main, думал что quik зависнет в ожидании... Но в обычном порядке state в main попадает только один раз при запуске скрипта, как я понимаю ? А в callback-ах не тот де самый state приходит ?
 
Цитата
BVladimir написал:
Но в обычном порядке state в main попадает только один раз при запуске скрипта, как я понимаю ? А в callback-ах не тот де самый state приходит ?
Да, на входе в мейн вы получаете стейт отдельного потока и он жив, пока мейн не вернулся, то есть действительно стейт мейна передается один раз на входе (в мейн). Все остальные колбеки в текущей реализации получают другой стейт (для всех колбеков одного скрипта один и тот же), но тут никаких гарантий нет, что так будет всегда, лучше сразу предположить, что у каждого колбека может быть свой отдельный стейт и не создавать себе на будущее проблем.
 
Цитата
Anton написал:
Все остальные колбеки в текущей реализации получают другой стейт
Тогда у меня что-то не сходится:

"//это main
static int main_from_lua(lua_State* L) {       global_lua_state = L;
...

//это OnParam
static int OnParam_from_lua(lua_State* L) {        lua_settop(L, 0);    
   data_receive_time = GetTickCount64();    
   return 1;
}
"

Т.е. все команды шлются через global_lua_state полученный из main в момент запуска скрипта. И если убрать обработчика OnParam, то все работает, подключаю OnParam - начинает вешать quik, хотя там свой state должен быть...
 
Цитата
BVladimir написал:
global_lua_state = L;
Вот это надо убрать совершенно точно и внутри мейна использовать L напрямую. Уже убрав global_lua_state увидите, где еще этот стейт использовался. Затем, как понимаю, работал еще один поток, который дергал луа через global_lua_state, принадлежащий потоку мейна. На входе в любую lua_* функцию идет захват критической секции. Если вдруг она уже захвачена и мейн из своего потока еще раз пытается захватить, будет рекурсивный захват, что ок, а если мейн держит секцию и ее пытается захватить другой поток, будет дедлок. Возможно, отсюда ноги растут.

Цитата
BVladimir написал:
lua_settop(L, 0);        data_receive_time = GetTickCount64();        return 1;
Побочно: некрасиво, чистим стек и return 1, т.е. "эй луа, тут на стеке один элемент возвращен". Хотя по идее луа должен бы это съесть, но может и не ест.
 
Цитата
Anton написал:
Если вдруг она уже захвачена и мейн из своего потока еще раз пытается захватить, будет рекурсивный захват, что ок, а если мейн держит секцию и ее пытается захватить другой поток, будет дедлок. Возможно, отсюда ноги растут.
Ну так пока не включен обработчик OnParam со своим стейтом, то все ок и за 1 сек. lua_call с этим global_lua_state успешно отрабатывает более 26 тыс.раз. Только включаю обработчика, то может зависнуть на 10 вызове, а может на 1000-м... Хотя стайты точно разные в main и в обработчике. Если в main стэйт уже пришел, то адрес его уже не меняется. Сейчас из main я его не трогаю он используется только из одного потока, типа моего эвент-сервера и все хорошо до подключения обработчика...Дедлока, по идее, не может быть !
 
Цитата
BVladimir написал:
пока не включен обработчик OnParam
Все же поправьте его для начала. Вот в таком виде перестанет виснуть?
Код
static int OnParam_from_lua(lua_State* L) {    
    data_receive_time = GetTickCount64();    
    return 0;
}
 
Цитата
Anton написал:
Вот в таком виде перестанет виснуть?
Нет, повисает также. Похоже, что разные стэйты не такие уж и независимые. Буду переделывать на выполнение команд из main.
 
Цитата
BVladimir написал:
Похоже, что разные стэйты не такие уж и независимые.
Вы их выведите в лог (printf("%p\n", state)) и посмотрите. Так-то они действительно не совсем независимые, второй произведен от первого и у них общее глобальное пространство. Но блочить это не должно.

Мне вот мысль пришла, а какой транспорт используется? Если пайп, там очень легко устроить дедлок, когда в две стороны передача идет. Т.к. пайп с сообщениями блокируется, когда вторая сторона не полностью прочитала сообщение. Если она в этот момент попытается что-то отправить, все встанет колом.
 
Цитата
Anton написал:
Мне вот мысль пришла, а какой транспорт используется?
На стороне приложения просто SetEvent (именной, ранее созданный), на стороне quik - сервер с бесконечным WaitForMultipleObject, сработал, выполнил функцию quik, данные в общую память и ответил приложению, там соответственно WaitForSingleObject принял ответ, данные забрал и по новой. Сбой только при включении OnParam...
 
Перенес все в main, передаю стэйт как параметр для вызова функции quik и все равно если перехват OnParam подключен в dll,то подвешивает quik в непредсказуемые моменты. В режиме отладки отловил тут акцесс виолэйшн в lua53.dll. Если OnParam не перехватывать, то все идеально. Что же еще может быть тогда ?
 
BVladimir,  у вас все же где-то косячок-с. Вот глядите, примерно нечто в том же роде накропал (попроще) - ничего не виснет.

Скрытый текст
 
Цитата
Anton написал:
Вот глядите, примерно нечто в том же роде накропал
Этот пример и под 5.3.5 работает без сбоев ? Одна надежда, что дело в версии...

И еще эта строчка "extern "C" int __declspec(dllexport) load(lua_State * s)" это что ? Там же должен быть luaopen_...
 
Цитата
BVladimir написал:
под 5.3.5
не собирал. Уверен, что будет работать. Собственно, можете собрать, там внешних зависимостей нет, только пути к заголовкам поменять.

Цитата
BVladimir написал:
Там же должен быть luaopen_...
Это если грузить через require. Я загружаю длл так
Код
package.loadlib(getScriptPath()..'\\dllname.dll', 'load')()
, поэтому имя функции не имеет значения.
 
Цитата
Anton написал:
Собственно, можете собрать, там внешних зависимостей нет
Буду разбираться ! А еще у меня обычный lua_call, а в примере lua_callk. Есть какие-то преимущества ?
 
Цитата
BVladimir написал:
у меня обычный lua_call, а в примере lua_callk
Это одно и то же, lua_call просто макрос над lua_callk с теми же нулями в конце.
 
Пересобрал свою dll на 5.4.2 - и все заработало как часы! Дело оказалось только в версии -поверить не могу !

Кстати, в новой версии появилась помимо lua54.lib еще и lua54.dll. А смысл ?
 
Цитата
BVladimir написал:
в новой версии появилась помимо lua54.lib еще и lua54.dll
Как это появилась. Собственно luaXX.dll это и есть луа в составе квика. Вот тут возникает вопрос, а откуда у вас была lua53.lib, может это был весь луа в виде статической библиотеки, а не просто список экспорта от длл, как должно быть?
 
BVladimir,  сдается мне, вы собирали весь луа вместе со своим кодом (и в версии 5.3 у вас собирался статический луа, а в 5.4 динамический, поэтому получилась длл и более-менее правильная библиотека экспорта). От луа нужны только три заголовка luaconf.h, lua.h, lauxlib.h, все остальное включать в проект не надо, линковаться надо с luaXX.lib, полученной из luaXX.dll из состава квика с помощью dumpbin.
 
Цитата
Anton написал:
это был весь луа в виде статической библиотеки
Все верно ! А есть где прочитать, как тогда с 5.4.x правильно собираться, по пунктам ? А то про dumpbin вообще не понял...
 
Цитата
BVladimir написал:
как тогда с 5.4.x правильно собираться, по пунктам
Ну давайте здесь напишем ) Для любой версии луа
1) качаете с lua.org нужную версию луа в зипе
2) из зипа берете lua.h, luaconf.h, lauxlib.h, остальной зип можно выбросить
3) в папке с квиком создаете файл makelib.bat со следующим содержимым
Код
@echo off
setlocal enabledelayedexpansion
for /f "tokens=1-4" %%1 in ('dumpbin /exports %1') do (
    set /a ordinal=%%1 2>nul
    set /a hint=0x%%2 2>nul
    set /a rva=0x%%3 2>nul
    if !ordinal! equ %%1 if !hint! equ 0x%%2 if !rva! equ 0x%%3 set exports=!exports! /export:%%4
)
for /f %%i in ("%1") do set dllpath=%%~dpni
start lib /out:%dllpath%.lib /machine:x64 /def: %exports%
4) запускаете Visual Studio Command Prompt x64 release, переходите в папку с квиком, выполняете команду (скажем, для луа 5.3)
Код
makelib lua53.dll
5) в папке квика появляются файлы lua53.lib и lua53.exp. Файл .exp выбрасываете, он нам не нужен
6) в папку своего проекта копируете файлы lua.h, luaconf.h, lauxlib.h и полученный luaXX.dll
7) в своем проекте инклюдите как обычно
Код
extern "C" {
#include "luaconf.h"
#include "lua.h"
#include "lauxlib.h"
}
8) и указываете, с чем линковаться
Код
#pragma comment(lib, "luaXX.lib")
Все.
 
Цитата
Anton написал:
6) в папку своего проекта копируете файлы lua.h, luaconf.h, lauxlib.h и полученный luaXX.dll
поправочка, "и полученный luaXX.lib"
 
Спасибо. Ясно.Хорошо бы в отдельную тему вывести описание сборки !
Страницы: 1
Читают тему
Наверх