Лучший способ обнаружить сбой приложения и перезапустить его?

StackOverflow https://stackoverflow.com/questions/78048

  •  09-06-2019
  •  | 
  •  

Вопрос

Как лучше всего обнаружить сбой приложения в XP (каждый раз создается одна и та же пара окон с ошибками - каждое с одинаковым заголовком окна), а затем перезапустить его?

Мне особенно интересно услышать о решениях, которые используют минимальные системные ресурсы, поскольку рассматриваемая система довольно старая.

Я думал об использовании языка сценариев, такого как AutoIt (http://www.autoitscript.com/autoit3/) и, возможно, запускать скрипт «детектора» каждые несколько минут?

Было бы лучше сделать это на Python, Perl, PowerShell или на чем-то другом?

Любые идеи, советы или мысли очень ценятся.

РЕДАКТИРОВАТЬ:На самом деле он не выходит из строя (т.выйти/завершить - спасибо @tialaramex).Он отображает диалоговое окно, ожидающее ввода пользователя, за которым следует еще одно диалоговое окно, ожидающее дальнейшего ввода пользователя, а затем он фактически завершается.Именно эти диалоги мне хотелось бы обнаружить и разобраться с ними.

Это было полезно?

Решение

Как насчет создания приложения-оболочки, которое запускает неисправное приложение как дочернее и ждет его?Если код завершения дочернего процесса указывает на ошибку, перезапустите его, иначе выйдите.

Другие советы

Лучший способ - использовать именованный мьютекс.

  1. Запустите приложение.
  2. Создайте новый именованный мьютекс и возьмите на себя ответственность за него.
  3. Запустите новый процесс (процесс, а не поток) или новое приложение, как вы предпочитаете.
  4. Из этого процесса/приложения попытайтесь получить мьютекс.Процесс будет заблокирован
  5. Когда приложение завершится, освободите мьютекс (подайте сигнал об этом)
  6. Процесс «управления» получит мьютекс только в случае завершения работы приложения или его сбоя.
  7. Проверьте полученное состояние после получения мьютекса.Если приложение вылетело, оно будет WAIT_ABANDONED.

Объяснение: Когда поток завершается, не освобождая мьютекс, любой другой процесс, ожидающий его, может получить его, но в качестве возвращаемого значения он получит WAIT_ABANDONED, что означает, что мьютекс оставлен, и, следовательно, состояние раздела, который он защищал, может быть небезопасным.

Таким образом, ваше второе приложение не будет потреблять никаких циклов ЦП, поскольку оно будет продолжать ждать мьютекса (и это полностью обрабатывается операционной системой).

Я думаю, что основная проблема в том, что Dr.Уотсон отображает диалог и поддерживает ваш процесс.

Вы можете написать свой собственный отладчик, используя API Windows и запустить сбой приложения оттуда.Это не позволит другим отладчикам поймать сбой вашей заявки, и вы также можете поймать событие исключения.

Поскольку я не нашел никакого образца кода, я написал этот быстрый образец Python.Я не уверен, насколько надежным это особенно может быть улучшено объявление DEBUG_EVENT.

from ctypes import windll, c_int, Structure
import subprocess

WaitForDebugEvent = windll.kernel32.WaitForDebugEvent    
ContinueDebugEvent = windll.kernel32.ContinueDebugEvent
DBG_CONTINUE = 0x00010002L    
DBG_EXCEPTION_NOT_HANDLED = 0x80010001L

event_names = {    
    3: 'CREATE_PROCESS_DEBUG_EVENT',
    2: 'CREATE_THREAD_DEBUG_EVENT',
    1: 'EXCEPTION_DEBUG_EVENT',
    5: 'EXIT_PROCESS_DEBUG_EVENT',
    4: 'EXIT_THREAD_DEBUG_EVENT',
    6: 'LOAD_DLL_DEBUG_EVENT',
    8: 'OUTPUT_DEBUG_STRING_EVENT', 
    9: 'RIP_EVENT',
    7: 'UNLOAD_DLL_DEBUG_EVENT',
}
class DEBUG_EVENT(Structure):
    _fields_ = [
        ('dwDebugEventCode', c_int),
        ('dwProcessId', c_int),
        ('dwThreadId', c_int),
        ('u', c_int*20)]

def run_with_debugger(args):
    proc = subprocess.Popen(args, creationflags=1)
    event = DEBUG_EVENT()

    while True:
        if WaitForDebugEvent(pointer(event), 10):
            print event_names.get(event.dwDebugEventCode, 
                    'Unknown Event %s' % event.dwDebugEventCode)
            ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE)
        retcode = proc.poll()
        if retcode is not None:
            return retcode

