From 55afab22761048900ed38eee06da5d36bf563fa6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Robert=20J=C3=B6rdens?= Date: Fri, 29 Nov 2013 01:43:44 -0700 Subject: [PATCH] sim: use Simulator as a contextmanager __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 | 16 ++++++++++++++++ migen/sim/icarus.py | 7 ++++++- migen/sim/ipc.py | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/migen/sim/generic.py b/migen/sim/generic.py index 30587329..741ccfcf 100644 --- a/migen/sim/generic.py +++ b/migen/sim/generic.py @@ -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: diff --git a/migen/sim/icarus.py b/migen/sim/icarus.py index a692872a..36a200ae 100644 --- a/migen/sim/icarus.py +++ b/migen/sim/icarus.py @@ -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]: diff --git a/migen/sim/ipc.py b/migen/sim/ipc.py index 0121a593..384def18 100644 --- a/migen/sim/ipc.py +++ b/migen/sim/ipc.py @@ -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() -- 2.30.2