vbox_kd_monitor.pyw 3.6 KB
Newer Older
1 2 3 4 5 6 7 8
import ConfigParser
import subprocess
import threading
import sys
import os

from vboxapi import VirtualBoxManager
_vboxmgr = VirtualBoxManager()
Aleksey R.'s avatar
Aleksey R. committed
9 10 11 12 13
try:
    _vbox = _vboxmgr.vbox
except AttributeError:
    # virtualbox 5.2 api
    _vbox = _vboxmgr.platform.getVirtualBox()
14 15 16 17 18 19 20 21 22

_ACTIVE_DEBUGGERS = dict()

def get_ini_option(option_name):
    config = ConfigParser.ConfigParser()
    config.read( os.path.join(os.path.dirname(sys.argv[0]), "vbox_kd.ini") )
    return config.get("General", option_name)

def start_debugger(machine_id):
Aleksey R.'s avatar
Aleksey R. committed
23
    machine = _vbox.findMachine(machine_id)
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85

    connect_options = machine.getExtraData("KD/ConnectOptions")
    if not connect_options:
        return

    stop_debugger(machine_id)

    pipename = "\\\\.\\pipe\\kd_{}".format(machine.name)
    pipename = pipename.replace(" ", "_")

    windbg_file = get_ini_option("WinDbgFile")
    windbg_args = [ windbg_file,
                    "-k",
                    connect_options.replace("$(pipename)", pipename),
                  ]
    try:
        command = get_ini_option("WinDbgCommand")

        windbg_args.append("-c")
        windbg_args.append(command)
    except ConfigParser.NoOptionError:
        pass

    global _ACTIVE_DEBUGGERS
    _ACTIVE_DEBUGGERS[machine_id] = subprocess.Popen( args=windbg_args,
                                                      cwd = os.path.dirname(windbg_file)
                                                    )

def stop_debugger(machine_id):
    global _ACTIVE_DEBUGGERS
    if machine_id in _ACTIVE_DEBUGGERS:
        _ACTIVE_DEBUGGERS[machine_id].kill()
        del _ACTIVE_DEBUGGERS[machine_id]

_MACHINE_STATE_HANDLERS = { _vboxmgr.constants.MachineState_FirstOnline:    start_debugger,
                            _vboxmgr.constants.MachineState_PoweredOff:     stop_debugger,
                            _vboxmgr.constants.MachineState_Saved:          stop_debugger,
                            _vboxmgr.constants.MachineState_Aborted:        stop_debugger,
                          }

def on_machine_state_changed(event):
    casted_event = _vboxmgr.queryInterface(event, "IMachineStateChangedEvent")

    global _MACHINE_STATE_HANDLERS
    if casted_event.state in _MACHINE_STATE_HANDLERS:
        _MACHINE_STATE_HANDLERS[casted_event.state](casted_event.machineId)

class WaitableEvent:
    def __init__(self):
        self._cv = threading.Condition()

    def wait(self):
        self._cv.acquire()
        self._cv.wait()
        self._cv.release()

    def set(self):
        self._cv.acquire()
        self._cv.notify()
        self._cv.release()

def thread_routine(event_thread_ready, flag_stop_thread):
Aleksey R.'s avatar
Aleksey R. committed
86 87 88 89
    listener = _vbox.eventSource.createListener()
    _vbox.eventSource.registerListener( listener,
                                        [_vboxmgr.constants.VBoxEventType_OnMachineStateChanged],
                                        False )
90 91 92 93

    event_thread_ready.set()

    while flag_stop_thread.is_set() == False:
Aleksey R.'s avatar
Aleksey R. committed
94
        event = _vbox.eventSource.getEvent(listener, 500)
95 96 97
        if event:
            on_machine_state_changed(event)

Aleksey R.'s avatar
Aleksey R. committed
98
    _vbox.eventSource.unregisterListener(listener)
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116

def main():
    event_thread_ready = WaitableEvent()
    flag_stop_thread = threading.Event()

    thread = threading.Thread(target=thread_routine, args=(event_thread_ready, flag_stop_thread, ))
    thread.start()

    event_thread_ready.wait()

    vbox_process = subprocess.Popen( [ get_ini_option("VirtualBoxFile"), ] )
    vbox_process.wait()

    flag_stop_thread.set()
    thread.join()

if __name__ == "__main__":
    main()