Quellcode durchsuchen

basic debugging (pause/resume)

Simon Van Mierlo vor 8 Jahren
Ursprung
Commit
11d0c45f3d
3 geänderte Dateien mit 131 neuen und 46 gelöschten Zeilen
  1. 75 31
      hybrid_server/classes/mvkcontroller.xml
  2. 15 15
      kernel/modelverse_kernel/main.py
  3. 41 0
      scripts/debug_prompt.py

+ 75 - 31
hybrid_server/classes/mvkcontroller.xml

@@ -21,6 +21,10 @@
             self.source = None
             self.port = int(sys.argv[1])
             self.count = 0
+            
+            self.debugged_users = set()
+            self.debug_info = {}
+            self.done_something = False
 
             self.mvs_operations = {
                     "CN": self.mvs.create_node,
@@ -95,6 +99,8 @@
                         <script>
                             # No JSON encoding necessary, as it is not complex
                             try:
+                                print 'from_mvi %s' % data
+                                self.done_something = False
                                 if data["op"] == "set_input":
                                     if "value" in data:
                                         value = [json.loads(data["value"])]
@@ -103,6 +109,34 @@
                                     self.input_queue[data["username"]].append((source, value))
                                 elif data["op"] == "get_output":
                                     self.output_queue[data["username"]].append(source)
+                                elif data["op"] == "attach_debugger":
+                                    self.debugged_users.add(data["username"])
+                                    self.done_something = True
+                                    self.source = source
+                                    self.debug_info[data["username"]] = {'state': 'running', 'breakpoints': []}
+                                elif data["op"] == "detach_debugger":
+                                    self.debugged_users.discard(data["username"])
+                                    self.done_something = True
+                                    self.source = source
+                                    del self.debug_info[data["username"]]
+                                elif data["op"] == "pause":
+                                    if data["username"] in self.debugged_users:
+                                        self.debug_info[data["username"]]['state'] = 'paused'
+                                    self.done_something = True
+                                    self.source = source
+                                elif data["op"] == "resume":
+                                    if data["username"] in self.debugged_users:
+                                        self.debug_info[data["username"]]['state'] = 'running'
+                                    self.done_something = True
+                                    self.source = source
+                                elif data["op"] == "step_over":
+                                    pass
+                                    self.done_something = True
+                                    self.source = source
+                                elif data["op"] == "step_into":
+                                    pass
+                                    self.done_something = True
+                                    self.source = source
                                 else:
                                     raise Exception("DROPPING unknown operation: " + str(data["op"]))
                             except ValueError:
@@ -110,6 +144,15 @@
                                 raise
                         </script>
                     </transition>
+
+                    <transition cond="self.done_something" target=".">
+                        <raise event="HTTP_input" scope="narrow" target="'to_mvi/%s' % self.source">
+                            <parameter expr="json.dumps(True)"/>
+                        </raise>
+                        <script>
+                            self.done_something = False
+                        </script>
+                    </transition>
                 </state>
             </state>
 
@@ -121,37 +164,38 @@
                             self.destination = None
                             if self.users:
                                 user = self.users.pop()
-
-                                # Check if there are values to input
-                                if self.input_queue[user]:
-                                    source, args = self.input_queue[user].pop(0)
-                                    for args_entry in args:
-                                        self.execute_modelverse(user, "set_input", [args_entry])
-
-                                    self.destination = source
-                                    self.value = "OK"
-                                    self.all_failed = False
-
-                                # Now process for some steps, or until we are again blocked for input
-                                for x in xrange(100):
-                                    self.execute_modelverse(user, "execute_rule", [])
-
-                                    if not self.mvk.success:
-                                        # Blocking or broken, so quit already to stop wasting CPU
-                                        break
-
-                                    # Could at least execute one instruction, so mark it as "not failed"
-                                    self.all_failed = False
-
-                                # Check that we don't have anything to output yet, otherwise we wait
-                                if self.destination is None:
-                                    # Perform output if there is anything
-                                    if self.output_queue[user]:
-                                        self.execute_modelverse(user, "get_output", [])
-                                        if self.mvk.success:
-                                            self.destination = self.output_queue[user].pop(0)
-                                            self.value = self.mvk.returnvalue
-                                            self.all_failed = False
+                                if not user in self.debugged_users or self.debug_info[user]['state'] == 'running':
+                                    # Check if there are values to input
+                                    if self.input_queue[user]:
+                                        source, args = self.input_queue[user].pop(0)
+                                        for args_entry in args:
+                                            self.execute_modelverse(user, "set_input", [args_entry])
+
+                                        self.destination = source
+                                        self.value = "OK"
+                                        self.all_failed = False
+
+                                    nr_of_steps = 1 if user in self.debugged_users else 100
+                                    # Now process for some steps, or until we are again blocked for input
+                                    for x in xrange(nr_of_steps):
+                                        self.execute_modelverse(user, "execute_rule", [])
+
+                                        if not self.mvk.success:
+                                            # Blocking or broken, so quit already to stop wasting CPU
+                                            break
+
+                                        # Could at least execute one instruction, so mark it as "not failed"
+                                        self.all_failed = False
+
+                                    # Check that we don't have anything to output yet, otherwise we wait
+                                    if self.destination is None:
+                                        # Perform output if there is anything
+                                        if self.output_queue[user]:
+                                            self.execute_modelverse(user, "get_output", [])
+                                            if self.mvk.success:
+                                                self.destination = self.output_queue[user].pop(0)
+                                                self.value = self.mvk.returnvalue
+                                                self.all_failed = False
 
                             else:
                                 if self.count >= 2000:

+ 15 - 15
kernel/modelverse_kernel/main.py

@@ -44,37 +44,37 @@ class ModelverseKernel(object):
     def execute_rule(self, username):
         user_root, =    yield [("RD", [self.root, username])]
         user_frame, =   yield [("RD", [user_root, "frame"])]
-        inst, phase =   yield [("RD", [user_frame, "IP"]),
+        self.inst, phase =   yield [("RD", [user_frame, "IP"]),
                                ("RD", [user_frame, "phase"]),
                               ]
-        self.new_debug, phase_v, inst_v = \
-                        yield [("RD", [inst, "__debug"]),
+        self.new_debug, self.phase_v, inst_v = \
+                        yield [("RD", [self.inst, "__debug"]),
                                ("RV", [phase]),
-                               ("RV", [inst]),
+                               ("RV", [self.inst]),
                               ]
         if self.new_debug is not None:
             self.debug_info, = yield [("RV", [self.new_debug])]
 
-        if phase_v == "finish":
+        if self.phase_v == "finish":
             gen = self.helper_init(user_root)
-        elif inst is None:
+        elif self.inst is None:
             raise Exception("Instruction pointer could not be found!")
-        elif isinstance(phase_v, string_types):
-            if phase_v == "init" and inst in self.compiled:
-                #print("%-30s(%s)" % ("COMPILED " + str(self.compiled[inst]), phase_v))
-                gen = self.execute_primitive(user_root, inst, username)
+        elif isinstance(self.phase_v, string_types):
+            if self.phase_v == "init" and self.inst in self.compiled:
+                #print("%-30s(%s)" % ("COMPILED " + str(self.compiled[self.inst]), self.phase_v))
+                gen = self.execute_primitive(user_root, self.inst, username)
             elif inst_v is None:
-                raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info, inst_v, phase_v))
+                raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info, inst_v, self.phase_v))
             else:
