La meilleure façon de détecter un crash d'application et de le redémarrer?

Quelle est la meilleure façon de détecter un crash d'application dans XP (produit la même paire de fenêtres 'error' à chaque fois - chacun avec le même titre de fenêtre) puis de le redémarrer?

je suis particulièrement intéressé d'entendre parler de solutions qui utilisent des ressources minimales de système que le système en question est assez vieux.

j'avais pensé à utiliser un langage de script comme AutoIt ( http://www.autoitscript.com/autoit3 / ), et peut-être le déclenchement un script "détecteur" toutes les quelques minutes?

serait-ce mieux en Python, Perl, PowerShell ou autre chose?

toutes idées, conseils ou pensées très apprécié.

EDIT: Il ne fait pas de crash (c'est à dire quitter/fin - merci @tialaramex). Il affiche une boîte de dialogue en attente de l'entrée de l'utilisateur, suivie d'une autre boîte de dialogue en attente de l'entrée de l'utilisateur, puis il sort effectivement. Ce sont ces dialogues que j'aimerais détecter. et de les traiter.

9
demandé sur Umber Ferrule 2008-09-17 02:40:50

5 réponses

Que Diriez-vous de créer une application d'emballage qui lance l'application défectueuse comme un enfant et l'attend? Si le code de sortie de l'enfant indique une erreur, puis redémarrez-le, d'autre sortie.

3
répondu Vinko Vrsalovic 2008-09-16 22:48:07

Meilleur moyen est d'utiliser un nommé mutex .

  1. démarrez votre application.
  2. Créer un mutex nommé et prendre possession de
  3. lancer un nouveau processus (Processus pas thread) ou une nouvelle application, ce que vous présentez.
  4. de ce processus / application essayer d'acquérir le mutex. Le processus bloquera
  5. lorsque l'application fini de libérer le mutex (signal)
  6. le processus de "contrôle" n'acquiert le mutex que si l'application est terminée ou si l'application tombe en panne.
  7. tester l'état résultant après l'acquisition du mutex. Si l'application s'était crashée, elle sera WAIT_ABANDONED

explication: quand un fil se termine sans libérer le mutex tout autre processus en attente peut l'acquérir mais il obtiendra un WAIT_ABANDONED comme valeur de retour, ce qui signifie que le mutex est abandonné et donc l'état de la section il a été protégé peut être dangereux.

de cette façon, votre deuxième application ne consommera pas de cycles CPU car il va garder en attente pour le mutex (et qui est géré de manière entérique par le système d'exploitation)

12
répondu Jorge Córdoba 2012-06-05 07:56:48

je pense que le problème principal est que le Dr Watson affiche un dialogue et garde ton processus vivant.

vous pouvez écrire votre propre débogueur en utilisant L'API Windows et Lancez l'application de crashing à partir de là. Cela empêchera les autres débogueurs d'attraper le crash de votre application et vous pourriez également attraper l'événement D'Exception.

comme je n'ai pas trouvé de code échantillon, j'ai écrit ceci Python rapide et sale de l'échantillon. Je ne suis pas sûr de savoir comment robuste, il est 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'])
3
répondu Leonhard 2009-04-23 21:06:51

je me rends compte que vous avez affaire à Windows XP, mais pour les personnes dans une situation similaire sous Vista, Il ya de nouveaux crash recovery API S disponibles. Voici une bonne introduction à ce qu'ils peuvent faire.

2
répondu Eclipse 2008-09-17 18:17:24

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

dans mon test, le code précédent tourne en boucle infinie lorsque le exe défectueux génère une"violation d'accès".

Je ne suis pas totalement satisfait de ma solution parce que je n'ai pas de critères clairs pour savoir quelle exception devrait être poursuivie et laquelle ne pourrait pas être (les sacs D'Exception n'est d'aucune aide).

mais ça marche sur l'exemple que j'exécute.

J'espère aider, 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'])
2
répondu 2009-06-04 10:14:10