Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в эту темуОткрыть новую тему
> CreateThread блокирует ffi.C.Sleep
DarkMaster
сообщение 1.6.2024, 17:23
Сообщение #1


***********

Модератор UOPilot
Сообщений: 9.487
Регистрация: 2.12.2008
Группа: Супермодераторы
Наличность: 28025
Пользователь №: 11.279



code
Код
local ffi = require("ffi")

ffi.cdef[[
    typedef void* HANDLE;
    typedef void* HWND;
    typedef void* HINSTANCE;
    typedef unsigned int UINT;
    typedef int BOOL;
    typedef const char* LPCSTR;
    typedef long LONG;
    typedef unsigned int DWORD;
    typedef unsigned long long UINT_PTR;
    typedef void* LPVOID;
    typedef void* HMODULE;
    typedef int (__stdcall *THREAD_START_ROUTINE)(LPVOID lpThreadParameter);
    typedef UINT_PTR (__stdcall *TIMERPROC)(HWND, UINT, UINT_PTR, DWORD);
    typedef unsigned int WPARAM;
    typedef long LPARAM;
    typedef void* HFONT;

    HWND __stdcall CreateWindowExA(
        LONG     dwExStyle,
        LPCSTR   lpClassName,
        LPCSTR   lpWindowName,
        LONG     dwStyle,
        int      x,
        int      y,
        int      nWidth,
        int      nHeight,
        HWND     hWndParent,
        void*    hMenu,
        HINSTANCE hInstance,
        void*    lpParam
    );

    BOOL __stdcall ShowWindow(
        HWND hWnd,
        int  nCmdShow
    );

    BOOL __stdcall UpdateWindow(
        HWND hWnd
    );

    int __stdcall MessageBoxTimeoutA(
        HWND    hWnd,
        LPCSTR  lpText,
        LPCSTR  lpCaption,
        UINT    uType,
        UINT    wLanguageId,
        UINT    dwMilliseconds
    );

    BOOL __stdcall DestroyWindow(
        HWND hWnd
    );

    DWORD __stdcall GetCurrentThreadId();

    HMODULE __stdcall GetModuleHandleA(
        LPCSTR lpModuleName
    );

    HANDLE __stdcall CreateThread(
        void* lpThreadAttributes,
        size_t dwStackSize,
        THREAD_START_ROUTINE lpStartAddress,
        LPVOID lpParameter,
        DWORD dwCreationFlags,
        DWORD* lpThreadId
    );

    BOOL __stdcall CloseHandle(
        HANDLE hObject
    );

    UINT_PTR __stdcall SetTimer(
        HWND     hWnd,
        UINT_PTR nIDEvent,
        UINT     uElapse,
        TIMERPROC lpTimerFunc
    );

    BOOL __stdcall KillTimer(
        HWND     hWnd,
        UINT_PTR uIDEvent
    );

    typedef struct {
        int x;
        int y;
    } POINT;

    typedef struct {
        HWND   hwnd;
        UINT   message;
        uintptr_t wParam;
        intptr_t lParam;
        DWORD  time;
        POINT  pt;
    } MSG;

    typedef intptr_t LRESULT;

    typedef struct {
        uint32_t size;
        uint32_t pos_x;
        uint32_t pos_y;
        uint32_t timeout;
        const char* text;
    } HintStruct;

    BOOL __stdcall GetMessageA(
        MSG* lpMsg,
        HWND hWnd,
        UINT wMsgFilterMin,
        UINT wMsgFilterMax
    );

    BOOL __stdcall TranslateMessage(
        const MSG* lpMsg
    );

    LRESULT __stdcall DispatchMessageA(
        const MSG* lpMsg
    );

    int __stdcall SendMessageA(
        HWND   hWnd,
        UINT   Msg,
        WPARAM wParam,
        LPARAM lParam
    );

    HFONT __stdcall CreateFontA(
        int     nHeight,
        int     nWidth,
        int     nEscapement,
        int     nOrientation,
        int     fnWeight,
        unsigned long fdwItalic,
        unsigned long fdwUnderline,
        unsigned long fdwStrikeOut,
        unsigned long fdwCharSet,
        unsigned long fdwOutputPrecision,
        unsigned long fdwClipPrecision,
        unsigned long fdwQuality,
        unsigned long fdwPitchAndFamily,
        LPCSTR  lpszFace
    );

    void Sleep(unsigned int dwMilliseconds);

    static const int WM_SETFONT = 0x0030;
]]