-                #print("%-30s(%s) -- %s" % (inst_v["value"], phase_v, username))
-                gen = getattr(self, "%s_%s" % (inst_v["value"], phase_v))(user_root)
+                #print("%-30s(%s) -- %s" % (inst_v["value"], self.phase_v, username))
+                gen = getattr(self, "%s_%s" % (inst_v["value"], self.phase_v))(user_root)
         elif inst_v is None:
-            raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info, inst_v, phase_v))
+            raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info, inst_v, self.phase_v))
         elif inst_v["value"] == "call":
             #print("%-30s(%s)" % ("call", "param"))
             gen = self.call_param(user_root)
         else:
-            raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info, inst_v, phase_v))
+            raise Exception("%s: error understanding command (%s, %s)" % (self.debug_info, inst_v, self.phase_v))
 
         try:
             inp = None

+ 41 - 0
scripts/debug_prompt.py

@@ -0,0 +1,41 @@
+import urllib
+import urllib2
+import threading
+import subprocess
+import os
+import sys
+import json
+
+def local_print(string):
+    if os.name == "posix":
+        # Nicer colour output when using posix (and thus supporting colour)
+        string = "\033[92m%s\033[0m" % string
+    print(string)
+
+def remote_print(string):
+    if os.name == "posix":
+        # Nicer colour output when using posix (and thus supporting colour)
+        string = "\033[94m%s\033[0m" % string
+    print(string)
+
+local_print("Welcome to the debugging shell!")
+local_print("Please specify Modelverse location (default: 127.0.0.1:8001)")
+
+location = raw_input()
+if location == "":
+    address = "http://127.0.0.1:8001/"
+
+local_print("Switching context to Modelverse: all data is piped.")
+local_print("Available commands: 'attach_debugger', 'detach_debugger', 'pause', 'resume'")
+local_print("To quit: execute command 'quit'")
+
+while 1:
+    inp = raw_input().split(" ")
+    action = inp[0]
+    if action == "quit":
+        local_print("Received quit: breaking connection to Modelverse immediately!")
+        break
+    else:
+        username = inp[1]
+
+    urllib2.urlopen(urllib2.Request(address, urllib.urlencode({"op": action, "username": username}))).read()