Skip to content

Partial async runtime support #182

@stevefan1999-personal

Description

@stevefan1999-personal

Ok, this is quite a hard one. Now, there's barely any memory protection in EFI (there some fundamental alloc functions for you to write a page allocator IIRC, as seen in the allocator written in this repo) and so everything by default is not "thread-safe".

But worse, we all know that EFI is pretty much running on bare-metal so there's no multi-threading either.

This means we cannot have the true async experience like we do with tokio/async-std that features work stealing from multiple threads. We are set to have the libuv/Node experience where we have one core, multiple promises, aka cooperative scheduling without preemption.

If we are fortunate enough and we have hardware interrupts/polling mechanism, then we can still have some degree of asynchronicity. This is a well-documented practice done by various hardware engineers using Rust on ARM/RISC-V who exploits such features. There's no way we can't do it in EFI.

But the sad reality is, this is not really supported by EFI either, due to EFI being able to target multiple platforms. but I do found some gems on the boot service table:
https://github.com/tianocore/edk2/blob/f1567720b13a578ffa54716119f826df622babcd/MdePkg/Include/Uefi/UefiSpec.h#L1896-L1901

I suppose this is a primitive FCFS event system, i.e. without scheduling, but at least we are saved from the hassle of writing from scratch ourselves.

My idea is shown as follows:

  1. Call CreateEvent for each Future allocation; on debug mode, tag future and the event primitives to each other for better debugging. (not necessary on release mode, keeping either one is okay)
  2. We store the pointer to the Future in each context.
  3. Call CheckEvent on each poll
  4. We do not call WaitForEvent for each await call. Instead we let Rust to handle the polling pending and resend it to the event queue since that's supposed to be the way Rust is.
  5. When Future completes/fails we can call SignalEvent.
  6. After the future has been consumed/droppable, free the underlying event primitives by CloseEvent.

This is a very good reference point to write an executor.

Keep in mind that this is only available during boot service, there's no equivalent in runtime service.

Also according to here the EFI_EVENT is an opaque structure, this mean we might not have a consistent behavior on different platforms. Intensive testing should be needed.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions