sim: use Simulator as a contextmanager
authorRobert Jördens <jordens@gmail.com>
Fri, 29 Nov 2013 08:43:44 +0000 (01:43 -0700)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Fri, 29 Nov 2013 22:05:15 +0000 (23:05 +0100)
__del__ garbage collector callbacks are too delicate.  E.g. imported
modules can be garbage collected before the objects using them. Can't
use os.remove, socket.SHUT_RDWR...

* added a DeprecationWarning if a Simulator is garbage collected without
having its .close() called
* renamed all gc __del__ callbacks to close()
* implemented context manager hooks for Simulator. Use like

   with Simulator(TestBench()) as s:
       s.run()

migen/sim/generic.py
migen/sim/icarus.py
migen/sim/ipc.py

index 305873298d1f829f5737d64186ce36b91464d902..741ccfcfd784fea221fe963db5e3c4e628d0a42c 100644 (file)
@@ -1,3 +1,5 @@
+import warnings
+
 from migen.fhdl.std import *
 from migen.fhdl.structure import _Fragment
 from migen.fhdl import verilog
@@ -177,9 +179,23 @@ class Simulator:
                                self.multiwrite(getattr(obj, k), v)
 
        def __del__(self):
+               if hasattr(self, "ipc"):
+                       warnings.warn("call Simulator.close() to clean up "
+                                       "or use it as a contextmanager", DeprecationWarning)
+                       self.close()
+
+       def close(self):
+               self.ipc.close()
+               self.sim_runner.close()
                del self.ipc
                del self.sim_runner
 
+       def __enter__(self):
+               return self
+
+       def __exit__(self,  type, value, traceback):
+               self.close()
+
 # Contrary to multiread/multiwrite, Proxy fetches the necessary signals only and
 # immediately forwards writes into the simulation.
 class Proxy:
index a692872a1896b9296f47e70fc7de254cba51473e..36a200aef5d741cc1896e5e2c5dbe4db0986316b 100644 (file)
@@ -3,6 +3,7 @@
 
 import subprocess
 import os
+import time
 
 def _str2file(filename, contents):
        f = open(filename, "w")
@@ -27,8 +28,12 @@ class Runner:
                subprocess.check_call(["iverilog", "-o", self.vvp_file] + self.options + [self.top_file, self.dut_file] + self.extra_files)
                self.process = subprocess.Popen(["vvp", "-mmigensim", self.vvp_file])
 
-       def __del__(self):
+       def close(self):
                if hasattr(self, "process"):
+                       self.process.terminate()
+                       if self.process.poll() is None:
+                               time.sleep(.1)
+                               self.process.kill()
                        self.process.wait()
                if not self.keep_files:
                        for f in [self.top_file, self.dut_file, self.vvp_file]:
index 0121a5938fa4589f931b55ab27911ea736f60fdd..384def18ca2f6d1c22320497b5830c0fadd4a100 100644 (file)
@@ -166,7 +166,7 @@ class Initiator:
                        raise PacketTooLarge
                return _unpack(packet)
 
-       def __del__(self):
+       def close(self):
                if hasattr(self, "conn"):
                        self.conn.shutdown(socket.SHUT_RDWR)
                        self.conn.close()