Skip to content

Commit b26af5d

Browse files
author
whitequark
committedAug 8, 2015
Implement sending RPCs.
1 parent 22457bc commit b26af5d

File tree

11 files changed

+432
-130
lines changed

11 files changed

+432
-130
lines changed
 

Diff for: ‎artiq/compiler/builtins.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ def is_bool(typ):
163163

164164
def is_int(typ, width=None):
165165
if width is not None:
166-
return types.is_mono(typ, "int", {"width": width})
166+
return types.is_mono(typ, "int", width=width)
167167
else:
168168
return types.is_mono(typ, "int")
169169

@@ -184,7 +184,7 @@ def is_numeric(typ):
184184

185185
def is_list(typ, elt=None):
186186
if elt is not None:
187-
return types.is_mono(typ, "list", {"elt": elt})
187+
return types.is_mono(typ, "list", elt=elt)
188188
else:
189189
return types.is_mono(typ, "list")
190190

Diff for: ‎artiq/compiler/embedding.py

+114-11
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
annotated as ``@kernel`` when they are referenced.
66
"""
77

8-
import inspect, os
8+
import os, re, linecache, inspect
9+
from collections import OrderedDict
10+
911
from pythonparser import ast, source, diagnostic, parse_buffer
12+
1013
from . import types, builtins, asttyped, prelude
11-
from .transforms import ASTTypedRewriter, Inferencer
14+
from .transforms import ASTTypedRewriter, Inferencer, IntMonomorphizer
1215

1316

1417
class ASTSynthesizer:
@@ -45,6 +48,9 @@ def quote(self, value):
4548
typ = builtins.TFloat()
4649
return asttyped.NumT(n=value, ctx=None, type=typ,
4750
loc=self._add(repr(value)))
51+
elif isinstance(value, str):
52+
return asttyped.StrT(s=value, ctx=None, type=builtins.TStr(),
53+
loc=self._add(repr(value)))
4854
elif isinstance(value, list):
4955
begin_loc = self._add("[")
5056
elts = []
@@ -123,7 +129,7 @@ def visit_Name(self, node):
123129
if inspect.isfunction(value):
124130
# It's a function. We need to translate the function and insert
125131
# a reference to it.
126-
function_name = self.quote_function(value)
132+
function_name = self.quote_function(value, node.loc)
127133
return asttyped.NameT(id=function_name, ctx=None,
128134
type=self.globals[function_name],
129135
loc=node.loc)
@@ -154,7 +160,19 @@ def __init__(self, engine=None):
154160

155161
self.functions = {}
156162

163+
self.next_rpc = 0
157164
self.rpc_map = {}
165+
self.inverse_rpc_map = {}
166+
167+
def _map(self, obj):
168+
obj_id = id(obj)
169+
if obj_id in self.inverse_rpc_map:
170+
return self.inverse_rpc_map[obj_id]
171+
172+
self.next_rpc += 1
173+
self.rpc_map[self.next_rpc] = obj
174+
self.inverse_rpc_map[obj_id] = self.next_rpc
175+
return self.next_rpc
158176

159177
def _iterate(self):
160178
inferencer = Inferencer(engine=self.engine)
@@ -213,17 +231,102 @@ def _quote_embedded_function(self, function):
213231
quote_function=self._quote_function)
214232
return asttyped_rewriter.visit(function_node)
215233

216-
def _quote_function(self, function):
234+
def _function_def_note(self, function):
235+
filename = function.__code__.co_filename
236+
line = function.__code__.co_firstlineno
237+
name = function.__code__.co_name
238+
239+
source_line = linecache.getline(filename, line)
240+
column = re.search("def", source_line).start(0)
241+
source_buffer = source.Buffer(source_line, filename, line)
242+
loc = source.Range(source_buffer, column, column)
243+
return diagnostic.Diagnostic("note",
244+
"definition of function '{function}'",
245+
{"function": name},
246+
loc)
247+
248+
def _type_of_param(self, function, loc, param):
249+
if param.default is not inspect.Parameter.empty:
250+
# Try and infer the type from the default value.
251+
# This is tricky, because the default value might not have
252+
# a well-defined type in APython.
253+
# In this case, we bail out, but mention why we do it.
254+
synthesizer = ASTSynthesizer()
255+
ast = synthesizer.quote(param.default)
256+
synthesizer.finalize()
257+
258+
def proxy_diagnostic(diag):
259+
note = diagnostic.Diagnostic("note",
260+
"expanded from here while trying to infer a type for an"
261+
" unannotated optional argument '{param_name}' from its default value",
262+
{"param_name": param.name},
263+
loc)
264+
diag.notes.append(note)
265+
266+
diag.notes.append(self._function_def_note(function))
267+
268+
self.engine.process(diag)
269+
270+
proxy_engine = diagnostic.Engine()
271+
proxy_engine.process = proxy_diagnostic
272+
Inferencer(engine=proxy_engine).visit(ast)
273+
IntMonomorphizer(engine=proxy_engine).visit(ast)
274+
275+
return ast.type
276+
else:
277+
# Let the rest of the program decide.
278+
return types.TVar()
279+
280+
def _quote_rpc_function(self, function, loc):
281+
signature = inspect.signature(function)
282+
283+
arg_types = OrderedDict()
284+
optarg_types = OrderedDict()
285+
for param in signature.parameters.values():
286+
if param.kind not in (inspect.Parameter.POSITIONAL_ONLY,
287+
inspect.Parameter.POSITIONAL_OR_KEYWORD):
288+
# We pretend we don't see *args, kwpostargs=..., **kwargs.
289+
# Since every method can be still invoked without any arguments
290+
# going into *args and the slots after it, this is always safe,
291+
# if sometimes constraining.
292+
#
293+
# Accepting POSITIONAL_ONLY is OK, because the compiler
294+
# desugars the keyword arguments into positional ones internally.
295+
continue
296+
297+
if param.default is inspect.Parameter.empty:
298+
arg_types[param.name] = self._type_of_param(function, loc, param)
299+
else:
300+
optarg_types[param.name] = self._type_of_param(function, loc, param)
301+
302+
# Fixed for now.
303+
ret_type = builtins.TInt(types.TValue(32))
304+
305+
rpc_type = types.TRPCFunction(arg_types, optarg_types, ret_type,
306+
service=self._map(function))
307+
308+
rpc_name = "__rpc_{}__".format(rpc_type.service)
309+
self.globals[rpc_name] = rpc_type
310+
self.functions[function] = rpc_name
311+
312+
return rpc_name
313+
314+
def _quote_function(self, function, loc):
217315
if function in self.functions:
218316
return self.functions[function]
219317

220-
# Insert the typed AST for the new function and restart inference.
221-
# It doesn't really matter where we insert as long as it is before
222-
# the final call.
223-
function_node = self._quote_embedded_function(function)
224-
self.typedtree.insert(0, function_node)
225-
self.inference_finished = False
226-
return function_node.name
318+
if hasattr(function, "artiq_embedded"):
319+
# Insert the typed AST for the new function and restart inference.
320+
# It doesn't really matter where we insert as long as it is before
321+
# the final call.
322+
function_node = self._quote_embedded_function(function)
323+
self.typedtree.insert(0, function_node)
324+
self.inference_finished = False
325+
return function_node.name
326+
else:
327+
# Insert a storage-less global whose type instructs the compiler
328+
# to perform an RPC instead of a regular call.
329+
return self._quote_rpc_function(function, loc)
227330

228331
def stitch_call(self, function, args, kwargs):
229332
function_node = self._quote_embedded_function(function)

Diff for: ‎artiq/compiler/module.py

+11-8
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,16 @@ def from_filename(cls, filename, engine=None):
4141

4242
class Module:
4343
def __init__(self, src):
44-
int_monomorphizer = transforms.IntMonomorphizer(engine=src.engine)
45-
inferencer = transforms.Inferencer(engine=src.engine)
46-
monomorphism_validator = validators.MonomorphismValidator(engine=src.engine)
47-
escape_validator = validators.EscapeValidator(engine=src.engine)
48-
artiq_ir_generator = transforms.ARTIQIRGenerator(engine=src.engine,
44+
self.engine = src.engine
45+
46+
int_monomorphizer = transforms.IntMonomorphizer(engine=self.engine)
47+
inferencer = transforms.Inferencer(engine=self.engine)
48+
monomorphism_validator = validators.MonomorphismValidator(engine=self.engine)
49+
escape_validator = validators.EscapeValidator(engine=self.engine)
50+
artiq_ir_generator = transforms.ARTIQIRGenerator(engine=self.engine,
4951
module_name=src.name)
50-
dead_code_eliminator = transforms.DeadCodeEliminator(engine=src.engine)
51-
local_access_validator = validators.LocalAccessValidator(engine=src.engine)
52+
dead_code_eliminator = transforms.DeadCodeEliminator(engine=self.engine)
53+
local_access_validator = validators.LocalAccessValidator(engine=self.engine)
5254

5355
self.name = src.name
5456
self.globals = src.globals
@@ -62,7 +64,8 @@ def __init__(self, src):
6264

6365
def build_llvm_ir(self, target):
6466
"""Compile the module to LLVM IR for the specified target."""
65-
llvm_ir_generator = transforms.LLVMIRGenerator(module_name=self.name, target=target)
67+
llvm_ir_generator = transforms.LLVMIRGenerator(engine=self.engine,
68+
module_name=self.name, target=target)
6669
return llvm_ir_generator.process(self.artiq_ir)
6770

6871
def entry_point(self):

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

+89-9
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
into LLVM intermediate representation.
44
"""
55

