Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 661b9bfbfacd
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 03e317780bed
Choose a head ref
  • 3 commits
  • 4 files changed
  • 1 contributor

Commits on Oct 18, 2015

  1. Copy the full SHA
    5947f54 View commit details
  2. Copy the full SHA
    a560676 View commit details
  3. Copy the full SHA
    03e3177 View commit details
Showing with 42 additions and 35 deletions.
  1. +2 −12 artiq/frontend/artiq_rpctool.py
  2. +10 −5 artiq/master/worker_db.py
  3. +30 −9 artiq/protocols/pc_rpc.py
  4. +0 −9 examples/master/device_db.pyon
14 changes: 2 additions & 12 deletions artiq/frontend/artiq_rpctool.py
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
import numpy as np # Needed to use numpy in RPC call arguments on cmd line
import pprint

from artiq.protocols.pc_rpc import Client
from artiq.protocols.pc_rpc import AutoTarget, Client


def get_argparser():
@@ -85,19 +85,9 @@ def main():
args = get_argparser().parse_args()

remote = Client(args.server, args.port, None)

targets, description = remote.get_rpc_id()

if args.action != "list-targets":
# If no target specified and remote has only one, then use this one.
# Exit otherwise.
if len(targets) > 1 and args.target is None:
print("Remote server has several targets, please supply one with "
"-t")
sys.exit(1)
elif args.target is None:
args.target = targets[0]
remote.select_rpc_target(args.target)
remote.select_rpc_target(AutoTarget)

if args.action == "list-targets":
list_targets(targets, description)
15 changes: 10 additions & 5 deletions artiq/master/worker_db.py
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@
import h5py

from artiq.protocols.sync_struct import Notifier
from artiq.protocols.pc_rpc import Client, BestEffortClient
from artiq.protocols.pc_rpc import AutoTarget, Client, BestEffortClient


logger = logging.getLogger(__name__)
@@ -22,11 +22,16 @@ def _create_device(desc, device_mgr):
device_class = getattr(module, desc["class"])
return device_class(device_mgr, **desc["arguments"])
elif ty == "controller":
if desc["best_effort"]:
cl = BestEffortClient
if desc.get("best_effort", False):
cls = BestEffortClient
else:
cl = Client
return cl(desc["host"], desc["port"], desc["target_name"])
cls = Client
# Automatic target can be specified either by the absence of
# the target_name parameter, or a None value.
target_name = desc.get("target_name", None)
if target_name is None:
target_name = AutoTarget
return cls(desc["host"], desc["port"], target_name)
else:
raise ValueError("Unsupported type in device DB: " + ty)

39 changes: 30 additions & 9 deletions artiq/protocols/pc_rpc.py
Original file line number Diff line number Diff line change
@@ -27,6 +27,12 @@
logger = logging.getLogger(__name__)


class AutoTarget:
"""Use this as target value in clients for them to automatically connect
to the target exposed by the server. Servers must have only one target."""
pass


class RemoteError(Exception):
"""Raised when a RPC failed or raised an exception on the remote (server)
side."""
@@ -42,6 +48,20 @@ class IncompatibleServer(Exception):
_init_string = b"ARTIQ pc_rpc\n"


def _validate_target_name(target_name, target_names):
if target_name is AutoTarget:
if len(target_names) > 1:
raise ValueError("Server has multiple targets: " +
" ".join(sorted(target_names)))
else:
target_name = target_names[0]
elif target_name not in target_names:
raise IncompatibleServer(
"valid target name(s): " +
" ".join(sorted(target_names)))
return target_name


class Client:
"""This class proxies the methods available on the server so that they
can be used as if they were local methods.
@@ -67,11 +87,13 @@ class Client:
:param port: TCP port to use.
:param target_name: Target name to select. ``IncompatibleServer`` is
raised if the target does not exist.
Use ``AutoTarget`` for automatic selection if the server has only one
target.
Use ``None`` to skip selecting a target. The list of targets can then
be retrieved using ``get_rpc_id`` and then one can be selected later
using ``select_rpc_target``.
"""
def __init__(self, host, port, target_name):
def __init__(self, host, port, target_name=AutoTarget):
self.__socket = socket.create_connection((host, port))

try:
@@ -89,8 +111,7 @@ def __init__(self, host, port, target_name):
def select_rpc_target(self, target_name):
"""Selects a RPC target by name. This function should be called
exactly once if the object was created with ``target_name=None``."""
if target_name not in self.__target_names:
raise IncompatibleServer
target_name = _validate_target_name(target_name, self.__target_names)
self.__socket.sendall((target_name + "\n").encode())

def get_rpc_id(self):
@@ -180,8 +201,7 @@ def select_rpc_target(self, target_name):
"""Selects a RPC target by name. This function should be called
exactly once if the connection was created with ``target_name=None``.
"""
if target_name not in self.__target_names:
raise IncompatibleServer
target_name = _validate_target_name(target_name, self.__target_names)
self.__writer.write((target_name + "\n").encode())

def get_rpc_id(self):
@@ -259,7 +279,8 @@ def __init__(self, host, port, target_name,
except:
logger.warning("first connection attempt to %s:%d[%s] failed, "
"retrying in the background",
self.__host, self.__port, self.__target_name)
self.__host, self.__port, self.__target_name,
exc_info=True)
self.__start_conretry()
else:
self.__conretry_thread = None
@@ -273,9 +294,9 @@ def __coninit(self, timeout):
(self.__host, self.__port), timeout)
self.__socket.sendall(_init_string)
server_identification = self.__recv()
if self.__target_name not in server_identification["targets"]:
raise IncompatibleServer
self.__socket.sendall((self.__target_name + "\n").encode())
target_name = _validate_target_name(self.__target_name,
server_identification["targets"])
self.__socket.sendall((target_name + "\n").encode())

def __start_conretry(self):
self.__conretry_thread = threading.Thread(target=self.__conretry)
9 changes: 0 additions & 9 deletions examples/master/device_db.pyon
Original file line number Diff line number Diff line change
@@ -92,34 +92,26 @@

"qc_q1_0": {
"type": "controller",
"best_effort": false,
"host": "::1",
"port": 4000,
"target_name": "pdq2",
"command": "pdq2_controller -p {port} --bind {bind} --simulation --dump qc_q1_0.bin"
},
"qc_q1_1": {
"type": "controller",
"best_effort": false,
"host": "::1",
"port": 4001,
"target_name": "pdq2",
"command": "pdq2_controller -p {port} --bind {bind} --simulation --dump qc_q1_1.bin"
},
"qc_q1_2": {
"type": "controller",
"best_effort": false,
"host": "::1",
"port": 4002,
"target_name": "pdq2",
"command": "pdq2_controller -p {port} --bind {bind} --simulation --dump qc_q1_2.bin"
},
"qc_q1_3": {
"type": "controller",
"best_effort": false,
"host": "::1",
"port": 4003,
"target_name": "pdq2",
"command": "pdq2_controller -p {port} --bind {bind} --simulation --dump qc_q1_3.bin"
},
"electrodes": {
@@ -138,7 +130,6 @@
"best_effort": true,
"host": "::1",
"port": 3253,
"target_name": "lda",
"command": "lda_controller -p {port} --bind {bind} --simulation"
},