local kernel32 = ffi.load("kernel32")
local function createWindowAsync()
  ffi.cdef[[
    void Sleep(unsigned int dwMilliseconds);
  ]]
  ffi.C.Sleep(1000)
  return 0
end

local function test()
  local threadId = ffi.new("DWORD[1]")
  local threadHandle = kernel32.CreateThread(nil, 0, ffi.cast("THREAD_START_ROUTINE", createWindowAsync), ffi.cast("LPVOID", 500), 0, threadId)
  kernel32.CloseHandle(threadHandle)
end

while 1 do
  print"!!!!!!!!!!!!!"
  test()
  print(111)
  print(222)
  print(333)
  ffi.C.Sleep(1000)
  print"sleep end"
end


Создавал окно, обратил внимание, что если окно еще живо, то вызов ffi.C.Sleep наглухо вешает основной поток. Обрезал код до минимума, чтобы воспроизводимость ошибки осталась. Так он еще и внутри нового потока стал с некоторым шансом забывать ffi.C.Sleep. Что не так?


--------------------
Скрипты UOPilot под заказ.
Консультации по UOpilot 15$/час.
Услуги Lua разработчика (не пилот, проекты, постоянка)
Disсоrd:
Kov____
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
Cockney
сообщение 1.6.2024, 23:22
Сообщение #2


********

Master
Сообщений: 1.397
Регистрация: 22.6.2013
Группа: Пользователи
Наличность: 21342
Пользователь №: 16.156



внимательней нужно читать https://learn.microsoft.com/en-us/windows/w...-synchapi-sleep



Цитата
Code that directly or indirectly creates windows (for example, DDE and COM CoInitialize). If a thread creates any windows, it must process messages. Message broadcasts are sent to all windows in the system. If you have a thread that uses Sleep with infinite delay, the system will deadlock.
Пользователь в онлайне!Delete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
DarkMaster
сообщение 2.6.2024, 2:34
Сообщение #3


***********

Модератор UOPilot
Сообщений: 9.487
Регистрация: 2.12.2008
Группа: Супермодераторы
Наличность: 28025
Пользователь №: 11.279



ну так мы для этого и создаем поток. в одном потоке крутится окно и читаются сообщения, основной же поток встает на паузу. Причем даже если ты сделаешь вызов:
while 1 do
ffi.C.Sleep(1) -- 1 мс
end
что к локу привести не должно, темболее это основной поток в котором не находится окно, все равно все повиснет намертво. При этом если же вызвать слип, скажем на 10 секунд при существовании окна только 5 секунд, то лока не получится. Код который обрабатывал поток с окном был н<вырезано анти-матом>кирующем, окно не зависало. Так же обращаю внимание, что в текущем огрызке кода вообще никакие окна не создаются. Тупо создается новый поток, висит 1 секунду и завершается. При этом мы получаем какие-то дики ошибки, создается впечатление, что там что-то бьется и перезаписывается в памяти.

вобщем дальнейшие поиски оказались неожиданными. нитки безопасно из luajit не создаются. Для их создания в безопасном виде необходимо jit.off(). Так же функция которая передается, как инициализирующа не должна быть C функцией (возможно так же нельзя использовать далее по стеку C функции). Как альтернативу предлагали lua_newstate или как ее. Короче еще одну среду форкать из луа. Что-то в этом есть, это какой-то апогей всей структуры луа в котрой таблица в таблице в метатаблице, так еще и луа завернем в луа.

