понедельник, 28 января 2013 г.

Борюсь с дедлоком в своем проекте эмулятора. Вещь неприятная - возникает рандомно при включении звука в HOMM3. Оказалась причина дедлока - библиотека Miles Sound System. Для синхронизации работы с основным потоком они не используют критические секции и подобные примитивы, а нашли более "оригинальный метод".
Как написано на их сайте, "John Miles first released MSS in 1991 in the early days of PC gaming". Во времена ДОС для синхронизации было популярно использовать команды CLI (запретить прерывания), сделать свои дела и потом вызвать STI (разрешить прерывания). Видать стояла перед Женькой задача "быстро портировать под windows", вот он взял и заменил CLI на SuspendThread, а STI на ResumeThread для основного потока программы. А о том, что основной поток может быть не единственным, или то, что этот поток может "держать" критическую секцию, которая может понадобится самому MSS, да и то, что использовать данные функции не оптимально хотя бы с точки зрения производительности - думать не надо. И работало все до тех пор, пока не пришел я со своим эмулятором. И засуспендил MSS основной поток в тот момент, когда эмулятор держал критическую секцию, и попробовал MSS начать дальше выполняться - а фиг вам, для этого надо взять ту же секцию, а остановленный поток ее держит и не отдает. И пришлось мне делать свою реализацию SuspendThread, учитывающую подобные "особенности" криворуких программистов, не умеющих пользоваться примитивами синхронизации и изобретающих свой велосипед. "Miles is super robust. Since we ship in so many games, Miles just gets better and better - it just doesn't crash", да, он не крашится. Он просто наглухо вешает вашу программу. Хотя я сужу по библиотеке более чем 10-летней давности, может быть в последних версиях, наконец, действуют более корректно.

И еще один перл от того же автора. На этот раз в библиотеке binkw32.dll:
          loc_100014C2:                          
                push    0              
                call    Sleep
                mov     eax, [esi+4Ch]
                test    eax, eax
                jnz     short loc_100014C2
Зачем нам евенты - есть же поллинг, так хорошо зарекомендовавший себя под ДОС! Будем опрашивать переменную до посинения обнуления. Хотя бы Sleep(0) догадался добавить, чтобы квант времени потока отдать. Только не сильно оно помогло, у меня в эмуляторе этот цикл превратился в вечный. Но это уже баг на моей стороне, "переоптимизировал".

mamaich, 28.01.2013

воскресенье, 27 января 2013 г.

Занимаюсь проектом - запуск x86 Windows программ на планшетнике под Windows RT. Нужно было найти наиболее "тормозящие" места в коде, а Visual Studio 2012 не имеет в себе профайлера для АРМ, там даже profile-guided optimization падает на более-менее больших объемах кода. В итоге пришлось в очередной раз писать свой профайлер. Раньше уже раза 3 делал такой же код, еще под Windows Mobile в порте QEMU, и как на зло - код нигде не сохранился.
Поэтому оставляю код тут, на будущее :)

CSet Counters;
bool volatile DumpProfiler=false;
bool ForEachFunc(unsigned int Idx, void *Data, void *Param)
{
 if(Data)
  LogInfo("%08X - %d\n",Idx,Data);
 return true;
}

HANDLE ProfThread=0;
DWORD WINAPI Profiler(
  _In_  LPVOID lpParameter
)
{
 CONTEXT Ctx;
 while(1)
 {
  SuspendThread(ProfThread);
  Ctx.ContextFlags=CONTEXT_CONTROL;
  GetThreadContext(ProfThread,&Ctx);
  ResumeThread(ProfThread);
  Counters.Set(Ctx.Pc,(void*)(1+(DWORD)Counters.Get(Ctx.Pc)));
  if(DumpProfiler)
  {
   Counters.ForEach(ForEachFunc,0);
  }
  Sleep(20);
 }
}

void InitProfiler()
{
 DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&ProfThread,0,FALSE,DUPLICATE_SAME_ACCESS);
 CreateThread(0,0,Profiler,0,0,0);
}

Код - прост до ужаса. Параллельный поток останавливает интересующий нас поток программы, получает его PC и фиксирует сколько раз на этом месте мы были. Далее - в отладчике стопорим программу, ставим DumpProfiler=true, сортируем/фильтруем полученный лог в Excel-е по адресам - и анализируем в отладчике что где за функция вызывалась.

mamaich, 27.01.2013

четверг, 24 января 2013 г.

Ровно месяц назад у меня родилась дочка. Сегодня отмечаем ее первый мини день рождения.
Пока что она, как все мелкие дети только и делает что орет, спит, ест, и производит из еды что-то обратное. Однако в месяц уже видны отличия от зверька - пытается тренировать родителей, показывает что ей уже что-то не нравится, и, что удивило, на нее очень хорошо действует успокаивающая музыка. В частности поиском по "музыка для новорожденных" находится неплохой сборник от "Happy Baby" с мелодиями и колыбельными, записанными на фоне сердцебиения. Засыпает - сразу же как только ставлю такую мелодию, так что рекомендую, ссылка. Можно сказать, я хакнул дочь, заставив ее уходить в sleep mode по своему желанию :)
На торрентах можно найти и другие мелодии для детей от тех же авторов. Особенно вставили битлы переделанные под звуки как-бы из детского мобиля.

mamaich, 24.01.2012
Это русскоязычная часть моего блога.
Английский вариант находится тут: http://mamaich-eng.blogspot.com

Основное назначение русского блога - место для хранения мыслей "за жизнь", "о компах" и так далее, в то время, как англоязычная часть планируется больше для технической информации о reverse engineering и подобных увлечениях, и как место для размещения ссылок на мои файлы и комментариев к ним.

mamaich, 24.01.2012