doc/wg/core/notes/core-notes-2022-02-18.md
Attendees:
const_fn one). We remove the one use of
option_result_contains, so that's one feature we've removed. The major
limiting thing is const mut refs, which we might have to dig into a bit
more. Some progress, things are looking good from the Rust point of view.libtock-rs API designlibtock-rs
interacting with kernel drivers -- should their APIs generally look like?".libtock-rs and faced a
dilemma on how to write them. I tried to get inspiration from libtock-rs 1
but they can't be done exactly the same. There's no async in libtock-rs
2. Basically, I could see two ways of doing this. Either write drivers as
super low level, mimicking what the capsule does. The second is to write
higher-level drivers which would be meaningful, and the best example is the
GPIO driver. We could either go with functions like set_pin, clear_pin,
set_input, read_input, or we could have a higher-level driver which
exports structures like Pin, InputPin, OutputPin. Or we could have a
mixture of the two -- low level drivers which mimic the capsules and build on
top of them optional libraries that use memory allocation and stuff that
requires more memory.set
which gets the pin number and clear which gets the pin number. For
interrupts, we register a single callback. Whenever there's an interrupt for
the pin, the same callback would be called always. The callback would have a
parameter for the number of the pin and the state of the pin. The
higher-level API would be to have a structure called Pin, from which we can
get an InputPin and an OutputPin. You can't read from an OutputPin as
the function would not be there. Whenever we want to set a callback, you
would set the callback on the pin, like pin.on_interrupt(callback). That
would mean the high-level driver would need to register one single callback,
have a dynamically-allocated array of pins -- we don't know at compilation
time how many pins we have -- and send the event to those pins. It would
probably require memory allocation -- I'd be happy to talk about how to avoid
that -- and probably more memory. Some applications would need that, some
would not. If this is one single driver, then you can't opt out. If you split
them into two, the users would have a choice not to include this upper level.
The GPIO driver is written in a strange way right now -- it has some basic
functionlity (global callback) and some structures for pins. I don't like it
very much.libtock-rs to be and what should be done elsewhere".
A reasonable model to me is how Rust divides the core library and the std
library. The core library contains the stuff -- it's not exactly 1:1
because the core library doesn't contain system calls -- but nonetheless,
the core library contains the stuff that any Rust application needs.
Similarly, maybe libtock-rs should contain the bare-bones glue that
effectively should apply to any Rust application for Tock. The std library
for Rust contains not only mapping to drivers, but layers of abstraction like
the sockets API, which is higher level than the C socket API, some
portability, etc, at the expense of not being appropriate for all
applications. It's reasonable to have multiple standard libraries, like the
async ecosystem has a few alternative standard libraries. Maybe we don't
have to go as far as having a separate crate for each high-level driver.
Maybe it's reasonable to have a libtock-rs-std -- maybe let's not call it
that -- that is one point in the design space for how a Rust application
would be written against a common set of high-level drivers. In fact, maybe
that should focus on relative ease of use and good abstractions for common
applications + prototyping, and doesn't need to be concerned about absolutely
minimizing footprint or performance or whatever. Critical applications, like
OpenTitan, might not use it, but many of us would use it for applications
that are less sensitive.libtock-rs
used by all applications, and a separate part where some of these APIs
belong. We already have a division there, where libtock_platform contains
stuff used by all libtock-rs applications, and GPIO and LEDs are in their
own crates. We already have a division there, but maybe the lines aren't
drawn in the right place. Like libtock_platform is suitable for all users
and these APIs could just all be high-level APIs, and anyone who needs a
low-level API could write their own.libtock-rs might have a different bar than a library that is focused on
providing usable abstractions. The same way that the bar for merging stuff
into the kernel is different than for merging stuff into userspace.Pins add some code size. I'm not sure if it's significant, but it does add
some code size.1. The simplest way you could
do it is Gpio::set(pin_number). If the pin is valid and it was previously
set to output, it would work, otherwise it would fail. If it is an input pin,
it's now allowed to be called like that. The way it is implemented now, you
have Gpio::get_pin(pin_number), which returns a Pin structure that has no
useful methods, except for make_input and make_output. make_output will
give you back an Output structure, on which you can set and clear.make_output but I have another process that
shares that PIN, I could make the argument that now the API also needs to
check whether the pin is still an output since I've created it. I think that
exposing these lower-level methods could be a good common ground to build
upon, where everyone can agree on a flat and clean API surface, and then
develop it in these different directions with regards to how much
functionality the high-level APIs actually cover. There's much more space for
exploration there.get_pin twice. There's no way to stop that
without using allocation. At least I couldn't find a way, probably somebody
more experienced than me might find a way. The problem gets trickier once you
have two apps using the same pin. In one app you set it to an output and
start using it, and the other app might set it as an input and the first app
wouldn't know about that. Unless the GPIO driver allocates pins to the apps,
and then we'd need to modify the GPIO driver in the kernel.libtock-rs, or the stuff that Alex is proposing?unsafe to do so, does it not?command is a perfectly-safe API.libc in Unix is offered as the
recommended way to interact with the kernel through a set of abstractions,
and sometimes people choose to go around that. Like the Go runtime doesn't
link against libc and interacts directly with system calls. Now again, the
division might be a little bit different, but to me it sounds reasonable to
say "the recommended way is to use this crate with safe abstractions, but
applications that are more constrained are free to use the core libtock-rs
interface with little abstraction".RawSyscalls.libtock-rs' public API surface, there is no ambiguity.raw and make it clear
that these are the unchecked interfaces, and have functions that are really
thin wrappers over the syscalls, so you don't have to do a ton of research to
figure out how to do a raw output on a pin.libtock-rs are basically free.unsafe, I would be really interested
to talk about it.libtock-rs, but I honestly didn't want to
review the high-level APIs also.libtock-rs and push there.apis/?libtock-rs work.libtock-c, where part of
the alarms are set in userspace. The driver only accepts one alarm per
process, and in libtock-c you can have several. Or simply go with a simple
raw interface as Alyssa said. I'm not really sure how to continue and I'm not
really sure if I should change the GPIO driver.libtock-rs' primary goal should not be to do that, that we should have an
advocated-for but optional separate library for exposing a porcelain API that
prioritizes convenience and ease of development over performance or memory
efficiency. Obviously there's a tradeoff and we need to find a reasonable
design point, but yes. For alarms, I think it should be similar to
libtock-c -- it makes sense for apps to have multiple alarms, and managing
that on your own is tricky, and that logic shouldn't be in libtock-rs. I
think it should be in at least a separate crate or separate repository that
takes much more freedom than libtock-rs should about implementing
heavyweight abstractions.libtock-rs or does it belong in that crate? That has much more tie-in with
the runtime than it is optional in libtock-rs. I'm not sure if a separate
repository is right, a separate crate seems good thought.libtock-rs doesn't implement
something that makes sense, we'll implement our own, and I'd rather not
duplicate that work.Box can be replaced by a static
reference.core and std libraries do, and the division
seems very natural to me.libtock-rs? Are the APIs library, or how do you see these being
organized?libtock_platform.apis/leds crate and maybe there
should be a apis/leds::raw module.apis/leds raw.libtock_platform or
something.