소스 검색

Rewrite request_handler from scratch

Yentl Van Tendeloo 7 년 전
부모
커밋
b3487abe8f
4개의 변경된 파일46개의 추가작업 그리고 152개의 파일을 삭제
  1. 1 1
      hybrid_server/classes/task.xml
  2. 7 11
      kernel/modelverse_kernel/main.py
  3. 37 139
      kernel/modelverse_kernel/request_handler.py
  4. 1 1
      wrappers/modelverse_SCCD.py

+ 1 - 1
hybrid_server/classes/task.xml

@@ -46,7 +46,7 @@
                 import traceback
                 import traceback
                 print("Error on requests: " + str(commands))
                 print("Error on requests: " + str(commands))
                 print("For taskname " + str(taskname))
                 print("For taskname " + str(taskname))
-                stack = [gen['generator'] for gen in mvk.request_handlers[taskname][operation].generator_stack if gen['generator'].__name__ not in ['execute_rule', 'execute_jit', 'execute_jit_internal']]
+                stack = [gen for gen in mvk.request_handlers[taskname][operation].generator_stack if gen is not None and gen.__name__ not in ['execute_rule', 'execute_jit']]
                 printed_stack = []
                 printed_stack = []
                 for gen in stack:
                 for gen in stack:
                     try:
                     try:

+ 7 - 11
kernel/modelverse_kernel/main.py

@@ -102,8 +102,7 @@ class ModelverseKernel(object):
     ### Process primitives ###
     ### Process primitives ###
     ##########################
     ##########################
     def load_primitives(self, taskname):
     def load_primitives(self, taskname):
-        yield [("CALL_ARGS",
-                [self.load_primitives_from, (taskname, 'primitives', primitive_functions)])]
+        yield [("CALL_ARGS", [self.load_primitives_from, (taskname, 'primitives', primitive_functions)])]
 
 
     def load_primitives_from(self, taskname, source_name, source):
     def load_primitives_from(self, taskname, source_name, source):
         hierarchy, = yield [("RD", [self.root, "__hierarchy"])]
         hierarchy, = yield [("RD", [self.root, "__hierarchy"])]
@@ -240,9 +239,8 @@ class ModelverseKernel(object):
         elif inst_type["value"] == "assign":
         elif inst_type["value"] == "assign":
             var, val = yield [("RD", [inst, "var"]),
             var, val = yield [("RD", [inst, "var"]),
                               ("RD", [inst, "value"])]
                               ("RD", [inst, "value"])]
-            (prev_var, instruction_var), (prev_val, instruction_val) = \
-                        yield [("CALL_ARGS", [self.print_instruction, (var, 0, indent)]),
-                               ("CALL_ARGS", [self.print_instruction, (val, 0, indent)])]
+            (prev_var, instruction_var), = yield [("CALL_ARGS", [self.print_instruction, (var, 0, indent)])]
+            (prev_val, instruction_val), = yield [("CALL_ARGS", [self.print_instruction, (val, 0, indent)])]
 
 
             instruction = prev_val + "  " * indent + instruction_var + " = " + instruction_val + "\n"
             instruction = prev_val + "  " * indent + instruction_var + " = " + instruction_val + "\n"
 
 
@@ -272,9 +270,8 @@ class ModelverseKernel(object):
                 value, = yield [("RD", [param, "value"])]
                 value, = yield [("RD", [param, "value"])]
                 name, = yield [("RD", [param, "name"])]
                 name, = yield [("RD", [param, "name"])]
                 name, = yield [("RV", [name])]
                 name, = yield [("RV", [name])]
-                (prev_res, instruction_res), param = \
-                        yield [("CALL_ARGS", [self.print_instruction, (value, 0, nested_indent)]),
-                               ("RD", [param, "next_param"])]
+                (prev_res, instruction_res), = yield [("CALL_ARGS", [self.print_instruction, (value, 0, nested_indent)])]
+                param, = yield [("RD", [param, "next_param"])]
                 computation += prev_res
                 computation += prev_res
                 param_list[name] = instruction_res
                 param_list[name] = instruction_res
 
 
@@ -305,9 +302,8 @@ class ModelverseKernel(object):
         elif inst_type["value"] == "while":
         elif inst_type["value"] == "while":
             cond, body = yield [("RD", [inst, "cond"]),
             cond, body = yield [("RD", [inst, "cond"]),
                                 ("RD", [inst, "body"])]
                                 ("RD", [inst, "body"])]
