forked from M-Labs/artiq
support exceptions raised by RPCs
This commit is contained in:
parent
8ea21f544d
commit
f7232fd3d1
|
@ -10,6 +10,7 @@ from artiq.language import units
|
|||
from artiq.language.context import *
|
||||
from artiq.coredevice.runtime import Environment
|
||||
from artiq.coredevice import runtime_exceptions
|
||||
from artiq.coredevice.rpc_wrapper import RPCWrapper
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -69,6 +70,7 @@ class Comm(AutoContext):
|
|||
self.port.flush()
|
||||
self.set_remote_baud(self.baud_rate)
|
||||
self.set_baud(self.baud_rate)
|
||||
self.rpc_wrapper = RPCWrapper()
|
||||
|
||||
def set_baud(self, baud):
|
||||
self.port.baudrate = baud
|
||||
|
@ -183,19 +185,18 @@ class Comm(AutoContext):
|
|||
if type_tag == "l":
|
||||
r.append(self._receive_rpc_values())
|
||||
|
||||
def _serve_rpc(self, rpc_map):
|
||||
(rpc_num, ) = struct.unpack(">h", _read_exactly(self.port, 2))
|
||||
def _serve_rpc(self, rpc_map, user_exception_map):
|
||||
rpc_num = struct.unpack(">h", _read_exactly(self.port, 2))[0]
|
||||
args = self._receive_rpc_values()
|
||||
logger.debug("rpc service: {} ({})".format(rpc_num, args))
|
||||
r = rpc_map[rpc_num](*args)
|
||||
if r is None:
|
||||
r = 0
|
||||
_write_exactly(self.port, struct.pack(">l", r))
|
||||
eid, r = self.rpc_wrapper.run_rpc(user_exception_map, rpc_map[rpc_num], args)
|
||||
_write_exactly(self.port, struct.pack(">ll", eid, r))
|
||||
logger.debug("rpc service: {} ({}) == {}".format(
|
||||
rpc_num, args, r))
|
||||
|
||||
def _serve_exception(self, user_exception_map):
|
||||
(eid, ) = struct.unpack(">l", _read_exactly(self.port, 4))
|
||||
eid = struct.unpack(">l", _read_exactly(self.port, 4))[0]
|
||||
self.rpc_wrapper.filter_rpc_exception(eid)
|
||||
if eid < core_language.first_user_eid:
|
||||
exception = runtime_exceptions.exception_map[eid]
|
||||
else:
|
||||
|
@ -206,7 +207,7 @@ class Comm(AutoContext):
|
|||
while True:
|
||||
msg = self._get_device_msg()
|
||||
if msg == _D2HMsgType.RPC_REQUEST:
|
||||
self._serve_rpc(rpc_map)
|
||||
self._serve_rpc(rpc_map, user_exception_map)
|
||||
elif msg == _D2HMsgType.KERNEL_EXCEPTION:
|
||||
self._serve_exception(user_exception_map)
|
||||
elif msg == _D2HMsgType.KERNEL_FINISHED:
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
from artiq.coredevice.runtime_exceptions import exception_map, _RPCException
|
||||
|
||||
|
||||
def _lookup_exception(d, e):
|
||||
for eid, exception in d.items():
|
||||
if isinstance(e, exception):
|
||||
return eid
|
||||
return 0
|
||||
|
||||
|
||||
class RPCWrapper:
|
||||
def __init__(self):
|
||||
self.last_exception = None
|
||||
|
||||
def run_rpc(self, user_exception_map, fn, args):
|
||||
eid = 0
|
||||
r = None
|
||||
|
||||
try:
|
||||
r = fn(*args)
|
||||
except Exception as e:
|
||||
eid = _lookup_exception(user_exception_map, e)
|
||||
if not eid:
|
||||
eid = _lookup_exception(exception_map, e)
|
||||
if eid:
|
||||
self.last_exception = None
|
||||
else:
|
||||
self.last_exception = e
|
||||
eid = _RPCException.eid
|
||||
|
||||
if r is None:
|
||||
r = 0
|
||||
else:
|
||||
r = int(r)
|
||||
|
||||
return eid, r
|
||||
|
||||
def filter_rpc_exception(self, eid):
|
||||
if eid == _RPCException.eid:
|
||||
raise self.last_exception
|
|
@ -9,7 +9,11 @@ class OutOfMemory(RuntimeException):
|
|||
"""Raised when the runtime fails to allocate memory.
|
||||
|
||||
"""
|
||||
eid = 0
|
||||
eid = 1
|
||||
|
||||
|
||||
class _RPCException(RuntimeException):
|
||||
eid = 2
|
||||
|
||||
|
||||
class RTIOUnderflow(RuntimeException):
|
||||
|
@ -19,11 +23,9 @@ class RTIOUnderflow(RuntimeException):
|
|||
The offending event is discarded and the RTIO core keeps operating.
|
||||
|
||||
"""
|
||||
eid = 1
|
||||
eid = 3
|
||||
|
||||
|
||||
# Raised by RTIO driver for regular RTIO.
|
||||
# Raised by runtime for DDS FUD.
|
||||
class RTIOSequenceError(RuntimeException):
|
||||
"""Raised when an event is submitted on a given channel with a timestamp
|
||||
not larger than the previous one.
|
||||
|
@ -31,7 +33,7 @@ class RTIOSequenceError(RuntimeException):
|
|||
The offending event is discarded and the RTIO core keeps operating.
|
||||
|
||||
"""
|
||||
eid = 2
|
||||
eid = 4
|
||||
|
||||
|
||||
class RTIOOverflow(RuntimeException):
|
||||
|
@ -43,7 +45,7 @@ class RTIOOverflow(RuntimeException):
|
|||
the exception is caught, and events will be partially retrieved.
|
||||
|
||||
"""
|
||||
eid = 3
|
||||
eid = 5
|
||||
|
||||
|
||||
exception_map = {e.eid: e for e in globals().values()
|
||||
|
|
|
@ -170,6 +170,25 @@ class _Exceptions(AutoContext):
|
|||
self.trace.append(104)
|
||||
|
||||
|
||||
class _RPCExceptions(AutoContext):
|
||||
def build(self):
|
||||
self.success = False
|
||||
|
||||
def exception_raiser(self):
|
||||
raise _MyException
|
||||
|
||||
@kernel
|
||||
def do_not_catch(self):
|
||||
self.exception_raiser()
|
||||
|
||||
@kernel
|
||||
def catch(self):
|
||||
try:
|
||||
self.exception_raiser()
|
||||
except _MyException:
|
||||
self.success = True
|
||||
|
||||
|
||||
@unittest.skipIf(no_hardware, "no hardware")
|
||||
class ExecutionCase(unittest.TestCase):
|
||||
def test_primes(self):
|
||||
|
@ -219,6 +238,17 @@ class ExecutionCase(unittest.TestCase):
|
|||
_run_on_host(_Exceptions, trace=t_host)
|
||||
self.assertEqual(t_device, t_host)
|
||||
|
||||
def test_rpc_exceptions(self):
|
||||
comm = comm_serial.Comm()
|
||||
try:
|
||||
uut = _RPCExceptions(core=core.Core(comm=comm))
|
||||
with self.assertRaises(_MyException):
|
||||
uut.do_not_catch()
|
||||
uut.catch()
|
||||
self.assertTrue(uut.success)
|
||||
finally:
|
||||
comm.close()
|
||||
|
||||
|
||||
class _RTIOLoopback(AutoContext):
|
||||
i = Device("ttl_in")
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <generated/csr.h>
|
||||
|
||||
#include "comm.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
/* host to device */
|
||||
enum {
|
||||
|
@ -224,6 +225,8 @@ static int send_value(int type_tag, void *value)
|
|||
int comm_rpc(int rpc_num, ...)
|
||||
{
|
||||
int type_tag;
|
||||
int eid;
|
||||
int retval;
|
||||
|
||||
send_char(MSGTYPE_RPC_REQUEST);
|
||||
send_sint(rpc_num);
|
||||
|
@ -235,7 +238,13 @@ int comm_rpc(int rpc_num, ...)
|
|||
va_end(args);
|
||||
send_char(0);
|
||||
|
||||
return receive_int();
|
||||
eid = receive_int();
|
||||
retval = receive_int();
|
||||
|
||||
if(eid != EID_NONE)
|
||||
exception_raise(eid);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void comm_log(const char *fmt, ...)
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
#define __EXCEPTIONS_H
|
||||
|
||||
enum {
|
||||
EID_OUT_OF_MEMORY = 0,
|
||||
EID_RTIO_UNDERFLOW = 1,
|
||||
EID_RTIO_SEQUENCE_ERROR = 2,
|
||||
EID_RTIO_OVERFLOW = 3,
|
||||
EID_NONE = 0,
|
||||
EID_OUT_OF_MEMORY = 1,
|
||||
EID_RPC_EXCEPTION = 2,
|
||||
EID_RTIO_UNDERFLOW = 3,
|
||||
EID_RTIO_SEQUENCE_ERROR = 4,
|
||||
EID_RTIO_OVERFLOW = 5,
|
||||
};
|
||||
|
||||
int exception_setjmp(void *jb) __attribute__((returns_twice));
|
||||
|
|
Loading…
Reference in New Issue