двух-трех потоков приходит вызов. Как мне блокировать остальные вызовы, пока я один отрабатываю?
Что-то вроде CriticalSection, пока он не завершился, все остальные вызовы холдятся.
Да есть, всякие Mutex, Critical Section и прочий вагон добра, м.б уже решал кто эту проблему?
Вот как выглядит в асме:
Non_reentrant_fn: push rcx rdx rbx
Lock (resource)
Blablabla...
Так вот пока я делаю push регистров, прилетает второй и третий вызов моей функции. Т.к стек общий, он тотально портится и программа крашится.
Без сохранения регистров вначале - никак, т.к Lock(resource) портит регистры.
Примерно такая же проблема, как с DOS, в котором нельзя было вызывать самого себя из-за нереентерабельности.
Как бы решить эту проблему?
так откуда вызовы то прилетают с других потоков в один стэк? Или с одного потока?
Собственный перехватчик mfc-шной dll, в части CInternetSession:GetHTTPConnection, вызывается из одной dll-ки, которая дергается из нескольких потоков. Т.е выглядит так Thread1: call MainDll, call CInternetSession:GetHTTPConnection Thread2: call MainDll, call CInternetSession:GetHTTPConnection На GetHTTPConnection висит собственный хук, который решает пускать далее в mfc-шный GetHTTPConnection или внутри себя обрабатывать
Меняй архитектуру, если, конечно, ты контролируешь код той функции...
Что бог послал, на том и работаю)))
Я прочитал, но та и не понял почему процедура не реентерабельна? И как так получается, что при каждом вызове общий стек?
Я смотрю по значению rsp
Что у тебя за отладчик?
У тебя точка останова на входе в твою процедуру?
Да, и перед вызовом собственной процедуры и в ней
Ты уверен, что у тебя эта точка останова отлавливается в одном потоке?
Да, а ей больше некуда деваться. При входе в мою процедуру поставил специально счетчик вызовов и при пошаговой трассировке вижу, что он уже несколько раз инкрементировался, пока я пошагово трассировал подготовку параметров для вызова моей функции. В Иде/x64dbg выглядит как произвольное изменение rip при пошаговой - всего лишь выщов одного и того же места из нескольких потоков
Вот еще почитай, может это поможет навести порядок: В Windows x86-64 используется единое соглашение вызовов __fastcall. Первые четыре целочисленных аргумента (слева направо) передаются в 64-битных регистрах RCX, RDX, R8 и R9. Остальные аргументы (целочисленные) передаются через стек (справа налево). Указатель this всегда хранится в регистре RCX. Даже если аргумент передан в регистре, вызывающая функция обязана резервировать для него место в стеке, уменьшая значение регистра RSP. За очистку стека отвечает вызывающая функция
У меня все процедуры по конвенции fastcall
Вот можно как сделать, что то типа такого generate $id; mutex $id; while i=1 $id.lock(); i=1; ..yourprogram.. i=0; $id.unlock(); только i надо обьявить в статике где то повыше чтоли или какой то другой триггер общий использовать семафор, можно тогда вообще без мутексов обойтись только while и скобками наверное это псевдокод ;) Вот такую функцию можно в качестве глобального счетчика использовать, прошу прощения за небольшой офтоп ну это в тему: HANDLE CreateSemaphore ( LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, // атр. доступа LONG lInitialCount, // начальное состояние счетчика LONG lMaximumCount, // макс кол-о обращений LPCTSTR lpName // имя объекта ); Это видимо надо в отдельном процессе создавать который не будет дуплицироваться BOOL ReleaseSemaphore ( HANDLE hSemaphore,// указатель на семафор LONG lReleaseCount, // на сколько изменять счетчик LPLONG lpPreviousCount // предыдущее значение ); В случае успеха возвращаемое значение — не ноль. —
Взаимодействие с винапи должно идти по его соглашению по, а не так как ты себе напридумывал
Произвольное изменение rip походит на некорректную отладку многопотока, такого не бывает, выведи в отладчике себе окно со списком потоков и гляди на каком именно потоке остановился отладчик
Обсуждают сегодня