Skip to content

stdio: a layered / multiheaded approach to I/O #13469

Closed
@miri64

Description

Description

We need to rethink our STDIO model! With new methods for STDIO emerging (stdio_cdc_acm, stdio_nimble, ...) and usage of modules that multiplex STDIOs with other functionality (e.g. ethos or slipdev to multiplex network connections via serial) getting more and more complicated to configure, while only being able to just talk to one specific lower-end implementation of STDIO (stdio_uart in ethos's case) this becomes clearer and clearer. After some brainstorming with @haukepetersen and @kaspar030 I decided to write down our initial ideas to be build upon and maybe to find someone™ to implement it in the end.

Problems with the current model

The current model maps STDIO system calls to the functions stdio_read() and stdio_write(), these can be implemented by a stdio_* module to provide the desired functionality. The problem is that this only allows for exactly one STDIO implementation at a time. This leads to problems if this use case isn't given anymore.

Use cases

There are several use cases that call for a new model.

  1. Mapping a more advanced STDIO on top of a more basic STDIO: e.g. multiplexing STDIO with other functionality such as in ethos.
  2. Having multiple STDIO interfaces: e.g. stdio_cdc_acm as main interface for user interaction but also providing stdio_uart for debugging (in case stdio_cdc_acm is unable to be initialized).
  3. Having no STDIO: This is currently modeled as a module with empty operations called stdio_null. However, maybe we find a way to not necessitate it at all.

Model proposal

My initial gut / keep-it-simple feeling would call for a driver-based approach. That means that a new STDIO implementation would provide a struct with function pointers similar as we did it elsewhere (e.g. in netdev).

typedef struct {
    ssize_t (*read)(void *buffer, size_t max_len);
    ssize_t (*write)(const void *buffer, size_t len);
} stdio_t;

Additionally a module dependent init-function is provided.
A top-level implementation (under the current model that would be the equivalent to stdio_read()/stdio_write()) would then call a stdio_t object that is provided via configuration.

static const stdio_t *_stdio;

void stdio_init(const stdio_t *stdio)
{
    _stdio = stdio;
}

ssize_t stdio_read(void *buffer, size_t max_len)
{
     return _stdio->read(buffer, max_len)
}

ssize_t stdio_write(const void *buffer, size_t len)
{
     return _stdio->write(buffer, max_len)
}

This should IMHO cover at least use case 1 and 2 (please understand the code snippets more as pseudo-code than actual implementation ideas, I don't think it is as easy as I make it seem here):

  1. Initialize the more advanced STDIO with the more basic STDIO and use the advanced STDIO in the top-level implementation, e.g.
    const stdio_t *stdio = stdio_uart_init(uart_config, baudrate);
    stdio = ethos_init(stdio, ...);
    stdio_init(stdio);
  2. Provide a multiplexer STDIO to call multiple other STDIOs
    const stdio_t *stdios[] = {
        uart,
        cdc_acm,
        NULL,
    }
    const stdio_t *stdio = stdio_multiplex_init(stdios);
    stdio_init(stdio);

Use case 3 still would be a NOP module, but we could use some compile-time config to make at least stdio_read() and stdio_write() also NOPs in case no other STDIO module is present.

For the more graphically minded people here is a somewhat thrown together UML diagram of what I am thinking of (showing both the cases shown in 1. and 2. as a model)

Untitled Diagram

More considerations

Useful links

Related issues, PRs, and discussions:

Metadata

Labels

Area: sysArea: SystemCommunity: help wantedThe contributors require help from other members of the communityDiscussion: RFCThe issue/PR is used as a discussion starting point about the item of the issue/PRType: enhancementThe issue suggests enhanceable parts / The PR enhances parts of the codebase / documentationType: new featureThe issue requests / The PR implemements a new feature for RIOT

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions