Skip to content

Commit 27d2390

Browse files
author
whitequark
committedAug 8, 2015
Add zero-cost exception support to runtime and host.
1 parent 1d61e44 commit 27d2390

File tree

11 files changed

+238
-67
lines changed

11 files changed

+238
-67
lines changed
 

Diff for: ‎artiq/compiler/builtins.py

+1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class TException(types.TMono):
8686
("__file__", TStr()),
8787
("__line__", TInt(types.TValue(32))),
8888
("__col__", TInt(types.TValue(32))),
89+
("__func__", TStr()),
8990
("__message__", TStr()),
9091
("__param0__", TInt(types.TValue(64))),
9192
("__param1__", TInt(types.TValue(64))),

Diff for: ‎artiq/compiler/transforms/artiq_ir_generator.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def visit_ModuleT(self, node):
157157

158158
def visit_function(self, node, is_lambda, is_internal):
159159
if is_lambda:
160-
name = "lambda.{}.{}".format(node.loc.line(), node.loc.column())
160+
name = "lambda@{}:{}".format(node.loc.line(), node.loc.column())
161161
typ = node.type.find()
162162
else:
163163
name = node.name
@@ -471,9 +471,11 @@ def raise_exn(self, exn):
471471
loc_file = ir.Constant(self.current_loc.source_buffer.name, builtins.TStr())
472472
loc_line = ir.Constant(self.current_loc.line(), builtins.TInt(types.TValue(32)))
473473
loc_column = ir.Constant(self.current_loc.column(), builtins.TInt(types.TValue(32)))
474+
loc_function = ir.Constant(".".join(self.name), builtins.TStr())
474475
self.append(ir.SetAttr(exn, "__file__", loc_file))
475476
self.append(ir.SetAttr(exn, "__line__", loc_line))
476477
self.append(ir.SetAttr(exn, "__col__", loc_column))
478+
self.append(ir.SetAttr(exn, "__func__", loc_function))
477479

478480
if self.unwind_target is not None:
479481
self.append(ir.Raise(exn, self.unwind_target))
@@ -1237,6 +1239,7 @@ def alloc_exn(self, typ, message=None, param0=None, param1=None, param2=None):
12371239
ir.Constant("<not thrown>", builtins.TStr()), # file
12381240
ir.Constant(0, builtins.TInt(types.TValue(32))), # line
12391241
ir.Constant(0, builtins.TInt(types.TValue(32))), # column
1242+
ir.Constant("<not thrown>", builtins.TStr()), # function
12401243
]
12411244

12421245
if message is None:

Diff for: ‎artiq/coredevice/comm_generic.py

+83-35
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import struct
22
import logging
3+
import traceback
34
from enum import Enum
45
from fractions import Fraction
56

@@ -18,11 +19,12 @@ class _H2DMsgType(Enum):
1819
RUN_KERNEL = 5
1920

2021
RPC_REPLY = 6
22+
RPC_EXCEPTION = 7
2123

22-
FLASH_READ_REQUEST = 7
23-
FLASH_WRITE_REQUEST = 8
24-
FLASH_ERASE_REQUEST = 9
25-
FLASH_REMOVE_REQUEST = 10
24+
FLASH_READ_REQUEST = 8
25+
FLASH_WRITE_REQUEST = 9
26+
FLASH_ERASE_REQUEST = 10
27+
FLASH_REMOVE_REQUEST = 11
2628

2729

2830
class _D2HMsgType(Enum):
@@ -223,16 +225,12 @@ def switch_clock(self, external):
223225

224226
self._read_empty(_D2HMsgType.CLOCK_SWITCH_COMPLETED)
225227

226-
def load(self, kernel_library):
227-
self._write_header(_H2DMsgType.LOAD_LIBRARY)
228-
self._write_chunk(kernel_library)
229-
self._write_flush()
230-
231-
self._read_empty(_D2HMsgType.LOAD_COMPLETED)
228+
def get_log(self):
229+
self._write_empty(_H2DMsgType.LOG_REQUEST)
232230