-            (prev_cond, instruction_cond), (prev_body, instruction_body) = \
-                        yield [("CALL_ARGS", [self.print_instruction, (cond, 0, indent+1)]),
-                               ("CALL_ARGS", [self.print_instruction, (body, indent+1)])]
+            (prev_cond, instruction_cond), = yield [("CALL_ARGS", [self.print_instruction, (cond, 0, indent+1)])]
+            (prev_body, instruction_body), = yield [("CALL_ARGS", [self.print_instruction, (body, indent+1)])]
             instruction = "  " * indent + "while 1:\n" + prev_cond + \
             instruction = "  " * indent + "while 1:\n" + prev_cond + \
                           "  " * (indent + 1) + "if 'value' not in %s:\n" % instruction_cond + \
                           "  " * (indent + 1) + "if 'value' not in %s:\n" % instruction_cond + \
                           "  " * (indent + 2) + "%s['value'], = yield [('RV', [%s['id']])]\n" % (instruction_cond, instruction_cond) + \
                           "  " * (indent + 2) + "%s['value'], = yield [('RV', [%s['id']])]\n" % (instruction_cond, instruction_cond) + \

+ 37 - 139
kernel/modelverse_kernel/request_handler.py

@@ -4,163 +4,61 @@ import modelverse_kernel.jit as jit
 from collections import defaultdict
 from collections import defaultdict
 
 
 class RequestHandler(object):
 class RequestHandler(object):
-    """A type of object that intercepts logic-related Modelverse requests, and
-       forwards Modelverse state requests."""
     def __init__(self):
     def __init__(self):
-        # generator_stack is a stack of GeneratorStackEntry values.
         self.generator_stack = []
         self.generator_stack = []
-        # exception_handlers is a stack of
-        # (generator_stack index, [(exception type, handler function)])
-        # tuples.
-        self.produce_stack_trace = True
-        self.handlers = {
-            'CALL' : self.execute_call,
-            'CALL_ARGS' : self.execute_call_args,
-            'CALL_KWARGS' : self.execute_call_kwargs,
-            'SLEEP' : self.execute_sleep,
-        }
+        self.handlers = {"CALL": self.execute_call,
+                         "CALL_ARGS": self.execute_call_args,
+                         "CALL_KWARGS": self.execute_call_kwargs,
+                         "SLEEP": self.execute_sleep}
 
 
-    def handle_request(self, reply):
-        """Replies to a request from the top-of-stack generator, and returns a new request."""
-        if not self.generator_stack:
-            raise ValueError('handle_request cannot be called with an empty generator stack.')
-
-        # Append the server's replies to the list of replies.
-        if reply is not None:
-            gen = self.generator_stack[-1]
-
-            if gen["replies"]:
-                gen["replies"].extend(reply)
-            else:
-                gen["replies"] = reply
+    def push_generator(self, gen):
+        self.generator_stack.append(gen)
 
 
-        while 1:
-            # Silence pylint's warning about catching Exception.
-            # pylint: disable=I0011,W0703
+    def handle_request(self, reply):
+        while self.generator_stack:
             try:
             try:
                 gen = self.generator_stack[-1]
                 gen = self.generator_stack[-1]
-                if gen["finished_requests"]:
-                    gen["pending_requests"] = gen["generator"].send(gen["replies"])
-                    gen["finished_requests"] = False
-                    gen["replies"] = None
-                ret = self.pop_requests()
-                if ret[0]:
-                    return ret[1]
+                requests = gen.send(reply)
+
+                # Generated new request, so process
+                if requests and requests[0][0] in self.handlers:
+                        # Known request, so process that one
+                        if len(requests) > 1:
+                            raise Exception("CALL_* and SLEEP operations MUST be split in individual yields")
+
+                        # Try to add a new generator to branch into
+                        reply = None
+                        self.generator_stack.append(None)
+                        # This next command potentially raises a finished message already, meaning that we should stop already
+                        # We avoid an extra try/except block by putting the None on the stack already
+                        self.generator_stack[-1] = self.handlers[requests[0][0]](requests[0][1])
+                else:
+                    # MvS request, so forward that instead
+                    return requests
 
 
             except StopIteration:
             except StopIteration:
-                # Done, so remove the generator
+                # Exception, so finished execution of this generator, passing on None to the caller
                 del self.generator_stack[-1]
                 del self.generator_stack[-1]
-                if self.generator_stack:
-                    # This generator was called from another generator.
-                    # Append 'None' to the caller's list of replies.
-                    self.append_reply(None)
-                else:
-                    # Looks like we're done here.
-                    return None
+                reply = [None]
+                
             except primitive_functions.PrimitiveFinished as ex:
             except primitive_functions.PrimitiveFinished as ex:
-                # Done, so remove the generator
+                # Exception, so finished execution of this generator, passing on ex.result to the caller
                 del self.generator_stack[-1]
                 del self.generator_stack[-1]
-                if self.generator_stack:
-                    # This generator was called from another generator.
-                    # Append the callee's result to the caller's list of replies.
-                    self.append_reply(ex.result)
-                else:
-                    # Looks like we're done here.
-                    return None
+                reply = [ex.result]
 
 
-    def push_generator(self, gen):
-        """Pushes a new generator onto the stack."""
-        dd = defaultdict(lambda : None)
-        dd["generator"] = gen
-        dd["finished_requests"] = True
-        self.generator_stack.append(dd)
-        # print('Pushed generator %s. Generator count: %d' % (gen, len(self.generator_stack)))
-
-    def append_reply(self, new_reply):
-        """Appends a reply to the top-of-stack generator's list of pending replies."""
-        if self.generator_stack[-1]["replies"] is None:
-            self.generator_stack[-1]["replies"] = [new_reply]
-        else:
-            self.generator_stack[-1]["replies"].append(new_reply)
-
-    def pop_requests(self):
-        """Tries to pop a batch of Modelverse _state_ requests from the
-           current list of requests. Known requests are executed immediately.
-
-           A list of requests and a Boolean are returned. The latter is True
-           if there are no more requests to process, and false otherwise."""
-        requests = self.generator_stack[-1]["pending_requests"]
-        if requests:
-            if requests[0][0] in self.handlers:
-                # First element is a known request
-                elem = requests.pop(0)
-
-                # The list of requests might be empty now. If so, then flag this
-                # batch of requests as finished.
-                if not requests:
-                    self.generator_stack[-1]["finished_requests"] = True
-
-                # Handle the request.
-                self.handlers[elem[0]](elem[1])
-                return (False, None)
-            else:
-                for i, elem in enumerate(requests):
-                    if elem[0] in self.handlers:
-                        # Handle any requests that precede the known request first.
-                        pre_requests = requests[:i]
-                        del requests[:i]
-                        return pre_requests
-
-        # We couldn't find a known request in the batch of requests, so we might as well
-        # handle them all at once then.
-        self.generator_stack[-1]["finished_requests"] = True
-        #return requests
-        return (True, requests)
+            except primitive_functions.SleepKernel:
+                # Processing sleep, so pop its generator and reraise
+                del self.generator_stack[-1]
+                raise
 
 
     def execute_call(self, request_args):
     def execute_call(self, request_args):
-        """Executes a CALL-request with the given argument list."""
-        # Format: ("CALL", [gen])
-        gen, = request_args
-        self.push_generator(gen)
+        return request_args[0]
 
 
     def execute_call_kwargs(self, request_args):
     def execute_call_kwargs(self, request_args):
-        """Executes a CALL_KWARGS-request with the given argument list."""
-        # Format: ("CALL_KWARGS", [func, kwargs])
-        # This format is useful because it also works for functions that
-        # throw an exception but never yield.
-        func, kwargs = request_args
-        # We need to be extra careful here, because func(**kwargs) might
-        # not be a generator at all: it might simply be a method that
-        # raises an exception. To cope with this we need to push a dummy
-        # entry onto the stack if a StopIteration or PrimtiveFinished
-        # exception is thrown. The logic in execute_yields will then pop
-        # that dummy entry.
-        try:
-            self.push_generator(func(**kwargs))
-        except primitive_functions.PrimitiveFinished, StopIteration:
-            self.push_generator(None)
-            raise
-        except:
-            print("EXCEPTION for " + str(locals()))
-            raise
+        return request_args[0](**(request_args[1]))
 
 
     def execute_call_args(self, request_args):
     def execute_call_args(self, request_args):
-        """Executes a CALL_ARGS-request with the given argument list."""
-        # Format: ("CALL_ARGS", [gen, args])
-        func, args = request_args
-        # We need to be extra careful here, because func(*args) might
-        # not be a generator at all: it might simply be a method that
-        # raises an exception. To cope with this we need to push a dummy
-        # entry onto the stack if a StopIteration or PrimtiveFinished
-        # exception is thrown. The logic in execute_yields will then pop
-        # that dummy entry.
-        try:
-            self.push_generator(func(*args))
-        except primitive_functions.PrimitiveFinished, StopIteration:
-            self.push_generator(None)
-            raise
+        return request_args[0](*(request_args[1]))
 
 
     def execute_sleep(self, request_args):
     def execute_sleep(self, request_args):
-        """Executes a SLEEP-request with the given argument list."""
-        self.append_reply(None)
         raise primitive_functions.SleepKernel(request_args[0], request_args[1])
         raise primitive_functions.SleepKernel(request_args[0], request_args[1])

+ 1 - 1
wrappers/modelverse_SCCD.py

@@ -1,7 +1,7 @@
 """
 """
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 Generated by Statechart compiler by Glenn De Jonghe, Joeri Exelmans, Simon Van Mierlo, and Yentl Van Tendeloo (for the inspiration)
 
 
-Date:   Fri Apr 27 11:01:30 2018
+Date:   Fri Apr 27 13:39:47 2018
 
 
 Model author: Yentl Van Tendeloo
 Model author: Yentl Van Tendeloo
 Model name:   MvK Server
 Model name:   MvK Server