Multiple instances are supported in order to enable developers who work on multiple downstream Pigweed projects to work unhindered and also to run multiple test instances in parallel on the same machine.
Each instance is identified by a system absolute path that is also used to store state about the running instance such as pid files for running processes, current emulator and target, etc. This directory also contains information about how to access the emulator channels (e.g. socket ports, pty paths)
The implementation uses the following classes:
pw_emu.frontend.Emulator: the user visible API
pw_emu.core.Launcher: an abstract class that starts an emulator instance for a given configuration and target
pw_emu.core.Connector: an abstract class that is the interface between a running emulator and the user visible APIs
pw_emu.core.Handles: class that stores specific information about a running emulator instance such as ports to reach emulator channels; it is populated by
pw_emu.core.Launcherand saved in the working directory and used by
pw_emu.core.Connectorto access the emulator channels, process pids, etc.
pw_emu.core.Config: loads the pw_emu configuration and provides helper methods to get and validate configuration options
The implementation exposes the ability to list, read and write emulator properties. The frontend does not abstract properties in a way that is emulator or even emulator target independent, other than mandating that each property is identified by a path. Note that the format of the path is also emulator specific and not standardized.
The QEMU frontend is using QMP to communicate with the running QEMU process and implement emulator specific functionality like reset, list or reading properties, etc.
QMP is exposed to the host through two channels: a temporary one to establish
the initial connection that is used to read the dynamic configuration (e.g. TCP
ports, pty paths) and a permanent one that can be used thought the life of the
QEMU processes. The frontend is configuring QEMU to expose QMP to a
localhost TCP port reserved by the frontend and then waiting for QEMU to
establish the connection on that port. Once the connection is established the
frontend will read the configuration of the permanent QMP channel (which can be
either a TCP port or a PTY path) and save it as a channel named
qmp in the
The renode frontend is using renode’s robot port to
interact with the renode process. Although the robot interface is designed for
testing and not as a control interface, it is more robust and better suited to
be used as a machine interface than the alternative
monitor interface which
is user oriented, ANSI colored, echoed, log mixed, telnet interface.
While renode allows passing 0 for ports to allocate a dynamic port, it does not have APIs to retrieve the allocated port. Until support for such a feature is added upstream, the implementation is using the following technique to allocate a port dynamically:
sock = socket.socket(socket.SOCK_INET, socket.SOCK_STREAM) sock.bind(('', 0)) _, port = socket.getsockname() sock.close()
There is a race condition that allows another program to fetch the same port, but it should work in most light use cases until the issue is properly resolved upstream.