tock / libtock-rs

Rust userland library for Tock

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Split `libtock_unittest::fake::Kernel` into multiple pieces.

jrvanwhy opened this issue · comments

libtock_unittest::fake::Kernel serves at least 3 roles:

  1. It is stored in thread-local storage and contains the data used by the fake kernel.
  2. It is the handle used by unit tests to control the fake kernel's lifetime (well, Rc<fake::Kernel> is) and to interact with the kernel directly (e.g. add drivers or examine the syscall log)
  3. It implements libtock_platform::Syscalls.

This results in some awkward code. yield_wait can invoke an upcall that calls command, which means the implementation of libtock_platform::Syscalls has to be reentrant. That reentrance is easier to comprehend when you think of fake::Kernel as a data-only type, but the API it exposes to unit tests is an object-oriented API.

The reentrance gets more awkward when you add upcalls:

  1. A system call is invoked
  2. The system call routes the call to the corresponding fake::Driver (using the thread-local fake::Kernel instance).
  3. The fake::Driver queues an Upcall.
  4. The Upcall instance fetches the thread-local fake::Kernel to add itself to the upcall queue.

Instead, I think fake::Kernel should be split into 3 pieces:

  1. kernel::Data is the data stored in thread-local storage. It is stored inside a RefCell, and borrowed by fake::Kernel, fake::Syscalls, and Upcall only as long as necessary to handle an operation. It is not visible to code outside libtock_unittest.
  2. fake::Kernel is the handle used by the unit test to access the kernel. It would be a zero-sized type, and would manipulate the thread-local kernel::Data.
  3. fake::Syscalls implements libtock_platform::Syscalls.

I'm not performing this refactoring yet because I don't want to slow down my feature development. Instead, I'm opening this issue to remind myself to perform this refactoring later.