ну либо сторонние либы. в частности ты одну компилил =)

Сообщение отредактировал DarkMaster - 2.6.2024, 2:35


--------------------
Скрипты UOPilot под заказ.
Консультации по UOpilot 15$/час.
Услуги Lua разработчика (не пилот, проекты, постоянка)
Disсоrd:
Kov____
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
DarkMaster
сообщение 2.6.2024, 17:15
Сообщение #4


***********

Модератор UOPilot
Сообщений: 9.487
Регистрация: 2.12.2008
Группа: Супермодераторы
Наличность: 28025
Пользователь №: 11.279



Вобщем как новый экземпляр со стринга стартнуть вроде разорался. А вот из существующей функции чет не пойму. Там вроде через lua_getfield надо. Сколько не крутил nil дергает. Пусть это тут отстанется - может пригодится.
запуск отдельного экземпляра lua
Код

local ffi = require 'ffi'
local C = ffi.C
ffi.cdef [[
    typedef struct lua_State lua_State;
    lua_State *luaL_newstate();
    void Sleep(unsigned int dwMilliseconds);
    void luaL_openlibs(lua_State *L);
    int luaL_loadstring (lua_State *L, const char *s);
    void lua_call (lua_State *L, int nargs, int nresults);
]]

-- Код передаваемый на исполнение
local lua_code = [[
    function my_function()
        local f = io.open("D:\\!IDDQD.txt", "wb+")
        f:close()
        print("Hello from Lua function!")
    end

    my_function()
]]

-- Создаем новый объект состояния Lua
local state = C.luaL_newstate()
-- Загружаем стандартные либы io, math, string и т.д.
C.luaL_openlibs(state)
-- Загружаем код Lua
C.luaL_loadstring(state, lua_code)
C.lua_call(state, 0, 0)

C.Sleep(10000)


Сообщение отредактировал DarkMaster - 2.6.2024, 17:18


--------------------
Скрипты UOPilot под заказ.
Консультации по UOpilot 15$/час.
Услуги Lua разработчика (не пилот, проекты, постоянка)
Disсоrd:
Kov____
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
Cockney
сообщение 2.6.2024, 17:35
Сообщение #5


********

Master
Сообщений: 1.397
Регистрация: 22.6.2013
Группа: Пользователи
Наличность: 21342
Пользователь №: 16.156



Совета не спрашивали, но имхо - зачем возиться с окнами (первоначальная задача вроде в них) на голом вин апи ? намного приятнее взять delphi/c# и сделать приложение, которое по запросам через tcp будет делать что нужно, и уведомлять скрипты на луа, + интерфейсы куда мощнее возможно делать, а не 105 вызовов на рисование пустой кнопки в вин апи
Пользователь в онлайне!Delete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
DarkMaster
сообщение 2.6.2024, 17:42
Сообщение #6


***********

Модератор UOPilot
Сообщений: 9.487
Регистрация: 2.12.2008
Группа: Супермодераторы
Наличность: 28025
Пользователь №: 11.279



создаем экзепляр из готовой lua функции
Код
local ffi = require 'ffi'
local C = ffi.C
ffi.cdef [[
  typedef struct lua_State lua_State;
  lua_State *luaL_newstate();
  void Sleep(unsigned int dwMilliseconds);
  void luaL_openlibs(lua_State *L);
  void lua_call (lua_State *L, int nargs, int nresults);
  typedef int (*lua_CFunction)(lua_State *L);
  void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
]]

local f = function()
    print"Where am i?"
    local f = io.open("D:\\!IDDQD.txt", "wb+")
    f:close()
    return 0 -- Вернуться должен 0, иначе error кинет.
end

-- Создаем новый объект состояния Lua
local state = C.luaL_newstate()
-- Пушим функцию
C.lua_pushcclosure (state, f, 0)
-- Загружаем стандартные либы io, math, string и т.д.
C.luaL_openlibs(state)
-- Выполняем функцию
C.lua_call(state, 0, 0)

