2008-09-16 8 views
9

¿Cuál es la mejor manera de detectar un bloqueo de aplicaciones en XP (produce el mismo par de ventanas de "error" cada vez, cada una con el mismo título de ventana) y luego lo reinicia?¿La mejor manera de detectar una falla de la aplicación y reiniciarla?

Me interesan especialmente las soluciones que utilizan recursos mínimos del sistema, ya que el sistema en cuestión es bastante antiguo.

Pensé en utilizar un lenguaje de scripting como AutoIt (http://www.autoitscript.com/autoit3/), y quizás desencadenar un script 'detector' cada pocos minutos?

¿Sería mejor hacerlo en Python, Perl, PowerShell o algo completamente distinto?

Todas las ideas, sugerencias o pensamientos son muy apreciados.

EDITAR: En realidad, no se bloquea (es decir, sale/finaliza - gracias @tialaramex). Muestra un cuadro de diálogo en espera de la entrada del usuario, seguido de otro cuadro de diálogo en espera de más entradas del usuario, y luego sale. Son estos diálogos que me gustaría detectar y tratar.

+0

¿La aplicación de hecho chocar (salida, terminar, dejan de estar en ejecución) o se mostrará un diálogo de error y esperar a que haga algo? – tialaramex

+0

¿Qué error es eso? ¿Enviar a Microsoft, o alguna personalizada? – Suma

Respuesta

3

¿Qué le parece crear una aplicación contenedora que inicie la aplicación defectuosa como un niño y la espere? Si el código de salida del niño indica un error, reinícielo, de lo contrario, salga.

12

La mejor manera es usar un nombre mutex.

  1. Comience su solicitud.
  2. Cree un nuevo mutex con nombre y tome posesión del mismo
  3. Comience un nuevo proceso (proceso sin enrutar) o una nueva aplicación, lo que usted prefiera.
  4. Desde ese proceso/aplicación, intente adquirir el mutex. El proceso bloqueará
  5. Cuando finalice la aplicación, libere el mutex (señalelo)
  6. El proceso de "control" solo obtendrá el mutex si la aplicación finaliza o si la aplicación falla.
  7. Pruebe el estado resultante después de adquirir el mutex. Si la solicitud se había estrellado será WAIT_ABANDONED

Explicación: Cuando un subproceso termina sin liberar el mutex cualquier otro proceso en espera de que pueda adquirir, pero que va a obtener una WAIT_ABANDONED como valor de retorno, lo que significa la exclusión mutua es abandonado y, por lo tanto, el estado de la sección que estaba protegido puede ser inseguro.

De esta manera su segunda aplicación no consumirá ningún ciclos de CPU ya que mantendrá a la espera de la exclusión mutua (y eso es mucho enterely manejados por el sistema operativo)

3

Creo que el principal problema es que el Dr. Watson muestra un cuadro de diálogo y mantiene su proceso con vida.

Puede escribir su propio depurador usando la API de Windows y ejecutar la aplicación que falla desde allí. Esto evitará que otros depuradores de controlar el accidente de su aplicación y también se puede capturar el evento de excepción.

Como no he encontrado ningún código de muestra, he escrito muestra rápida y sucia de Python. No estoy seguro de cuán robusto es , especialmente la declaración de DEPART_EVENT podría mejorarse.

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

Aquí hay una versión ligeramente mejorada.

En mi prueba el código de ejecución anterior en un bucle infinito cuando el exe defectuosa generó una "violación de acceso".

no estoy totalmente satisfecho por mi solución porque no tengo un criterio claro para saber qué excepción se debe continuar y que uno no podía ser (Los ExceptionFlags es de ninguna ayuda).

pero funciona en el ejemplo corro.

creo que sirve, 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']) 
Cuestiones relacionadas