Просмотр полной версии : [Function] dc_SleepFix
Daniel_Cortez
13.01.2016, 17:24
ВНИМАНИЕ: данная функция всё ещё не работает нигде, кроме функции main.
В ней только исправлена ошибка с неправильными значениями в указателе вершины стека (stack/heap collision), возникающая при очень частом использовании оператора sleep.
Скорее всего, вам эта функция нигде не пригодится, но я на всякий случай задокументирую её здесь.
Возможное использование: проведение тестов, в которых оператор sleep используется очень часто (в циклах, например). Мне хватило 2037 раз, чтобы вызвать ошибку времени выполнения обычным sleep - при использовании dc_SleepFix её нет.
Один из тестов можно найти здесь: http://pro-pawn.ru/showthread.php?13189
dc_SleepFix(time) // by Daniel_Cortez \\ pro-pawn.ru
{ // WARNING: This function is still only usable in main().
// It just fixes the stack/heap collision error in default sleep().
static heap_ptr, stack_ptr;
#emit lctrl 2
#emit stor.pri heap_ptr
#emit lctrl 4
#emit stor.pri stack_ptr
sleep(time);
#emit load.pri stack_ptr
#emit sctrl 4
#emit load.pri heap_ptr
#emit sctrl 2
}
#if defined _ALS_sleep
#undef sleep
#else
#define _ALS_sleep
#endif
#define sleep(%0) dc_SleepFix(%0)
Автор: Daniel_Cortez (http://pro-pawn.ru/member.php?100-Daniel_Cortez)
Специально для Pro-Pawn.ru (http://www.pro-pawn.ru)
Копирование данной статьи на других ресурсах без разрешения автора запрещено!
Вариант из fixes от Y_Less:
/*
* FIXES_sleep(const time)
*
* FIXES:
* sleep
*/
// Uses a little trick to consume part of the line and thus not match
// our hooked version.
#if defined _ALS_sleep
#error _ALS_sleep defined
#endif
#define BAD_sleep%0\n%9 sleep%0
#if FIX_sleep
stock FIXES_sleep(ms)
{
// Call a native function that does very little, but saves the current
// heap pointer. Then return to save the accurate stack pointer.
return heapspace(), ms;
}
#define _ALS_sleep
#define sleep%0\n%9 sleep FIXES_sleep(%0)
// This fixes another BIZZARE bug. Just doing:
//
// #define FIXES_sleep(%0;) FIXES_sleep(%0)
//
// Results in:
//
// FIXES_sleep(n));
//
// Which clearly it shouldn't. I've stepped through the compilation and that
// extra bracket comes from nowhere!
#define FIXES_sleep(%0;) FIXES_sleep _FIXES_SLEEP_BRACKET %0);
#define _FIXES_SLEEP_BRACKET (
#endif
Daniel_Cortez
13.01.2016, 19:02
Вариант из fixes от Y_Less:
/*
* FIXES_sleep(const time)
*
* FIXES:
* sleep
*/
// Uses a little trick to consume part of the line and thus not match
// our hooked version.
#if defined _ALS_sleep
#error _ALS_sleep defined
#endif
#define BAD_sleep%0\n%9 sleep%0
#if FIX_sleep
stock FIXES_sleep(ms)
{
// Call a native function that does very little, but saves the current
// heap pointer. Then return to save the accurate stack pointer.
return heapspace(), ms;
}
#define _ALS_sleep
#define sleep%0\n%9 sleep FIXES_sleep(%0)
// This fixes another BIZZARE bug. Just doing:
//
// #define FIXES_sleep(%0;) FIXES_sleep(%0)
//
// Results in:
//
// FIXES_sleep(n));
//
// Which clearly it shouldn't. I've stepped through the compilation and that
// extra bracket comes from nowhere!
#define FIXES_sleep(%0;) FIXES_sleep _FIXES_SLEEP_BRACKET %0);
#define _FIXES_SLEEP_BRACKET (
#endif
Да, я видел этот вариант, но он меня не устроил.
В комментарии можно увидеть, что автор фикса (Y_Less) утверждает, якобы нативная функция (heapspace) сохраняет текущий указатель кучи ("Call a native function that does very little, but saves the current heap pointer.").
Интересно, где он это увидел? Код функции можно посмотреть здесь (https://github.com/Zeex/pawn/blob/master/source/amx/amxcore.c#L188). Всё, что делает функция - возвращает разницу между значениями в указателях стека и кучи, т.е. свободное пространство в секции стека/кучи. Никакого сохранения указателей стека, кучи или фрейма стека в ней нет.
По сути оператор sleep заменяется на какую-то функцию, которая даже не производит никакой приостановки выполнения кода. С таким же успехом можно заменить sleep на функцию-пустышку.
stock FIX_Sleep(ms) return ms;
В чём смысл такого "фикса"? Можно ли это вообще назвать "фиксом"? Удивительно, почему этого до сих пор никто не заметил - вроде бы среди заморской аудитории много кто пользуется этим инклудом.
Да, я видел этот вариант, но он меня не устроил.
В комментарии можно увидеть, что автор фикса (Y_Less) утверждает, якобы нативная функция (heapspace) сохраняет текущий указатель кучи ("Call a native function that does very little, but saves the current heap pointer.").
Интересно, где он это увидел? Код функции можно посмотреть здесь (https://github.com/Zeex/pawn/blob/master/source/amx/amxcore.c#L188). Всё, что делает функция - возвращает разницу между значениями в указателях стека и кучи, т.е. свободное пространство в секции стека/кучи. Никакого сохранения указателей стека, кучи или фрейма стека в ней нет.
По сути оператор sleep заменяется на какую-то функцию, которая даже не производит никакой приостановки выполнения кода. С таким же успехом можно заменить sleep на функцию-пустышку.
stock FIX_Sleep(ms) return ms;
В чём смысл такого "фикса"? Можно ли это вообще назвать "фиксом"? Удивительно, почему этого до сих пор никто не заметил - вроде бы среди заморской аудитории много кто пользуется этим инклудом.
Хм, и правда, спасибо. В ближайшее время обновлю свой форк этой либы.
Daniel_Cortez
13.01.2016, 19:29
Хм, и правда, спасибо. В ближайшее время обновлю свой форк этой либы.
ИМХО, вряд ли в SA:MP есть хоть что-то, вызывающее задержку без вызова коллбэка (т.е. в пределах вызывающей функции) и без создания нагрузки на процессор. В конце концов, он для того и создан, чтобы быть однопоточным. Но если всё же будут идеи, постараюсь сделать PR в твоём форке.
Стоп. Я протестировал стандартную функцию, хватило примерно 1300 вызовов для получения этой ошибки. Затем я взял фикс от Y_Less и он, походу, действительно работает, ибо на 27 тысячах итераций полёт нормальный.
Тестировал очень просто:
main()
{
new a;
while (++a) {
printf("%d", a);
sleep(0);
}
}
Daniel_Cortez
13.01.2016, 20:00
Стоп. Я протестировал стандартную функцию, хватило примерно 1300 вызовов для получения этой ошибки. Затем я взял фикс от Y_Less и он, походу, действительно работает, ибо на 27 тысячах итераций полёт нормальный.
Тестировал очень просто:
main()
{
new a;
while (++a) {
printf("%d", a);
sleep(0);
}
}
Действительно, стоп. А теперь назад.
По сути оператор sleep заменяется на какую-то функцию, которая даже не производит никакой приостановки выполнения кода. С таким же успехом можно заменить sleep на функцию-пустышку.
Врема простоя и нагрузку на процессор проверял?
Действительно, стоп. А теперь назад.
Врема простоя и нагрузку на процессор проверял?
Да, оно работает. Здесь же не подмена функции, а её "дополнение":
#define sleep%0\n%9 sleep FIXES_sleep(%0)
Вот во что превращается код после работы препроцессора:
main()
{
new a;
while (++a) {
printf("%d", a);
sleep FIXES_sleep ( (100)); }
}
$continue$
13.01.2016, 20:11
Один вопрос:
stock FIXES_sleep(ms)
{
// Call a native function that does very little, but saves the current
// heap pointer. Then return to save the accurate stack pointer.
return heapspace(), ms;
}
На какой сначала возвращаеться: heapspace а потом ms?
Если в итоге вернет ms?
Один вопрос:
stock FIXES_sleep(ms)
{
// Call a native function that does very little, but saves the current
// heap pointer. Then return to save the accurate stack pointer.
return heapspace(), ms;
}
На какой сначала возвращаеться: heapspace а потом ms?
Если в итоге вернет ms?
heapspace не возвращается, а просто выполняется. Код написан "под" return для того, чтобы сократить размер AMX (по словам Y_Less).
Daniel_Cortez
13.01.2016, 20:54
Да, оно работает. Здесь же не подмена функции, а её "дополнение":
#define sleep%0\n%9 sleep FIXES_sleep(%0)
Вот во что превращается код после работы препроцессора:
main()
{
new a;
while (++a) {
printf("%d", a);
sleep FIXES_sleep ( (100)); }
}
Проверил. Хорошо, допустим, но за пределами main этот фикс всё так же не работает. Да и от вызова heapspace по прежнему нет никакого толку. Я попробовал убрать вызов той функции и фикс работал точно так же, никаких ошибок при выполнении в main. Замечу, я уже писал выше о бесполезности heapspace.
Вообще у Y_Less'а довольно интересный вариант. Никогда бы не подумал, что в Pawn можно использовать рекурсивные макросы, но Y_Less всё же придумал костыль (просто решением это назвать нельзя, поскольку его способ портит отступы, хоть это и видно только в препроцессе; да и способ этот далеко не самый простой). Но всё же надо будет запомнить тот метод.
Проверил. Хорошо, допустим, но за пределами main этот фикс всё так же не работает.
Дак целью было избавиться от ошибки "stack/heap collision", а не заставить эту функцию работать везде.
Да и от вызова heapspace по-прежнему нет никакого толку. Я попробовал убрать вызов той функции и фикс работал точно так же, никаких ошибок при выполнении в main.
Хм, и правда. Видимо достаточно перед вызовом sleep просто вернуть какое-нибудь значение.
Powered by vBulletin® Version 4.2.0 Copyright © 2024 vBulletin Solutions, Inc. All rights reserved. Перевод: zCarot