6-
from pythonparser import ast
6+
from pythonparser import ast, diagnostic
77
from llvmlite_artiq import ir as ll
88
from .. import types, builtins, ir
99

1010
class LLVMIRGenerator:
11-
def __init__(self, module_name, target):
11+
def __init__(self, engine, module_name, target):
12+
self.engine = engine
1213
self.target = target
1314
self.llcontext = target.llcontext
1415
self.llmodule = ll.Module(context=self.llcontext, name=module_name)
@@ -21,6 +22,11 @@ def llty_of_type(self, typ, bare=False, for_return=False):
2122
typ = typ.find()
2223
if types.is_tuple(typ):
2324
return ll.LiteralStructType([self.llty_of_type(eltty) for eltty in typ.elts])
25+
elif types.is_rpc_function(typ):
26+
if for_return:
27+
return ll.VoidType()
28+
else:
29+
return ll.LiteralStructType([])
2430
elif types.is_function(typ):
2531
envarg = ll.IntType(8).as_pointer()
2632
llty = ll.FunctionType(args=[envarg] +
@@ -89,10 +95,13 @@ def llconst_of_const(self, const):
8995
return ll.Constant(llty, False)
9096
elif isinstance(const.value, (int, float)):
9197
return ll.Constant(llty, const.value)
92-
elif isinstance(const.value, str):
93-
assert "\0" not in const.value
98+
elif isinstance(const.value, (str, bytes)):
99+
if isinstance(const.value, str):
100+
assert "\0" not in const.value
101+
as_bytes = (const.value + "\0").encode("utf-8")
102+
else:
103+
as_bytes = const.value
94104

95-
as_bytes = (const.value + "\0").encode("utf-8")
96105
if ir.is_exn_typeinfo(const.type):
97106
# Exception typeinfo; should be merged with identical others
98107
name = "__artiq_exn_" + const.value
@@ -144,6 +153,9 @@ def llbuiltin(self, name):
144153
llty = ll.FunctionType(ll.VoidType(), [self.llty_of_type(builtins.TException())])
145154
elif name == "__artiq_reraise":
146155
llty = ll.FunctionType(ll.VoidType(), [])
156+
elif name == "rpc":
157+
llty = ll.FunctionType(ll.IntType(32), [ll.IntType(32), ll.IntType(8).as_pointer()],
158+
var_arg=True)
147159
else:
148160
assert False
149161

@@ -546,11 +558,79 @@ def process_Closure(self, insn):
546558
name=insn.name)
547559
return llvalue
548560

