На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
! ПРАВИЛА РАЗДЕЛА · FAQ раздела Delphi · Книги по Delphi
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как прочитать список файлов, поддиректорий в директории?
5. Как запустить программу/файл?
... (продолжение следует) ...

Вопросы, подробно описанные во встроенной справочной системе Delphi, не несут полезной тематической нагрузки, поэтому будут удаляться.
Запрещается создавать темы с просьбой выполнить какую-то работу за автора темы. Форум является средством общения и общего поиска решения. Вашу работу за Вас никто выполнять не будет.


Внимание
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...
Модераторы: jack128, D[u]fa, Shaggy, Rouse_
Страницы: (3) [1] 2 3  все  ( Перейти к последнему сообщению )  
> Что бы такое придумать, что бы определить причину зависания галвного потока?
    Есть большой проект. В нем есть и потоки, и COM-объекты.
    С этими ком объектами работает IE. Точнее не IE а сторонняя программа SiteKiosk, которая использует IE в качестве движка. Приложение exe, т.е. COM-сервер outproc.

    При переходе на Delphi 2010 появился странный баг. Некоторые, я подчеркиваю, некоторые, компьютеры (их много) работают нормально, а некоторые (их примерно столько же, сколько и первых) зависают через какое-то время работы. Особенно все усложняется тем, что к проблемным (да и не к проблемным) компам есть только удаленный доступ через RAdmin. Тестовые, которые есть рядом работают нормально.

    SiteKiosk (SK) это оболочка для интернет киосков, которая перехватывает управление показывает только html странички в полный экран. Это если очень грубо. Эти странички используют мои activex. Так же сам SK экспортирует COM-объекты, через которые им можно управлять программно. Что и делает мое приложение. В частнотси постоянно проверяет, на каком адресе находится SK.

    Эффект такой. SiteKiosk виснет. Если снять мое приложение, то SK отлипает и продолжает работать. Если снять SK мое приложение не восстанавливается.

    Искал дедлоки. Не нашел. Искал долго и тщательно. В обычных потоках дедлоков нет. Возможно они связаны с COM. Тут уже сложнее...

    Ничего общего между такими компьютерами не удалось найти. Искал в версиях windows, версиях dll (в том числе системных), сравнивал количество процессоров\ядер.
    В системном журнале ничего особенного то же нет.

    Ставил отладчик на "глючащий комп". Смотрел. Сначала показалось, что зависает внутри компонентов Indy. TidHTTP создавался в отдельном потоке и часто уничтожался и создавался заново. Вис внутри метода get. Заменил все Indy компоненты на рукописный клиент на голых сокетах. Стал сравнивать и смотреть под отладчиком. Оказалось, что не работает цикл выборки сообщений Application.Run. Т.е. в этом цикле никогда не срабатывают точки останова. Для проверки ставил точки останова в обработчики TTimer ов. В рабочем состоянии они срабатывают, в зависшем - нет.
    Стэк главного потока в общем ничего особого не показывает. Остальные потоки работают и выполняют свои функции.

    ProcessExplorer показывает это:
    Цитата

    ntkrnlpa.exe+0x6d98b
    ntkrnlpa.exe+0x2b2b6
    ntkrnlpa.exe+0x2bb35
    ntkrnlpa.exe+0x13d7e7
    ntkrnlpa.exe+0x6960c
    ntdll.dll!KiFastSystemCallRet
    kernel32.dll!Sleep+0xf
    borlndmm.dll!Borlndmm+0xaa


    Причем переключения на поток происходят.

    Стек из под отладчика главного потока приложения сейчас не могу точно привести, никак что-то зависание не поймаю на компе, где стоит отладчик но в нем примерно тоже самое,за исключением строк ntkrnlpa.exe.
    Т.е. три последние строки.

    В проекте есть много длл, они взаимодействуют между собой через интерфейсы, но, так же и передают строки. Везде где надо стоит sharemem первым модулем.

    Так же PrcessExplorer показывает почему-то две запущенные копии exe. С разными типами маппинга.
    Например зависший вариант:
    user posted image
    Работающий вариант:
    user posted image
    Что бы это могло значить? Откуда вторая копия?

    не знаю, может ли относиться к делу, но вот еще есть такой стек (ProcessExplorer) для потока "ole32.dll!CoGetMalloc + 0x147"
    Цитата

    ntkrnlpa.exe+0x6d98b
    ntkrnlpa.exe+0x2b2b6
    ntkrnlpa.exe+0x2bb35
    win32k.sys+0x2ec4
    win32k.sys+0x1aa8
    win32k.sys+0xf106
    ntkrnlpa.exe+0x6960c
    ntdll.dll!KiFastSystemCallRet
    ole32.dll!CoFreeUnusedLibrariesEx+0x214
    ole32.dll!CoGetObject+0x2ccd
    ole32.dll!CoGetObject+0x2c00
    ole32.dll!CoGetMalloc+0xfa
    kernel32.dll!GetModuleFileNameA+0x1b4


    В принципе вызов последних процедур у них совпадает. Хотя, практически у всех потов к конце эти строки есть. В той или иной комбинации...

    В общем я че-то даже не знаю, что еще можно придумать, что бы если не исправить, так хоть найти причину?
    Может кто чего дельного сможет посоветовать?
    Сообщение отредактировано: Felan -
    // Когда у оппонента кончаются аргументы, он начинает уточнять национальность.
      если честно - жуть какая-то.

      по поводу ole32.dll
      Есть приложение - делает заковыристый запрос в базу данных и выводит отчет в Excel через Ole Automation.
      Запрос выполняется долго (порядка 10-15 мин), поэтому все вынес в дополнительный поток.
      Провели недавно обновления офиса 2003 мелкомягких, чтоб понимал новый формат. Прога стала вылетать, причем без всяких ошибок. Версия библиотеки вроде бы и не поменялась :(

      может и эта капля информации поможет!
      "Помилуйте, королева, — прохрипел он, — разве я позволил бы себе налить даме водки? Это чистый спирт!"
        Цитата Light13 @
        если честно - жуть какая-то.

        Да не то слово! :)

        Офис вроде нигде не используется у меня... хотя, вроде там было что-то с акссесом... надо будет покопать.

        В продолжение темы.

        Нет никакой стабильной периодичности в зависаниях. Что наводит на мысль, что зависает в случае выполнение каких то действий. Вот как бы их поймать...
        Логировать все подряд уже пробовал. Пока не помогло.
        // Когда у оппонента кончаются аргументы, он начинает уточнять национальность.
          По первому стеку: вы попробуйте несколько раз подряд получить стек. Если в нём всегда будет borlndmm.dll!Borlndmm+0xaa (и почти всегда Sleep), то я даже знаю, что это такое :)

          Это - memory corruption. Ваш код повредил управляющие структуры менеджера памяти (установив признак "занят" на свободный блок памяти), и теперь менеджер памяти пытается вечно ожидать освобождения никем не занятого участка памяти.

          Как лечить. Кратко: для начала - использовать отладочный менеджер памяти.
          Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
            Цитата CodeMonkey @
            вы попробуйте несколько раз подряд получить стек. Если в нём всегда будет borlndmm.dll!Borlndmm+0xaa (и почти всегда Sleep)

            Вот стек с другой повисшей машины. Много раз его смотрел process eplorer'ом с различными промежутками времени... Вот небольшая выборка. Других значений вроде не было.
            Скрытый текст

            Цитата

            ntkrnlpa.exe+0x6997f
            ntkrnlpa.exe+0xf5770
            ntkrnlpa.exe+0x25fbf
            ntkrnlpa.exe+0x29198
            ntkrnlpa.exe+0x1342f5
            ntkrnlpa.exe+0x65808
            ntdll.dll!KiFastSystemCallRet
            kernel32.dll!Sleep+0xf
            borlndmm.dll!Borlndmm+0xb5


            ntkrnlpa.exe+0x6997f
            ntkrnlpa.exe+0xf5770
            ntkrnlpa.exe+0x25fbf
            ntkrnlpa.exe+0x29198
            ntkrnlpa.exe+0x1342f5
            ntkrnlpa.exe+0x65808
            ntdll.dll!KiFastSystemCallRet
            kernel32.dll!Sleep+0xf
            borlndmm.dll!Borlndmm+0xb5


            ntkrnlpa.exe+0x6997f
            ntkrnlpa.exe+0xf5770
            ntkrnlpa.exe+0x25fbf
            ntkrnlpa.exe+0x29198
            ntkrnlpa.exe+0x1342f5
            ntkrnlpa.exe+0x65808
            ntdll.dll!KiFastSystemCallRet
            kernel32.dll!Sleep+0xf
            borlndmm.dll!Borlndmm+0x9b


            ntkrnlpa.exe+0x6997f
            ntkrnlpa.exe+0xf5770
            ntkrnlpa.exe+0x25fbf
            ntkrnlpa.exe+0x29198
            ntkrnlpa.exe+0x1342f5
            ntkrnlpa.exe+0x65808
            ntdll.dll!KiFastSystemCallRet
            kernel32.dll!Sleep+0xf
            borlndmm.dll!Borlndmm+0x9b


            ntkrnlpa.exe+0x6997f
            ntkrnlpa.exe+0xf5770
            ntkrnlpa.exe+0x25fbf
            ntkrnlpa.exe+0x29198
            ntkrnlpa.exe+0x1342f5
            ntkrnlpa.exe+0x65808
            ntdll.dll!KiFastSystemCallRet
            kernel32.dll!Sleep+0xf
            borlndmm.dll!Borlndmm+0xb5


            Т.е. да. Всегда есть Sleep и всегда есть borlndmm.dll!Borlndmm.
            Но смещение иногда меняется. От чего это зависит?

            Еще не мог бы объяснить, на основании чего сделан вывод о том, что это memory corruption? Это я не к тому, что не верю, а к тому, что бы понимать на что смотреть, может мысль какая подвернется... да и на будущее...
            // Когда у оппонента кончаются аргументы, он начинает уточнять национальность.
              Ну это не однозначный вывод, конечно же! :D А предположение.

              Просто я такое уже не раз видел. И в 90% случаев предположение о порче памяти подтверждается.

              Просто, если вы посмотрите в исходники FastMM, то увидите такие строки:
              ExpandedWrap disabled
                procedure LockAllSmallBlockTypes;
                var
                  LInd: Cardinal;
                begin
                  if IsMultiThread then
                  begin
                    for LInd := 0 to NumSmallBlockTypes - 1 do
                    begin
                      while LockCmpxchg(0, 1, @SmallBlockTypes[LInd].BlockTypeLocked) <> 0 do
                      begin
                        if not NeverSleepOnMMThreadContention then
                        begin
                          Sleep(InitialSleepTime);
                          if LockCmpxchg(0, 1, @SmallBlockTypes[LInd].BlockTypeLocked) = 0 then
                            Break;
                          Sleep(AdditionalSleepTime);
                        end;
                      end;
                    end;
                  end;
                end;


              и такие:

              ExpandedWrap disabled
                    {Lock the block type}
                    if IsMultiThread then
                    begin
                      while True do
                      begin
                        {Try to lock the small block type}
                        if LockCmpxchg(0, 1, @LPSmallBlockType.BlockTypeLocked) = 0 then
                          Break;
                        {Try the next block type}
                        Inc(Cardinal(LPSmallBlockType), SizeOf(TSmallBlockType));
                        if LockCmpxchg(0, 1, @LPSmallBlockType.BlockTypeLocked) = 0 then
                          Break;
                        {Try up to two sizes past the requested size}
                        Inc(Cardinal(LPSmallBlockType), SizeOf(TSmallBlockType));
                        if LockCmpxchg(0, 1, @LPSmallBlockType.BlockTypeLocked) = 0 then
                          Break;
                        {All three sizes locked - given up and sleep}
                        Dec(Cardinal(LPSmallBlockType), 2 * SizeOf(TSmallBlockType));
                        if not NeverSleepOnMMThreadContention then
                        begin
                          {Both this block type and the next is in use: sleep}
                          Sleep(InitialSleepTime);
                          {Try the lock again}
                          if LockCmpxchg(0, 1, @LPSmallBlockType.BlockTypeLocked) = 0 then
                            Break;
                          {Sleep longer}
                          Sleep(AdditionalSleepTime);
                        end;
                      end;
                    end;


              и такие:

              ExpandedWrap disabled
                  @LockBlockTypeLoop:
                  mov eax, $100
                  {Attempt to grab the block type}
                  lock cmpxchg TSmallBlockType([ebx]).BlockTypeLocked, ah
                  je @GotLockOnSmallBlockType
                  {Try the next size}
                  add ebx, Type(TSmallBlockType)
                  mov eax, $100
                  lock cmpxchg TSmallBlockType([ebx]).BlockTypeLocked, ah
                  je @GotLockOnSmallBlockType
                  {Try the next size (up to two sizes larger)}
                  add ebx, Type(TSmallBlockType)
                  mov eax, $100
                  lock cmpxchg TSmallBlockType([ebx]).BlockTypeLocked, ah
                  je @GotLockOnSmallBlockType
                  {Block type and two sizes larger are all locked - sleep and/or retry}
                  sub ebx, 2 * Type(TSmallBlockType)
                  {The pause instruction improves spinlock performance}
                  pause
                  {"Busy waiting" or "sleep and retry" strategy?}
                  cmp NeverSleepOnMMThreadContention, 0
                  jne @LockBlockTypeLoop
                  {Couldn't grab the block type - sleep and try again}
                  push InitialSleepTime
                  call Sleep
                  {Try again}
                  mov eax, $100
                  {Attempt to grab the block type}
                  lock cmpxchg TSmallBlockType([ebx]).BlockTypeLocked, ah
                  je @GotLockOnSmallBlockType
                  {Couldn't grab the block type - sleep and try again}
                  push AdditionalSleepTime
                  call Sleep
                  {Try again}
                  jmp @LockBlockTypeLoop


              И аналогичные...

              Как видите, во многих случаях FastMM работает по схеме (грубо):

              ExpandedWrap disabled
                while Busy do
                  Sleep;
                Busy := True;
                // Do the work
                Busy := False;


              Сделано это для быстроты работы, потому что ресурсы блокируются на очень короткий промежуток времени, и ждать их через объект ядра не имеет смысла.

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

              1. Явная порча памяти по адресу флага. Переполнение буфера испортило флаг. Туда записали что-то, отличное от 0.
              2. Вылет функции менеджера памяти ранее. Поскольку в FastMM нет try/finally (видимо, опять же, для скорости), то выброс исключения на этапе "Do the work" приведёт к тому, что флаг не будет сброшен. Выброс исключения, понятно, не штатная ситуация и происходит в результате, опять-таки, повреждения памяти. В целом это приводит к тому, что следующий же вызов функции менеджера памяти, работающей с этим же флагом, приведёт к бесконечному ожиданию.

              Цитата Felan @
              От чего это зависит?

              От конкретного куска кода. Как видно из примеров выше, Sleep вызывается во многих местах - смотря какую блокировку запрашивает FastMM. Без исходников borlndmm сказать что-то более определённое нельзя. Можно пересобрать её, добавив отладочную информацию. А потом сконвертить map-файл в что-то, принимаемое Process Explorer-ом.
              Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
                Вот, стек под отладчиком делфи для главного потока:

                Цитата
                :7c90eb94 ntdll.KiFastSystemCallRet
                :7c90d85c ntdll.ZwDelayExecution + 0xc
                :7c802451 kernel32.Sleep + 0f


                Всегда такой... Если заморозить все потоки кроме главного, то пошагово он крутиться в этих функциях...
                // Когда у оппонента кончаются аргументы, он начинает уточнять национальность.
                  Че-то я похоже не совсем понимаю...
                  Почему-то не могу найти выполняющуюся процедуру в map файле по инфе от process explorer...

                  Делаю так:

                  Вижу в окне с длл-ками:

                  KioskFeedBackModule.dll бла-бла ImageBase: 0xA00000 Base: 0xA6B0000.

                  Т.е. моя длл-ка имеет базовый адрес $A00000, но загружена с адреса $A6B0000. Ладно. Хотя в принципе по идее это и не важно. Дальше то все равно идут смещения...

                  Открываю свойства процесса, закладку Threads. Вижу список потоков приложения. Около них находится смещение.
                  Типа KioskFeedBackModule.dll + 0x6144.
                  Т.е. это говорит о том, что поток выполняет команды в модуле MyModule, а точка входа в модуль имеет смещение $6144.

                  Хорошо.

                  Открываем окно Stack for thread (жмем кнопку Stack).

                  Цитата

                  ntoskrnl.exe+0x5d0d
                  ntoskrnl.exe+0x1615a9
                  ntoskrnl.exe+0x1649a
                  ntoskrnl.exe+0x164d9
                  ntoskrnl.exe+0x98efc
                  ntoskrnl.exe+0x6f0f
                  ntdll.dll!KiFastSystemCallRet
                  kernel32.dll!Sleep+0xf
                  borlndmm.dll!Borlndmm+0xb5
                  KioskService2.exe+0x150b6c
                  KioskFeedBackModule.dll+0x129b9d
                  KioskFeedBackModule.dll+0x128b82
                  KioskFeedBackModule.dll+0x12818d
                  KioskFeedBackModule.dll+0x45755
                  KioskFeedBackModule.dll+0x616e
                  kernel32.dll!GetModuleFileNameA+0x1b4


                  Видим список вызываемых модулей после входа в наш модуль и смещения, точек входа.
                  Напирмер KioskFeedBackModule.dll+0x129b9d (последняя перед входом в модуль KioskService2.exe).

                  Т.е. у нас получается если взять смещение $129b9d, то в подробном map файле можно найти функцию, которой соответствует эта строчка в стеке.

                  Но в map файле нет такого смещения. Так же там нет и смещения $6144 + $129b9d.

                  Что я не так считаю?
                  // Когда у оппонента кончаются аргументы, он начинает уточнять национальность.
                    Так я и не разобрался, почему для exe есть две записи с различным типом мэппинга... и что это за типы...
                    // Когда у оппонента кончаются аргументы, он начинает уточнять национальность.
                      Цитата Felan @
                      Т.е. у нас получается если взять смещение $129b9d, то в подробном map файле можно найти функцию, которой соответствует эта строчка в стеке.
                      Но в map файле нет такого смещения

                      Во-первых, ProcessExplorer выдает смещения относительно базового адреса загрузки dll, а map-файл относительно секции кода (CODE == .text), поэтому чтобы привести их в соотв-е нужно к смещением в мапе добавить смещение секции кода относительно базы (обычно $1000 на PE-заголовок).
                      Во-вторых, нужно учитывать, что смещения в стеке вызовов это точки возврата, находящиеся внутри каких-то функций, а не точки входа самих функций. И к тому же, раскрутка стека не всегда может выполняться правильно и после какого-то значения м.б. просто мусор. Ты же не думаешь, что все твои функции вызываются из kernel32.dll!GetModuleFileNameA ?! ;) Также и твоя dll может вызывать ф-ю из KioskService2.exe только в случае передачи в dll какой-то callback функции приложения (обработчика события или вызова метода класса\интерфейса) - это действительно так ?
                        Цитата leo @
                        Во-вторых, нужно учитывать, что смещения в стеке вызовов это точки возврата, находящиеся внутри каких-то функций, а не точки входа самих функций.

                        Не понял... Что с ними делать то тогда надо?


                        Цитата leo @
                        что все твои функции вызываются из kernel32.dll!GetModuleFileNameA ?! ;)

                        А я че-то удивлялся, откуда на взялась вообще... А как-то можно отделить мусор от не мусора? В том же Process Explorer?


                        Цитата leo @
                        Также и твоя dll может вызывать ф-ю из KioskService2.exe только в случае передачи в dll какой-то callback функции приложения (обработчика события или вызова метода класса\интерфейса) - это действительно так ?

                        Да, это так.
                        Из exe в dll передаются интерфейсы, методы которых вызываются из длл.
                        // Когда у оппонента кончаются аргументы, он начинает уточнять национальность.
                          Felan, попробуй утилитку :)

                          Добавлено
                          И посмотри ещё вот это (сессия "How to find the exception source line").

                          Добавлено
                          Цитата Felan @
                          А я че-то удивлялся, откуда на взялась вообще... А как-то можно отделить мусор от не мусора? В том же Process Explorer?

                          Телепатией. Серьёзно.
                          Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
                            Цитата CodeMonkey @
                            Felan, попробуй утилитку :)

                            Попробовал. В приложении ее вывод.
                            Честно говоря не совсем понял, куда смотреть. В отличии от process explorer даже не понятно, к какой длл относится стек... Ну или я недопонимаю чего-то...


                            Цитата CodeMonkey @
                            И посмотри ещё вот это (сессия "How to find the exception source line").

                            Посмотрел. В вроде ничего нового не открыл :( Хотя, хорошо, что теперь это есть явно прописанное в одно месте :)


                            Цитата CodeMonkey @
                            Телепатией. Серьёзно.

                            Этого я и боялся.
                            Прикреплённый файлПрикреплённый файлCallStack_v495_197.zip (6.1 Кбайт, скачиваний: 105)
                            // Когда у оппонента кончаются аргументы, он начинает уточнять национальность.
                              Вот с другой машины. Подумал, надо бы сделать несколько дампов с небольшими промежутками...
                              Вот сделал три раза с разницей в несколько секунд... ну сильно примерно. Как рука взяла, короче...

                              Сравниваю файлы по содержимому, а они практически одинаковые. Т.е. насколько я понимаю, все прочно висит...
                              Прикреплённый файлПрикреплённый файлCallStack_v294_217.zip (18.25 Кбайт, скачиваний: 76)
                              // Когда у оппонента кончаются аргументы, он начинает уточнять национальность.
                                Ой как у тебя там страшно. Куча потоков, COM, WinSock, ... ужас :)

                                В общем, что я увидел: несколько потоков встали на @Borlndmm@SysFreeMem$qqrpv. Я уже предлагал погонять под FastMM в отладочном режиме. Чего не пробуем?

                                Второе: у главного потока есть ссылка на CheckIniChange и получение настроек форматирования. У второго потока - на WideFormatBuf. Вопрос: не может ли у тебя быть проблема с синхронизацией доступа к TFormatSettings?

                                Третье: что-то у тебя вообще отсутствуют номера строки. Ты включил бы генерацию map-файла-то. Да и "Use Debug DCUs" включенной не помешает. А вот пакеты лучше отключать (хотя ты их не используешь вроде).
                                Опытный программист на C++ легко решает любые не существующие в Паскале проблемы.
                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                                0 пользователей:
                                Страницы: (3) [1] 2 3  все


                                Рейтинг@Mail.ru
                                [ Script Execution time: 0,1593 ]   [ 17 queries used ]   [ Generated: 19.04.19, 02:50 GMT ]