Le meilleur moyen de détecter un blocage d'application et de le redémarrer?

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

  •  09-06-2019
  •  | 
  •  

Question

Quel est le meilleur moyen de détecter un blocage d'application dans XP (produit la même paire de fenêtres "d'erreur" à chaque fois, chacune avec le même titre de fenêtre), puis de le redémarrer?

Je suis particulièrement intéressé par les solutions qui utilisent des ressources système minimales, car le système en question est assez ancien.

J'avais pensé utiliser un langage de script tel que AutoIt ( http://www.autoitscript.com/autoit3/ ), et peut-être déclencher un script "détecteur" toutes les quelques minutes?

Est-ce que cela serait mieux fait en Python, Perl, PowerShell ou autre chose entièrement?

Toutes les idées, conseils ou idées sont très appréciés.

EDIT: Cela ne plante pas réellement (c’est-à-dire quitter / terminer - merci @tialaramex). Il affiche une boîte de dialogue en attente de saisie de l'utilisateur, suivi d'une autre boîte de dialogue en attente de toute nouvelle saisie de l'utilisateur, puis se ferme. Ce sont ces dialogues que je voudrais détecter et traiter.

Était-ce utile?

La solution

Pourquoi ne pas créer une application wrapper qui lance l’application défectueuse en tant qu’enfant et l’attend? Si le code de sortie de l'enfant indique une erreur, redémarrez-la, sinon quittez.

Autres conseils

La meilleure solution consiste à utiliser un mutex .

  1. Lancez votre application.
  2. Créez un nouveau mutex nommé et en prenez possession
  3. Démarrer un nouveau processus (processus non thread) ou une nouvelle application, ce que vous préférez.
  4. A partir de ce processus / de cette application, essayez d’acquérir le mutex. Le processus bloquera
  5. Lorsque l'application est terminée, relâchez le mutex (signalez-le)
  6. Le " contrôle " Le processus n’acquerra le mutex que si l’application se termine ou si elle se bloque.
  7. Testez l'état résultant de l'acquisition du mutex. Si l'application s'est écrasée, ce sera WAIT_ABANDONED

Explication: Lorsqu'un thread se termine sans relâcher le mutex, tout autre processus en attente peut l'acquérir, mais il obtiendra une valeur WAIT_ABANDONED renvoyée, ce qui signifie que le mutex est abandonné et que l'état du la section qu’elle a protégée peut être dangereuse.

Ainsi, votre seconde application ne consommera aucun cycle de traitement, car elle attendra toujours le mutex (et le système d’exploitation le gère entièrement)

Je pense que le problème principal est que M. Watson affiche une boîte de dialogue. et maintient votre processus en vie.

Vous pouvez écrire votre propre débogueur à l'aide de l'API Windows et Lancez l'application qui tombe en panne Cela empêchera d’autres débogueurs d’attraper le crash de votre application et vous pouvez également capturer l'événement Exception.

Comme je n'ai trouvé aucun exemple de code, j'ai écrit ceci Échantillon rapide et sale en python. Je ne suis pas sûr de sa robustesse en particulier, la déclaration de DEBUG_EVENT pourrait être améliorée.

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'])

Je me rends compte que vous utilisez Windows XP, mais il existe de nouveaux API de reprise sur incident disponible. En voici un bonne introduction à ce qu’ils peuvent faire.

Voici une version légèrement améliorée.

Dans mon test, le code précédent était exécuté dans une boucle infinie lorsque l'exe défectueux générait une "violation d'accès".

Je ne suis pas totalement satisfait de ma solution car je n'ai pas de critère clair pour savoir quelle exception doit être poursuivie et laquelle ne peut pas l'être (The ExceptionFlags n'est d'aucune aide).

Mais cela fonctionne sur l'exemple que je présente.

J'espère que ça aide, Vivian De Smedt

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'])
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top