561+
# See session.c:send_rpc_value.
562+
def _rpc_tag(self, typ, root_type, root_loc):
563+
if types.is_tuple(typ):
564+
assert len(typ.elts) < 256
565+
return b"t" + bytes([len(typ.elts)]) + \
566+
b"".join([self._rpc_tag(elt_type, root_type, root_loc)
567+
for elt_type in typ.elts])
568+
elif builtins.is_none(typ):
569+
return b"n"
570+
elif builtins.is_bool(typ):
571+
return b"b"
572+
elif builtins.is_int(typ, types.TValue(32)):
573+
return b"i"
574+
elif builtins.is_int(typ, types.TValue(64)):
575+
return b"I"
576+
elif builtins.is_float(typ):
577+
return b"f"
578+
elif builtins.is_str(typ):
579+
return b"s"
580+
elif builtins.is_list(typ):
581+
return b"l" + self._rpc_tag(builtins.get_iterable_elt(typ),
582+
root_type, root_loc)
583+
elif builtins.is_range(typ):
584+
return b"r" + self._rpc_tag(builtins.get_iterable_elt(typ),
585+
root_type, root_loc)
586+
elif ir.is_option(typ):
587+
return b"o" + self._rpc_tag(typ.params["inner"],
588+
root_type, root_loc)
589+
else:
590+
printer = types.TypePrinter()
591+
note = diagnostic.Diagnostic("note",
592+
"value of type {type}",
593+
{"type": printer.name(root_type)},
594+
root_loc)
595+
diag = diagnostic.Diagnostic("error",
596+
"type {type} is not supported in remote procedure calls",
597+
{"type": printer.name(typ)},
598+
root_loc)
599+
self.engine.process(diag)
600+
601+
def _build_rpc(self, service, args, return_type):
602+
llservice = ll.Constant(ll.IntType(32), service)
603+
604+
tag = b""
605+
for arg in args:
606+
if isinstance(arg, ir.Constant):
607+
# Constants don't have locations, but conveniently
608+
# they also never fail to serialize.
609+
tag += self._rpc_tag(arg.type, arg.type, None)
610+
else:
611+
tag += self._rpc_tag(arg.type, arg.type, arg.loc)
612+
tag += b":\x00"
613+
lltag = self.llconst_of_const(ir.Constant(tag, builtins.TStr()))
614+
615+
llargs = []
616+
for arg in args:
617+
llarg = self.map(arg)
618+
llargslot = self.llbuilder.alloca(llarg.type)
619+
self.llbuilder.store(llarg, llargslot)
620+
llargs.append(llargslot)
621+
622+
return self.llbuiltin("rpc"), [llservice, lltag] + llargs
623+
549624
def prepare_call(self, insn):
550-
llclosure, llargs = self.map(insn.target_function()), map(self.map, insn.arguments())
551-
llenv = self.llbuilder.extract_value(llclosure, 0)
552-
llfun = self.llbuilder.extract_value(llclosure, 1)
553-
return llfun, [llenv] + list(llargs)
625+
if types.is_rpc_function(insn.target_function().type):
626+
return self._build_rpc(insn.target_function().type.service,
627+
insn.arguments(),
628+
insn.target_function().type.ret)
629+
else:
630+
llclosure, llargs = self.map(insn.target_function()), map(self.map, insn.arguments())
631+
llenv = self.llbuilder.extract_value(llclosure, 0)
632+
llfun = self.llbuilder.extract_value(llclosure, 1)
633+
return llfun, [llenv] + list(llargs)
554634