C.Sleep(10000)


Цитата
Совета не спрашивали, но имхо - зачем возиться с окнами (первоначальная задача вроде в них) на голом вин апи ? намного приятнее взять delphi/c# и сделать приложение, которое по запросам через tcp будет делать что нужно, и уведомлять скрипты на луа, + интерфейсы куда мощнее возможно делать, а не 105 вызовов на рисование пустой кнопки в вин апи

Я тупо хотел хинт оживить, а тут вон как получилось. Я грешным делом уже смотрел на iup, wx и вспоминал твои слова, что не нужно трогать интерфесы пилота и делать, то, что уже сделано ибо там пропадешь с концами.

Сообщение отредактировал DarkMaster - 2.6.2024, 17:46


--------------------
Скрипты UOPilot под заказ.
Консультации по UOpilot 15$/час.
Услуги Lua разработчика (не пилот, проекты, постоянка)
Disсоrd:
Kov____
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения
DarkMaster
сообщение 2.6.2024, 21:58
Сообщение #7


***********

Модератор UOPilot
Сообщений: 9.487
Регистрация: 2.12.2008
Группа: Супермодераторы
Наличность: 28025
Пользователь №: 11.279



подгружать через require
вызов:
Код
local hint = require"hint"
hint(text, size, pos_x, pos_y, width, height, timeout)

В рамках пилота есть особенность - окно хинта закроется только после таймаута, даже если скрипт уже остановлен. Особенности реализации пилота. В чистом луа такого поведения нет.
hint
Код
--lua
local ffi = require 'ffi'
local C = ffi.C
ffi.cdef [[
    typedef struct lua_State lua_State;
    lua_State *luaL_newstate();
    void Sleep(unsigned int dwMilliseconds);
    void luaL_openlibs(lua_State *L);
    int luaL_loadstring (lua_State *L, const char *s);
    void lua_call (lua_State *L, int nargs, int nresults);
]]