run_with_debugger(['python', 'crash.py'])

Я понимаю, что вы имеете дело с Windows XP, но для людей, оказавшихся в аналогичной ситуации под Vista, есть новые API восстановления после сбояДоступно. Вот хорошее введение на то, что они могут сделать.

Вот немного улучшенная версия.

В моем тесте предыдущий код выполнялся в бесконечном цикле, когда неисправный exe-файл генерировал «нарушение прав доступа».

Я не полностью удовлетворен своим решением, потому что у меня нет четких критериев, позволяющих определить, какое исключение следует продолжить, а какое нет (ExceptionFlags не помогает).

Но это работает на примере, который я запускаю.

Надеюсь, это поможет, Вивиан де Смедт

from ctypes import windll, c_uint, c_void_p, Structure, Union, pointer
import subprocess

WaitForDebugEvent = windll.kernel32.WaitForDebugEvent
ContinueDebugEvent = windll.kernel32.ContinueDebugEvent
DBG_CONTINUE = 0x00010002L
DBG_EXCEPTION_NOT_HANDLED = 0x80010001L

event_names = {
    1: 'EXCEPTION_DEBUG_EVENT',
    2: 'CREATE_THREAD_DEBUG_EVENT',
    3: 'CREATE_PROCESS_DEBUG_EVENT',
    4: 'EXIT_THREAD_DEBUG_EVENT',
    5: 'EXIT_PROCESS_DEBUG_EVENT',
    6: 'LOAD_DLL_DEBUG_EVENT',
    7: 'UNLOAD_DLL_DEBUG_EVENT',
    8: 'OUTPUT_DEBUG_STRING_EVENT',
    9: 'RIP_EVENT',
}

EXCEPTION_MAXIMUM_PARAMETERS = 15

EXCEPTION_DATATYPE_MISALIGNMENT  = 0x80000002
EXCEPTION_ACCESS_VIOLATION       = 0xC0000005
EXCEPTION_ILLEGAL_INSTRUCTION    = 0xC000001D
EXCEPTION_ARRAY_BOUNDS_EXCEEDED  = 0xC000008C
EXCEPTION_INT_DIVIDE_BY_ZERO     = 0xC0000094
EXCEPTION_INT_OVERFLOW           = 0xC0000095
EXCEPTION_STACK_OVERFLOW         = 0xC00000FD


class EXCEPTION_DEBUG_INFO(Structure):
    _fields_ = [
        ("ExceptionCode", c_uint),
        ("ExceptionFlags", c_uint),
        ("ExceptionRecord", c_void_p),
        ("ExceptionAddress", c_void_p),
        ("NumberParameters", c_uint),
        ("ExceptionInformation", c_void_p * EXCEPTION_MAXIMUM_PARAMETERS),
    ]

class EXCEPTION_DEBUG_INFO(Structure):
    _fields_ = [
        ('ExceptionRecord', EXCEPTION_DEBUG_INFO),
        ('dwFirstChance', c_uint),
    ]

class DEBUG_EVENT_INFO(Union):
    _fields_ = [
        ("Exception", EXCEPTION_DEBUG_INFO),
    ]

class DEBUG_EVENT(Structure):
    _fields_ = [
        ('dwDebugEventCode', c_uint),
        ('dwProcessId', c_uint),
        ('dwThreadId', c_uint),
        ('u', DEBUG_EVENT_INFO)
    ]

def run_with_debugger(args):
    proc = subprocess.Popen(args, creationflags=1)
    event = DEBUG_EVENT()

    num_exception = 0

    while True:
        if WaitForDebugEvent(pointer(event), 10):
            print event_names.get(event.dwDebugEventCode, 'Unknown Event %s' % event.dwDebugEventCode)

            if event.dwDebugEventCode == 1:
                num_exception += 1

                exception_code = event.u.Exception.ExceptionRecord.ExceptionCode

                if exception_code == 0x80000003L:
                    print "Unknow exception:", hex(exception_code)

                else:
                    if exception_code == EXCEPTION_ACCESS_VIOLATION:
                        print "EXCEPTION_ACCESS_VIOLATION"

                    elif exception_code == EXCEPTION_INT_DIVIDE_BY_ZERO:
                        print "EXCEPTION_INT_DIVIDE_BY_ZERO"

                    elif exception_code == EXCEPTION_STACK_OVERFLOW:
                        print "EXCEPTION_STACK_OVERFLOW"

                    else:
                        print "Other exception:", hex(exception_code)

                    break

            ContinueDebugEvent(event.dwProcessId, event.dwThreadId, DBG_CONTINUE)

        retcode = proc.poll()
        if retcode is not None:
            return retcode

run_with_debugger(['crash.exe'])
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top