555635
def process_Call(self, insn):
556636
llfun, llargs = self.prepare_call(insn)

Diff for: ‎artiq/compiler/types.py

+32-2
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,26 @@ def __eq__(self, other):
222222
def __ne__(self, other):
223223
return not (self == other)
224224

225+
class TRPCFunction(TFunction):
226+
"""
227+
A function type of a remote function.
228+
229+
:ivar service: (int) RPC service number
230+
"""
231+
232+
def __init__(self, args, optargs, ret, service):
233+
super().__init__(args, optargs, ret)
234+
self.service = service
235+
236+
def unify(self, other):
237+
if isinstance(other, TRPCFunction) and \
238+
self.service == other.service:
239+
super().unify(other)
240+
elif isinstance(other, TVar):
241+
other.unify(self)
242+
else:
243+
raise UnificationError(self, other)
244+
225245
class TBuiltin(Type):
226246
"""
227247
An instance of builtin type. Every instance of a builtin
@@ -310,6 +330,8 @@ def is_mono(typ, name=None, **params):
310330
typ = typ.find()
311331
params_match = True
312332
for param in params:
333+
if param not in typ.params:
334+
return False
313335
params_match = params_match and \
314336
typ.params[param].find() == params[param].find()
315337
return isinstance(typ, TMono) and \
@@ -329,6 +351,9 @@ def is_tuple(typ, elts=None):
329351
def is_function(typ):
330352
return isinstance(typ.find(), TFunction)
331353

354+
def is_rpc_function(typ):
355+
return isinstance(typ.find(), TRPCFunction)
356+
332357
def is_builtin(typ, name=None):
333358
typ = typ.find()
334359
if name is None:
@@ -381,11 +406,16 @@ def name(self, typ):
381406
return "(%s,)" % self.name(typ.elts[0])
382407
else:
383408
return "(%s)" % ", ".join(list(map(self.name, typ.elts)))
384-
elif isinstance(typ, TFunction):
409+
elif isinstance(typ, (TFunction, TRPCFunction)):
385410
args = []
386411
args += [ "%s:%s" % (arg, self.name(typ.args[arg])) for arg in typ.args]
387412
args += ["?%s:%s" % (arg, self.name(typ.optargs[arg])) for arg in typ.optargs]
388-
return "(%s)->%s" % (", ".join(args), self.name(typ.ret))
413+
signature = "(%s)->%s" % (", ".join(args), self.name(typ.ret))
414+
415+
if isinstance(typ, TRPCFunction):
416+
return "rpc({}) {}".format(typ.service, signature)
417+
elif isinstance(typ, TFunction):
418+
return signature
389419
elif isinstance(typ, TBuiltinFunction):
390420
return "<function %s>" % typ.name
391421
elif isinstance(typ, (TConstructor, TExceptionConstructor)):

Diff for: ‎artiq/coredevice/comm_generic.py

+27-14
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,16 @@ def run(self):
276276
self._write_empty(_H2DMsgType.RUN_KERNEL)
277277
logger.debug("running kernel")
278278

279-
def _receive_rpc_value(self, tag, rpc_map):
280-
if tag == "n":
279+
_rpc_sentinel = object()
280+
281+
def _receive_rpc_value(self, rpc_map):
282+
tag = chr(self._read_int8())
283+
if tag == "\x00":
284+
return self._rpc_sentinel
285+
elif tag == "t":
286+
length = self._read_int8()
287+
return tuple(self._receive_rpc_value(rpc_map) for _ in range(length))
288+
elif tag == "n":
281289
return None
282290
elif tag == "b":
283291
return bool(self._read_int8())
@@ -291,31 +299,36 @@ def _receive_rpc_value(self, tag, rpc_map):
291299
numerator = self._read_int64()
292300
denominator = self._read_int64()
293301
return Fraction(numerator, denominator)
302+
elif tag == "s":
303+
return self._read_string()
294304
elif tag == "l":
295-
elt_tag = chr(self._read_int8())
296305
length = self._read_int32()
297-
return [self._receive_rpc_value(elt_tag) for _ in range(length)]
306+
return [self._receive_rpc_value(rpc_map) for _ in range(length)]
307+
elif tag == "r":
308+
lower = self._receive_rpc_value(rpc_map)
309+
upper = self._receive_rpc_value(rpc_map)
310+
step = self._receive_rpc_value(rpc_map)
311+
return range(lower, upper, step)
298312
elif tag == "o":
299313
return rpc_map[self._read_int32()]
300314
else:
301-
raise IOError("Unknown RPC value tag: {}", tag)
315+
raise IOError("Unknown RPC value tag: {}".format(repr(tag)))
302316

303-
def _receive_rpc_values(self, rpc_map):
304-
result = []
317+
def _receive_rpc_args(self, rpc_map):
318+
args = []
305319
while True:
306-
tag = chr(self._read_int8())
307-
if tag == "\x00":
308-
return result
309-
else:
310-
result.append(self._receive_rpc_value(tag, rpc_map))
320+
value = self._receive_rpc_value(rpc_map)
321+
if value is self._rpc_sentinel:
322+
return args
323+
args.append(value)
311324

312325
def _serve_rpc(self, rpc_map):
313326
service = self._read_int32()
314-
args = self._receive_rpc_values(rpc_map)
327+
args = self._receive_rpc_args(rpc_map)
315328
logger.debug("rpc service: %d %r", service, args)
316329

317330
try:
318-
result = rpc_map[rpc_num](args)
331+
result = rpc_map[service](*args)
319332
if not isinstance(result, int) or not (-2**31 < result < 2**31-1):
320333
raise ValueError("An RPC must return an int(width=32)")
321334
except ARTIQException as exn:

Diff for: ‎artiq/coredevice/core.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ def compile(self, function, args, kwargs, with_attr_writeback=True):
5050
raise CompileError() from error
5151

5252
def run(self, function, args, kwargs):
53+
kernel_library, rpc_map = self.compile(function, args, kwargs)
54+
5355
if self.first_run:
5456
self.comm.check_ident()
5557
self.comm.switch_clock(self.external_clock)
5658
self.first_run = False
5759

58-
kernel_library, rpc_map = self.compile(function, args, kwargs)
59-
6060
try:
6161
self.comm.load(kernel_library)
6262
except Exception as error:

Diff for: ‎soc/runtime/ksupport.c

+18-17
Original file line numberDiff line numberDiff line change
@@ -301,33 +301,34 @@ void watchdog_clear(int id)
301301
mailbox_send_and_wait(&request);
302302
}
303303

304-
int rpc(int rpc_num, ...)
304+
int rpc(int service, const char *tag, ...)
305305
{
306-
struct msg_rpc_request request;
306+
struct msg_rpc_send_request request;
307307
struct msg_base *reply;
308308

309-
request.type = MESSAGE_TYPE_RPC_REQUEST;
310-
request.rpc_num = rpc_num;
311-
va_start(request.args, rpc_num);
309+
request.type = MESSAGE_TYPE_RPC_SEND_REQUEST;
310+
request.service = service;
311+
request.tag = tag;
312+
va_start(request.args, tag);
312313
mailbox_send_and_wait(&request);
313314
va_end(request.args);
314315

315316
reply = mailbox_wait_and_receive();
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) {
321-
struct artiq_exception exception;
322-
memcpy(&exception, ((struct msg_rpc_exception *)reply)->exception,
323-
sizeof(struct artiq_exception));
324-
mailbox_acknowledge();
325-
__artiq_raise(&exception);
326-
} else {
317+
// if(reply->type == MESSAGE_TYPE_RPC_REPLY) {
318+
// int result = ((struct msg_rpc_reply *)reply)->result;
319+
// mailbox_acknowledge();
320+
// return result;
321+
// } else if(reply->type == MESSAGE_TYPE_RPC_EXCEPTION) {
322+
// struct artiq_exception exception;
323+
// memcpy(&exception, ((struct msg_rpc_exception *)reply)->exception,
324+
// sizeof(struct artiq_exception));
325+
// mailbox_acknowledge();
326+
// __artiq_raise(&exception);
327+
// } else {
327328
log("Malformed MESSAGE_TYPE_RPC_REQUEST reply type %d",
328329
reply->type);
329330
while(1);
330-
}
331+
// }
331332
}
332333

333334
void lognonl(const char *fmt, ...)

Diff for: ‎soc/runtime/ksupport.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ long long int now_init(void);
55
void now_save(long long int now);
66
int watchdog_set(int ms);
77
void watchdog_clear(int id);
8-
int rpc(int service, ...);
8+
int rpc(int service, const char *tag, ...);
99
void lognonl(const char *fmt, ...);
1010
void log(const char *fmt, ...);
1111

Diff for: ‎soc/runtime/messages.h

+13-6
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ enum {
1414
MESSAGE_TYPE_WATCHDOG_SET_REQUEST,
1515
MESSAGE_TYPE_WATCHDOG_SET_REPLY,
1616
MESSAGE_TYPE_WATCHDOG_CLEAR,
17-
MESSAGE_TYPE_RPC_REQUEST,
18-
MESSAGE_TYPE_RPC_REPLY,
17+
MESSAGE_TYPE_RPC_SEND_REQUEST,
18+
MESSAGE_TYPE_RPC_RECV_REQUEST,
19+
MESSAGE_TYPE_RPC_RECV_REPLY,
1920
MESSAGE_TYPE_RPC_EXCEPTION,
2021
MESSAGE_TYPE_LOG,
2122

@@ -80,15 +81,21 @@ struct msg_watchdog_clear {
8081
int id;
8182
};
8283

83-
struct msg_rpc_request {
84+
struct msg_rpc_send_request {
8485
int type;
85-
int rpc_num;
86+
int service;
87+
const char *tag;
8688
va_list args;
8789
};
8890

89-
struct msg_rpc_reply {
91+
struct msg_rpc_recv_request {
9092
int type;
91-
int result;
93+
// TODO ???
94+
};
95+
96+
struct msg_rpc_recv_reply {
97+
int type;
98+
// TODO ???
9299
};
93100

94101
struct msg_rpc_exception {

Diff for: ‎soc/runtime/session.c

+123-58
Original file line numberDiff line numberDiff line change
@@ -457,23 +457,23 @@ static int process_input(void)
457457
user_kernel_state = USER_KERNEL_RUNNING;
458458
break;
459459

460-
case REMOTEMSG_TYPE_RPC_REPLY: {
461-
struct msg_rpc_reply reply;
460+
// case REMOTEMSG_TYPE_RPC_REPLY: {
461+
// struct msg_rpc_reply reply;
462462

463-
int result = in_packet_int32();
463+
// int result = in_packet_int32();
464464

465-
if(user_kernel_state != USER_KERNEL_WAIT_RPC) {
466-
log("Unsolicited RPC reply");
467-
return 0; // restart session
468-
}
465+
// if(user_kernel_state != USER_KERNEL_WAIT_RPC) {
466+
// log("Unsolicited RPC reply");
467+
// return 0; // restart session
468+
// }
469469

470-
reply.type = MESSAGE_TYPE_RPC_REPLY;
471-
reply.result = result;
472-
mailbox_send_and_wait(&reply);
470+
// reply.type = MESSAGE_TYPE_RPC_REPLY;
471+
// reply.result = result;
472+
// mailbox_send_and_wait(&reply);
473473

474-
user_kernel_state = USER_KERNEL_RUNNING;
475-
break;
476-
}
474+
// user_kernel_state = USER_KERNEL_RUNNING;
475+
// break;
476+
// }
477477

478478
case REMOTEMSG_TYPE_RPC_EXCEPTION: {
479479
struct msg_rpc_exception reply;
@@ -509,91 +509,156 @@ static int process_input(void)
509509
return 1;
510510
}
511511

512-
static int send_rpc_value(const char **tag, void *value)
512+
// See llvm_ir_generator.py:_rpc_tag.
513+
static int send_rpc_value(const char **tag, void **value)
513514
{
514515
if(!out_packet_int8(**tag))
515-
return -1;
516+
return 0;
517+
518+
switch(*(*tag)++) {
519+
case 't': { // tuple
520+
int size = *(*tag)++;
521+
if(!out_packet_int8(size))
522+
return 0;
523+
524+
for(int i = 0; i < size; i++) {
525+
if(!send_rpc_value(tag, value))
526+
return 0;
527+
}
528+
break;
529+
}
516530

517-
int size = 0;
518-
switch(**tag) {
519-
case 0: // last tag
520531
case 'n': // None
521532
break;
522533

523-
case 'b': // bool
524-
size = 1;
525-
if(!out_packet_chunk(value, size))
526-
return -1;
534+
case 'b': { // bool
535+
int size = sizeof(int8_t);
536+
if(!out_packet_chunk(*value, size))
537+
return 0;
538+
*value = (void*)((intptr_t)(*value) + size);
527539
break;
540+
}
528541

529-
case 'i': // int(width=32)
530-
size = 4;
531-
if(!out_packet_chunk(value, size))
532-
return -1;
542+
case 'i': { // int(width=32)
543+
int size = sizeof(int32_t);
544+
if(!out_packet_chunk(*value, size))
545+
return 0;
546+
*value = (void*)((intptr_t)(*value) + size);
533547
break;
548+
}
534549

535-
case 'I': // int(width=64)
536-
case 'f': // float
537-
size = 8;
538-
if(!out_packet_chunk(value, size))
539-
return -1;
550+
case 'I': { // int(width=64)
551+
int size = sizeof(int64_t);
552+
if(!out_packet_chunk(*value, size))
553+
return 0;
554+
*value = (void*)((intptr_t)(*value) + size);
540555
break;
556+
}
541557

542-
case 'F': // Fraction
543-
size = 16;
544-
if(!out_packet_chunk(value, size))
545-
return -1;
558+
case 'f': { // float
559+
int size = sizeof(double);
560+
if(!out_packet_chunk(*value, size))
561+
return 0;
562+
*value = (void*)((intptr_t)(*value) + size);
546563
break;
564+
}
565+
566+
case 'F': { // Fraction
567+
int size = sizeof(int64_t) * 2;
568+
if(!out_packet_chunk(*value, size))
569+
return 0;
570+
*value = (void*)((intptr_t)(*value) + size);
571+
break;
572+
}
573+
574+
case 's': { // string
575+
const char **string = *value;
576+
if(!out_packet_string(*string))
577+
return 0;
578+
*value = (void*)((intptr_t)(*value) + strlen(*string) + 1);
579+
break;
580+
}
547581

548582
case 'l': { // list(elt='a)
549-
struct { uint32_t length; void *elements; } *list = value;
583+
struct { uint32_t length; struct {} *elements; } *list = *value;
550584
void *element = list->elements;
551585

552-
const char *tag_copy = *tag + 1;
586+
if(!out_packet_int32(list->length))
587+
return 0;
588+
589+
const char *tag_copy;
553590
for(int i = 0; i < list->length; i++) {
554-
int element_size = send_rpc_value(&tag_copy, element);
555-
if(element_size < 0)
556-
return -1;
557-
element = (void*)((intptr_t)element + element_size);
591+
tag_copy = *tag;
592+
if(!send_rpc_value(&tag_copy, &element))
593+
return 0;
558594
}
559595
*tag = tag_copy;
560596

561-
size = sizeof(list);
597+
*value = (void*)((intptr_t)(*value) + sizeof(*list));
562598
break;
563599
}
564600

565-
case 'o': { // host object
566-
struct { uint32_t id; } *object = value;
601+
case 'r': { // range(elt='a)
602+
const char *tag_copy;
603+
tag_copy = *tag;
604+
if(!send_rpc_value(&tag_copy, value)) // min
605+
return 0;
606+
tag_copy = *tag;
607+
if(!send_rpc_value(&tag_copy, value)) // max
608+
return 0;
609+
tag_copy = *tag;
610+
if(!send_rpc_value(&tag_copy, value)) // step
611+
return 0;
612+
*tag = tag_copy;
613+
break;
614+
}
567615

568-
if(!out_packet_int32(object->id))
569-
return -1;
616+
case 'o': { // option(inner='a)
617+
struct { int8_t present; struct {} contents; } *option = *value;
618+
void *contents = &option->contents;
570619

571-
size = sizeof(object);
572-
break;
620+
if(!out_packet_int8(option->present))
621+
return 0;
622+
623+
// option never appears in composite types, so we don't have
624+
// to accurately advance *value.
625+
if(option->present) {
626+
return send_rpc_value(tag, &contents);
627+
} else {
628+
(*tag)++;
629+
break;
630+
}
631+
}
632+
633+
case 'O': { // host object
634+
struct { uint32_t id; } **object = *value;
635+
636+
if(!out_packet_int32((*object)->id))
637+
return 0;
573638
}
574639

575640
default:
576-
return -1;
641+
log("send_rpc_value: unknown tag %02x", *((*tag) - 1));
642+
return 0;
577643
}
578644

579-
(*tag)++;
580-
return size;
645+
return 1;
581646
}
582647

583-
static int send_rpc_request(int service, va_list args)
648+
static int send_rpc_request(int service, const char *tag, va_list args)
584649
{
585650
out_packet_start(REMOTEMSG_TYPE_RPC_REQUEST);
586651
out_packet_int32(service);
587652

588-
const char *tag = va_arg(args, const char*);
589-
while(*tag) {
653+
while(*tag != ':') {
590654
void *value = va_arg(args, void*);
591655
if(!kloader_validate_kpointer(value))
592656
return 0;
593-
if(send_rpc_value(&tag, &value) < 0)
657+
if(!send_rpc_value(&tag, &value))
594658
return 0;
595659
}
596660

661+
out_packet_int8(0);
597662
out_packet_finish();
598663
return 1;
599664
}
@@ -670,10 +735,10 @@ static int process_kmsg(struct msg_base *umsg)
670735
break;
671736
}
672737

673-
case MESSAGE_TYPE_RPC_REQUEST: {
674-
struct msg_rpc_request *msg = (struct msg_rpc_request *)umsg;
738+
case MESSAGE_TYPE_RPC_SEND_REQUEST: {
739+
struct msg_rpc_send_request *msg = (struct msg_rpc_send_request *)umsg;
675740

676-
if(!send_rpc_request(msg->rpc_num, msg->args)) {
741+
if(!send_rpc_request(msg->service, msg->tag, msg->args)) {
677742
log("Failed to send RPC request");
678743
return 0; // restart session
679744
}

0 commit comments

Comments
 (0)
Please sign in to comment.