local lua_code = [=====[
local mega_f = function(...)
local ffi = require("ffi")
local C   = ffi.C

ffi.cdef[[
    typedef void* HANDLE;
    typedef void* HWND;
    typedef void* HINSTANCE;
    typedef unsigned int UINT;
    typedef int BOOL;
    typedef const char* LPCSTR;
    typedef long LONG;
    typedef unsigned int DWORD;
    typedef unsigned long long UINT_PTR;
    typedef void* LPVOID;
    typedef void* HMODULE;
    typedef int (__stdcall *THREAD_START_ROUTINE)(LPVOID lpThreadParameter);
    typedef UINT_PTR (__stdcall *TIMERPROC)(HWND, UINT, UINT_PTR, DWORD);
    typedef unsigned int WPARAM;
    typedef long LPARAM;
    typedef void* HFONT;

    HWND __stdcall CreateWindowExA(
        LONG     dwExStyle,
        LPCSTR   lpClassName,
        LPCSTR   lpWindowName,
        LONG     dwStyle,
        int      x,
        int      y,
        int      nWidth,
        int      nHeight,
        HWND     hWndParent,
        void*    hMenu,
        HINSTANCE hInstance,
        void*    lpParam
    );

    BOOL __stdcall ShowWindow(
        HWND hWnd,
        int  nCmdShow
    );

    BOOL __stdcall UpdateWindow(
        HWND hWnd
    );

    int __stdcall MessageBoxTimeoutA(
        HWND    hWnd,
        LPCSTR  lpText,
        LPCSTR  lpCaption,
        UINT    uType,
        UINT    wLanguageId,
        UINT    dwMilliseconds
    );

    BOOL __stdcall DestroyWindow(
        HWND hWnd
    );

    DWORD __stdcall GetCurrentThreadId();

    HMODULE __stdcall GetModuleHandleA(
        LPCSTR lpModuleName
    );

    HANDLE __stdcall CreateThread(
        void* lpThreadAttributes,
        size_t dwStackSize,
        THREAD_START_ROUTINE lpStartAddress,
        LPVOID lpParameter,
        DWORD dwCreationFlags,
        DWORD* lpThreadId
    );

    BOOL __stdcall CloseHandle(
        HANDLE hObject
    );

    UINT_PTR __stdcall SetTimer(
        HWND      hWnd,
        UINT_PTR  nIDEvent,
        UINT      uElapse,
        TIMERPROC lpTimerFunc
    );

    BOOL __stdcall KillTimer(
        HWND     hWnd,
        UINT_PTR uIDEvent
    );

    typedef struct {
        int x;
        int y;
    } POINT;

    typedef struct {
        HWND       hwnd;
        UINT       message;
        uintptr_t  wParam;
        intptr_t   lParam;
        DWORD      time;
        POINT      pt;
    } MSG;

    typedef intptr_t LRESULT;

    typedef struct {
        uint32_t size;
        uint32_t pos_x;
        uint32_t pos_y;
        uint32_t width;
        uint32_t height;
        uint32_t timeout;
        const char* text;
    } HintStruct;

    BOOL __stdcall GetMessageA(
        MSG* lpMsg,
        HWND hWnd,
        UINT wMsgFilterMin,
        UINT wMsgFilterMax
    );

    BOOL __stdcall TranslateMessage(
        const MSG* lpMsg
    );

    LRESULT __stdcall DispatchMessageA(
        const MSG* lpMsg
    );

    int __stdcall SendMessageA(
        HWND   hWnd,
        UINT   Msg,
        WPARAM wParam,
        LPARAM lParam
    );

    HFONT __stdcall CreateFontA(
        int     nHeight,
        int     nWidth,
        int     nEscapement,
        int     nOrientation,
        int     fnWeight,
        unsigned long fdwItalic,
        unsigned long fdwUnderline,
        unsigned long fdwStrikeOut,
        unsigned long fdwCharSet,
        unsigned long fdwOutputPrecision,
        unsigned long fdwClipPrecision,
        unsigned long fdwQuality,
        unsigned long fdwPitchAndFamily,
        LPCSTR  lpszFace
    );

    void Sleep(unsigned int dwMilliseconds);

    static const int WM_SETFONT = 0x0030;

    typedef struct lua_State lua_State;
    lua_State *luaL_newstate();
    void Sleep(unsigned int dwMilliseconds);
    void luaL_openlibs(lua_State *L);
    void lua_call (lua_State *L, int nargs, int nresults);
    typedef int (*lua_CFunction)(lua_State *L);
    void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n);
]]

local user32   = ffi.load("user32")
local kernel32 = ffi.load("kernel32")
local Gdi32    = ffi.load("Gdi32.dll")
local sleep    = C.Sleep

-- Переменная для хранения дескриптора окна с сообщением
local previousMessageWindow = nil

local function createWindow(HintStruct)
    local hwnd = user32.CreateWindowExA(
        0,                -- dwExStyle
        "STATIC" ,         -- lpClassName
        HintStruct.text,  -- lpWindowName
        0x80000000,       -- dwStyle WS_POPUP
        HintStruct.pos_x, -- x
        HintStruct.pos_y, -- y
        HintStruct.width, -- nWidth
        HintStruct.height,-- nHeight
        nil,              -- hWndParent
        nil,              -- hMenu
        nil,              -- hInstance
        nil               -- lpParam
    )

    -- Создаем шрифт
    local hFont = Gdi32.CreateFontA(
        HintStruct.size, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, "Arial"
    )

    -- Устанавливаем шрифт
    local res = user32.SendMessageA(hwnd, C.WM_SETFONT, ffi.cast("WPARAM", hFont), 1)


    user32.ShowWindow(hwnd, 5) -- SW_SHOW
    user32.UpdateWindow(hwnd)

    return hwnd
end

local function createTimer(hwnd, timeout)
    local timerId = user32.SetTimer(hwnd, 1, timeout, nil)
    return timerId
end

local function destroyTimer(hwnd, timerId)
    user32.KillTimer(hwnd, timerId)
end

local function createWindowAsync(HintStruct)
    HintStruct = ffi.cast("HintStruct*", HintStruct)
    -- Если предыдущее окно существует, закрываем его
    if previousMessageWindow ~= nil then
      print"_____"
        user32.DestroyWindow(previousMessageWindow)
        print"XXXX"
        previousMessageWindow = nil
    end

    local hwnd = createWindow(HintStruct)

    -- Сохраняем дескриптор текущего окна как предыдущий
    previousMessageWindow = hwnd

    if hwnd ~= nil then
        local timerId = createTimer(hwnd, HintStruct.timeout) -- Set timer for specified timeout

        -- Н<вырезано анти-матом>кирующее ожидание событий окна
        local start = os.clock()
        while os.clock() - start < HintStruct.timeout / 1000 do
            local msg = ffi.new("MSG")
            local result = user32.GetMessageA(msg, nil, 0, 0)
            if type(result) == 'number' and result > 0 then
                user32.TranslateMessage(msg)
                user32.DispatchMessageA(msg)
            end
        end

        destroyTimer(hwnd, timerId) -- Destroy timer
        user32.DestroyWindow(hwnd) -- Destroy window

        -- Обнуляем дескриптор предыдущего окна, так как оно уже было закрыто
        previousMessageWindow = nil
    else
        print("Failed to create window")
    end

    return 0
end



local function hint(text, size, pos_x, pos_y, width, height, timeout)
print(text)
print(size)
print(pos_x)
    local HintStruct = ffi.new("HintStruct")
    HintStruct.text    = text
    HintStruct.size    = size
    HintStruct.pos_x   = pos_x
    HintStruct.pos_y   = pos_y
    HintStruct.width   = width
    HintStruct.height  = height
    HintStruct.timeout = timeout
    local threadId = ffi.new("DWORD[1]")
    local threadHandle = kernel32.CreateThread(nil, 0, ffi.cast("THREAD_START_ROUTINE", createWindowAsync), ffi.cast("LPVOID", HintStruct), 0, threadId)
    kernel32.CloseHandle(threadHandle)
    return 0
end

]=====]