233-
def run(self):
234-
self._write_empty(_H2DMsgType.RUN_KERNEL)
235-
logger.debug("running kernel")
231+
self._read_header()
232+
self._read_expect(_D2HMsgType.LOG_REPLY)
233+
return self._read_chunk(self._read_length).decode('utf-8')
236234

237235
def flash_storage_read(self, key):
238236
self._write_header(_H2DMsgType.FLASH_READ_REQUEST)
@@ -267,7 +265,18 @@ def flash_storage_remove(self, key):
267265

268266
self._read_empty(_D2HMsgType.FLASH_OK_REPLY)
269267

270-
def _receive_rpc_value(self, tag):
268+
def load(self, kernel_library):
269+
self._write_header(_H2DMsgType.LOAD_LIBRARY)
270+
self._write_chunk(kernel_library)
271+
self._write_flush()
272+
273+
self._read_empty(_D2HMsgType.LOAD_COMPLETED)
274+
275+
def run(self):
276+
self._write_empty(_H2DMsgType.RUN_KERNEL)
277+
logger.debug("running kernel")
278+
279+
def _receive_rpc_value(self, tag, rpc_map):
271280
if tag == "n":
272281
return None
273282
elif tag == "b":
@@ -286,37 +295,83 @@ def _receive_rpc_value(self, tag):
286295
elt_tag = chr(self._read_int8())
287296
length = self._read_int32()
288297
return [self._receive_rpc_value(elt_tag) for _ in range(length)]
298+
elif tag == "o":
299+
return rpc_map[self._read_int32()]
289300
else:
290301
raise IOError("Unknown RPC value tag: {}", tag)
291302

292-
def _receive_rpc_values(self):
303+
def _receive_rpc_values(self, rpc_map):
293304
result = []
294305
while True:
295306
tag = chr(self._read_int8())
296307
if tag == "\x00":
297308
return result
298309
else:
299-
result.append(self._receive_rpc_value(tag))
310+
result.append(self._receive_rpc_value(tag, rpc_map))
300311

301312
def _serve_rpc(self, rpc_map):
302313
service = self._read_int32()
303-
args = self._receive_rpc_values()
314+
args = self._receive_rpc_values(rpc_map)
304315
logger.debug("rpc service: %d %r", service, args)
305316

306-
eid, result = rpc_wrapper.run_rpc(rpc_map[rpc_num], args)
307-
logger.debug("rpc service: %d %r == %r (eid %d)", service, args,
308-
result, eid)
317+
try:
318+
result = rpc_map[rpc_num](args)
319+
if not isinstance(result, int) or not (-2**31 < result < 2**31-1):
320+
raise ValueError("An RPC must return an int(width=32)")
321+
except ARTIQException as exn:
322+
logger.debug("rpc service: %d %r ! %r", service, args, exn)
323+
324+
self._write_header(_H2DMsgType.RPC_EXCEPTION)
325+
self._write_string(exn.name)
326+
self._write_string(exn.message)
327+
for index in range(3):
328+
self._write_int64(exn.param[index])
329+
330+
self._write_string(exn.filename)
331+
self._write_int32(exn.line)
332+
self._write_int32(exn.column)
333+
self._write_string(exn.function)
334+
335+
self._write_flush()
336+
except Exception as exn:
337+
logger.debug("rpc service: %d %r ! %r", service, args, exn)
338+
339+
self._write_header(_H2DMsgType.RPC_EXCEPTION)
340+
self._write_string(type(exn).__name__)
341+
self._write_string(str(exn))
342+
for index in range(3):
343+
self._write_int64(0)
344+
345+
((filename, line, function, _), ) = traceback.extract_tb(exn.__traceback__)
346+
self._write_string(filename)
347+
self._write_int32(line)
348+
self._write_int32(-1) # column not known
349+
self._write_string(function)
350+
351+
self._write_flush()
352+
else:
353+
logger.debug("rpc service: %d %r == %r", service, args, result)
309354

310-
self._write_header(_H2DMsgType.RPC_REPLY)
311-
self._write_int32(eid)
312-
self._write_int32(result)
313-
self._write_flush()
355+
self._write_header(_H2DMsgType.RPC_REPLY)
356+
self._write_int32(result)
357+
self._write_flush()
314358

315359
def _serve_exception(self):
316-
eid = self._read_int32()
317-
params = [self._read_int64() for _ in range(3)]
318-
rpc_wrapper.filter_rpc_exception(eid)
319-
raise exception(self.core, *params)
360+
name = self._read_string()
361+
message = self._read_string()
362+
params = [self._read_int64() for _ in range(3)]
363+
364+
filename = self._read_string()
365+
line = self._read_int32()
366+
column = self._read_int32()
367+
function = self._read_string()
368+
369+
backtrace = [self._read_int32() for _ in range(self._read_int32())]
370+
# we don't have debug information yet.
371+
# print("exception backtrace:", [hex(x) for x in backtrace])
372+
373+
raise core_language.ARTIQException(name, message, params,
374+
filename, line, column, function)
320375

321376
def serve(self, rpc_map):
322377
while True:
@@ -328,10 +383,3 @@ def serve(self, rpc_map):
328383
else:
329384
self._read_expect(_D2HMsgType.KERNEL_FINISHED)
330385
return
331-
332-
def get_log(self):
333-
self._write_empty(_H2DMsgType.LOG_REQUEST)
334-
335-
self._read_header()
336-
self._read_expect(_D2HMsgType.LOG_REPLY)
337-
return self._read_chunk(self._read_length).decode('utf-8')

Diff for: ‎artiq/coredevice/exceptions.py

+8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
from artiq.language.core import ARTIQException
22

3+
class ZeroDivisionError(ARTIQException):
4+
"""Python's :class:`ZeroDivisionError`, mirrored in ARTIQ."""
5+
6+
class ValueError(ARTIQException):
7+
"""Python's :class:`ValueError`, mirrored in ARTIQ."""
8+
9+
class IndexError(ARTIQException):
10+
"""Python's :class:`IndexError`, mirrored in ARTIQ."""
311

412
class InternalError(ARTIQException):
513
"""Raised when the runtime encounters an internal error condition."""

Diff for: ‎artiq/language/core.py