local create_state = function(text, size, pos_x, pos_y, width, height, timeout)
    local text    = text             and  tostring(text) or "text"
    local size    = size              or    24
    local pos_x   = pos_x             or     0
    local pos_y   = pos_y             or     0
    local width   = width             or   400
    local height  = height            or   200
    local timeout = timeout           or  5000

    print(text)
    print([[hint(']]..
                      text.."', "..size..", "..
                      pos_x..", "..pos_y..", "..
                      width..", "..height..", "..
                      timeout)

    -- Создаем новый объект состояния Lua
    local state = C.luaL_newstate()
    -- Загружаем стандартные либы io, math, string и т.д.
    C.luaL_openlibs(state)
    -- Загружаем код Lua
    C.luaL_loadstring(state, lua_code..[[hint(']]..
                      text.."', "..size..", "..
                      pos_x..", "..pos_y..", "..
                      width..", "..height..", "..
                      timeout..[[)
                      return 0
                      end
                      mega_f()]])
    C.lua_call(state, 0, 0)

    return 0
end

return create_state


По созданию нового state. Если передавать уже готовые функции, то весь набор проблем никуда не денется. Пришлось текстом код пушить...


--------------------
Скрипты UOPilot под заказ.
Консультации по UOpilot 15$/час.
Услуги Lua разработчика (не пилот, проекты, постоянка)
Disсоrd:
Kov____
Пользователь в офлайнеDelete PostОтправить личное сообщение
Вернуться в начало страницы
+Ответить с цитированием данного сообщения

Ответить в эту темуОткрыть новую тему
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 

- Текстовая версия | Версия для КПК Сейчас: 7.6.2024, 23:56
Designed by Nickostyle