+22-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Core ARTIQ extensions to the Python language.
33
"""
44

5+
import linecache
56
from collections import namedtuple
67
from functools import wraps
78

@@ -278,7 +279,8 @@ class ARTIQException(Exception):
278279
"""Base class for exceptions raised or passed through the core device."""
279280

280281
# Try and create an instance of the specific class, if one exists.
281-
def __new__(cls, name, message, params):
282+
def __new__(cls, name, message,
283+
params, filename, line, column, function):
282284
def find_subclass(cls):
283285
if cls.__name__ == name:
284286
return cls
@@ -293,15 +295,30 @@ def find_subclass(cls):
293295
more_specific_cls = cls
294296

295297
exn = Exception.__new__(more_specific_cls)
296-
exn.__init__(name, message, params)
298+
exn.__init__(name, message, params,
299+
filename, line, column, function)
297300
return exn
298301

299-
def __init__(self, name, message, params):
302+
def __init__(self, name, message, params,
303+
filename, line, column, function):
300304
Exception.__init__(self, name, message, *params)
301305
self.name, self.message, self.params = name, message, params
306+
self.filename, self.line, self.column = filename, line, column
307+
self.function = function
302308

303309
def __str__(self):
310+
lines = []
311+
304312
if type(self).__name__ == self.name:
305-
return self.message.format(*self.params)
313+
lines.append(self.message.format(*self.params))
306314
else:
307-
return "({}) {}".format(self.name, self.message.format(*self.params))
315+
lines.append("({}) {}".format(self.name, self.message.format(*self.params)))
316+
317+
lines.append("Core Device Traceback (most recent call last):")
318+
lines.append(" File \"{file}\", line {line}, column {column}, in {function}".
319+
format(file=self.filename, line=self.line, column=self.column + 1,
320+
function=self.function))
321+
line = linecache.getline(self.filename, self.line)
322+
lines.append(" {}".format(line.strip() if line else "<unknown>"))
323+
324+
return "\n".join(lines)

Diff for: ‎soc/runtime/artiq_personality.h

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ struct artiq_exception {
1212
const char *file;
1313
int32_t line;
1414
int32_t column;
15+
const char *function;
1516
const char *message;
1617
int64_t param[3];
1718
};

Diff for: ‎soc/runtime/kloader.c

+18-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ void kloader_start_bridge()
3030
start_kernel_cpu(NULL);
3131
}
3232

33-
static int load_or_start_kernel(void *library, int run_kernel)
33+
static int load_or_start_kernel(const void *library, int run_kernel)
3434
{
3535
static struct dyld_info library_info;
3636
struct msg_load_request request = {
@@ -56,7 +56,7 @@ static int load_or_start_kernel(void *library, int run_kernel)
5656
return 1;
5757
}
5858

59-
int kloader_load_library(void *library)
59+
int kloader_load_library(const void *library)
6060
{
6161
if(!kernel_cpu_reset_read()) {
6262
log("BUG: attempted to load kernel library while kernel CPU is running");
@@ -66,6 +66,22 @@ int kloader_load_library(void *library)
6666
return load_or_start_kernel(library, 0);
6767
}
6868

69+
void kloader_filter_backtrace(struct artiq_backtrace_item *backtrace,
70+
size_t *backtrace_size) {
71+
struct artiq_backtrace_item *cursor = backtrace;
72+
73+
// Remove all backtrace items belonging to ksupport and subtract
74+
// shared object base from the addresses.
75+
for(int i = 0; i < *backtrace_size; i++) {
76+
if(backtrace[i].function > KERNELCPU_PAYLOAD_ADDRESS) {
77+
backtrace[i].function -= KERNELCPU_PAYLOAD_ADDRESS;
78+
*cursor++ = backtrace[i];
79+
}
80+
}
81+
82+
*backtrace_size = cursor - backtrace;
83+
}
84+
6985
void kloader_start_kernel()
7086
{
7187
load_or_start_kernel(NULL, 1);

Diff for: ‎soc/runtime/kloader.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
#ifndef __KLOADER_H
22
#define __KLOADER_H
33

4+
#include "artiq_personality.h"
5+
46
#define KERNELCPU_EXEC_ADDRESS 0x40400000
57
#define KERNELCPU_PAYLOAD_ADDRESS 0x40420000
68
#define KERNELCPU_LAST_ADDRESS (0x4fffffff - 1024*1024)
79
#define KSUPPORT_HEADER_SIZE 0x80
810

911
extern long long int now;
1012

11-
int kloader_load_library(void *code);
13+
int kloader_load_library(const void *code);
14+
void kloader_filter_backtrace(struct artiq_backtrace_item *backtrace,
15+
size_t *backtrace_size);
1216

1317
void kloader_start_bridge(void);
1418
int kloader_start_idle_kernel(void);

Diff for: ‎soc/runtime/ksupport.c

+15-13
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ long long int now_init(void)
246246

247247
reply = mailbox_wait_and_receive();
248248
if(reply->type != MESSAGE_TYPE_NOW_INIT_REPLY) {
249-
log("Malformed MESSAGE_TYPE_NOW_INIT_REQUEST reply type");
249+
log("Malformed MESSAGE_TYPE_NOW_INIT_REQUEST reply type %d",
250+
reply->type);
250251
while(1);
251252
}
252253
now = reply->now;
@@ -281,7 +282,8 @@ int watchdog_set(int ms)
281282

282283
reply = mailbox_wait_and_receive();
283284
if(reply->type != MESSAGE_TYPE_WATCHDOG_SET_REPLY) {
284-
log("Malformed MESSAGE_TYPE_WATCHDOG_SET_REQUEST reply type");
285+
log("Malformed MESSAGE_TYPE_WATCHDOG_SET_REQUEST reply type %d",
286+
reply->type);
285287
while(1);
286288
}
287289
id = reply->id;
@@ -302,7 +304,7 @@ void watchdog_clear(int id)
302304
int rpc(int rpc_num, ...)
303305
{
304306
struct msg_rpc_request request;
305-
struct msg_rpc_reply *reply;
307+
struct msg_base *reply;
306308

307309
request.type = MESSAGE_TYPE_RPC_REQUEST;
308310
request.rpc_num = rpc_num;
@@ -311,20 +313,20 @@ int rpc(int rpc_num, ...)
311313
va_end(request.args);
312314

313315
reply = mailbox_wait_and_receive();
314-
if(reply->type != MESSAGE_TYPE_RPC_REPLY) {
315-
log("Malformed MESSAGE_TYPE_RPC_REPLY reply type");
316-
while(1);
317-
}
318-
319-
if(reply->exception != NULL) {
316+
if(reply->type == MESSAGE_TYPE_RPC_REPLY) {
317+
int result = ((struct msg_rpc_reply *)reply)->result;
318+
mailbox_acknowledge();
319+
return result;
320+
} else if(reply->type == MESSAGE_TYPE_RPC_EXCEPTION) {
320321
struct artiq_exception exception;
321-
memcpy(&exception, reply->exception, sizeof(exception));
322+
memcpy(&exception, ((struct msg_rpc_exception *)reply)->exception,
323+
sizeof(struct artiq_exception));
322324
mailbox_acknowledge();
323325
__artiq_raise(&exception);
324326
} else {
325-
int retval = reply->retval;
326-
mailbox_acknowledge();
327-
return retval;
327+
log("Malformed MESSAGE_TYPE_RPC_REQUEST reply type %d",
328+
reply->type);
329+
while(1);
328330
}
329331
}
330332

Diff for: ‎soc/runtime/messages.h

+7-2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ enum {
1616
MESSAGE_TYPE_WATCHDOG_CLEAR,
1717
MESSAGE_TYPE_RPC_REQUEST,
1818
MESSAGE_TYPE_RPC_REPLY,
19+
MESSAGE_TYPE_RPC_EXCEPTION,
1920
MESSAGE_TYPE_LOG,
2021

2122
MESSAGE_TYPE_BRG_READY,
@@ -37,7 +38,7 @@ struct msg_base {
3738
/* kernel messages */
3839

3940
struct msg_load_request {
40-
void *library;
41+
const void *library;
4142
struct dyld_info *library_info;
4243
int run_kernel;
4344
};
@@ -86,9 +87,13 @@ struct msg_rpc_request {
8687
};
8788

8889
struct msg_rpc_reply {
90+
int type;
91+
int result;
92+
};
93+
94+
struct msg_rpc_exception {
8995
int type;
9096
struct artiq_exception *exception;
91-
int retval;
9297
};
9398

9499
struct msg_log {

Diff for: ‎soc/runtime/session.c

+74-8
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,13 @@ static int32_t in_packet_int32()
128128
return result;
129129
}
130130

131+
static int64_t in_packet_int64()
132+
{
133+
int64_t result;
134+
in_packet_chunk(&result, sizeof(result));
135+
return result;
136+
}
137+
131138
static const void *in_packet_bytes(int *length)
132139
{
133140
*length = in_packet_int32();
@@ -310,6 +317,7 @@ enum {
310317
REMOTEMSG_TYPE_RUN_KERNEL,
311318

312319
REMOTEMSG_TYPE_RPC_REPLY,
320+
REMOTEMSG_TYPE_RPC_EXCEPTION,
313321

314322
REMOTEMSG_TYPE_FLASH_READ_REQUEST,
315323
REMOTEMSG_TYPE_FLASH_WRITE_REQUEST,
@@ -452,15 +460,44 @@ static int process_input(void)
452460
case REMOTEMSG_TYPE_RPC_REPLY: {
453461
struct msg_rpc_reply reply;
454462

463+
int result = in_packet_int32();
464+
455465
if(user_kernel_state != USER_KERNEL_WAIT_RPC) {
456466
log("Unsolicited RPC reply");
457467
return 0; // restart session
458468
}
459469

460470
reply.type = MESSAGE_TYPE_RPC_REPLY;
461-
// FIXME memcpy(&reply.eid, &buffer_in[9], 4);
462-
// memcpy(&reply.retval, &buffer_in[13], 4);
471+
reply.result = result;
472+
mailbox_send_and_wait(&reply);
473+
474+
user_kernel_state = USER_KERNEL_RUNNING;
475+
break;
476+
}
477+
478+
case REMOTEMSG_TYPE_RPC_EXCEPTION: {
479+
struct msg_rpc_exception reply;
480+
481+
struct artiq_exception exception;
482+
exception.name = in_packet_string();
483+
exception.message = in_packet_string();
484+
exception.param[0] = in_packet_int64();
485+
exception.param[1] = in_packet_int64();
486+
exception.param[2] = in_packet_int64();
487+
exception.file = in_packet_string();
488+
exception.line = in_packet_int32();
489+
exception.column = in_packet_int32();
490+
exception.function = in_packet_string();
491+
492+
if(user_kernel_state != USER_KERNEL_WAIT_RPC) {
493+
log("Unsolicited RPC exception reply");
494+
return 0; // restart session
495+
}
496+
497+
reply.type = MESSAGE_TYPE_RPC_EXCEPTION;
498+
reply.exception = &exception;
463499
mailbox_send_and_wait(&reply);
500+
464501
user_kernel_state = USER_KERNEL_RUNNING;
465502
break;
466503
}
@@ -509,8 +546,6 @@ static int send_rpc_value(const char **tag, void *value)
509546
break;
510547

511548
case 'l': { // list(elt='a)
512-
size = sizeof(void*);
513-
514549
struct { uint32_t length; void *elements; } *list = value;
515550
void *element = list->elements;
516551

@@ -522,6 +557,18 @@ static int send_rpc_value(const char **tag, void *value)
522557
element = (void*)((intptr_t)element + element_size);
523558
}
524559
*tag = tag_copy;
560+
561+
size = sizeof(list);
562+
break;
563+
}
564+
565+
case 'o': { // host object
566+
struct { uint32_t id; } *object = value;
567+
568+
if(!out_packet_int32(object->id))
569+
return -1;
570+
571+
size = sizeof(object);
525572
break;
526573
}
527574

@@ -575,10 +622,29 @@ static int process_kmsg(struct msg_base *umsg)
575622
case MESSAGE_TYPE_EXCEPTION: {
576623
struct msg_exception *msg = (struct msg_exception *)umsg;
577624

578-
out_packet_empty(REMOTEMSG_TYPE_KERNEL_EXCEPTION);
579-
// memcpy(&buffer_out[9], &msg->eid, 4);
580-
// memcpy(&buffer_out[13], msg->eparams, 3*8);
581-
// submit_output(9+4+3*8);
625+
out_packet_start(REMOTEMSG_TYPE_KERNEL_EXCEPTION);
626+
627+
out_packet_string(msg->exception->name);
628+
out_packet_string(msg->exception->message);
629+
out_packet_int64(msg->exception->param[0]);
630+
out_packet_int64(msg->exception->param[1]);
631+
out_packet_int64(msg->exception->param[2]);
632+
633+
out_packet_string(msg->exception->file);
634+
out_packet_int32(msg->exception->line);
635+
out_packet_int32(msg->exception->column);
636+
out_packet_string(msg->exception->function);
637+
638+
kloader_filter_backtrace(msg->backtrace,
639+
&msg->backtrace_size);
640+
641+
out_packet_int32(msg->backtrace_size);
642+
for(int i = 0; i < msg->backtrace_size; i++) {
643+
struct artiq_backtrace_item *item = &msg->backtrace[i];
644+
out_packet_int32(item->function + item->offset);
645+
}
646+
647+
out_packet_finish();
582648

583649
kloader_stop();
584650
user_kernel_state = USER_KERNEL_LOADED;

0 commit comments

Comments
 (0)
Please sign in to comment.