Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend IRunnable::run with a deadline #364

Closed
pavel-kirienko opened this issue Jun 24, 2024 · 9 comments
Closed

Extend IRunnable::run with a deadline #364

pavel-kirienko opened this issue Jun 24, 2024 · 9 comments
Assignees
Labels
class-requirement Issue that can be traced back to a design requiement domain-production Pertains to the shippable code rather than any scaffolding priority-high

Comments

@pavel-kirienko
Copy link
Member

See #363 (comment)

This should be a deadline rather than a timeout. The clock used for the deadline tracking is described in https://github.com/OpenCyphal-Garage/libcyphal/blob/main/docs/design/readme.md#time-primitives

@pavel-kirienko pavel-kirienko self-assigned this Jun 24, 2024
@pavel-kirienko pavel-kirienko added domain-production Pertains to the shippable code rather than any scaffolding priority-high class-requirement Issue that can be traced back to a design requiement labels Jun 24, 2024
@serges147
Copy link
Collaborator

What if introduce ICancellable (or IInterruptable TBD) with bool isCancelled() method, pass this interface (optionally?) to whatever run as MaybeError run(const TimePoint now, ICancellable* cancellation_token), and whatever loop we have in libcyphal currently is supposed to periodically check (on each iteration, or maybe even in between of some breakable sub-tasks of a single iteration, or even pass it to a nested internal runXxx methods in necessary) ? User implementation of such ICancellable might implement whatever logic she wants, f.e. keep track of currently allowed time slot, and when it's gone start returning true - and whole run should quickly unwind. With this approach we don't need to bring the clock entity into lybcyphal, and so don't need compare time by ourselves. Also, it allows user to interrupt a run safely and early by maybe some other than time condition...

@pavel-kirienko
Copy link
Member Author

Makes sense. But are we sure we need an interface for this instead of a simple cetl::function<bool() noexcept, 4*sizeof(void)>?

@serges147
Copy link
Collaborator

IMHO both will work, I just think that interface pointer might be more light way... In both cases we still need to first check for "emptiness" (either != nullptr or bool operator of function) before calling isCancelled, like:

while (/*some currently existing loop condition*/)
{
    if ((cancellation_token != nullptr) && cancellation_token->isCancelled())
    {
        return cetl::nullopt; // or `break;` if it suits better for some cases
    }
    ...
    runXxx(cancellation_token); // b/c might have nested "loop" inside
    ...
}

UNLESS!!! We will require non-empty token (either by passing ICancellable&, or require function to be pre-assigned with some functor like dummy []() { return false; }). Then the above code will be a bit simpler and with less branches to cover.

@pavel-kirienko What benefits do you think will be in using function here? Thnx

@pavel-kirienko
Copy link
Member Author

What benefits do you think will be in using function here?

706ec3ca-8360-4354-8aa9-2a337006f98a_text

@thirtytwobits
Copy link
Contributor

A cancellable assumes multiple threads of execution. We should avoid requiring this.

@serges147
Copy link
Collaborator

serges147 commented Jun 26, 2024

A cancellable assumes multiple threads of execution.

This is not what I meant. Here is an example of possible user-provided implementation of ICancellable:

bool TimeslotCancellable::isCancelled()
{
    return ::user_system_clock() > deadline_;
}

And somewhere else user calls our run like this in her super-loop:

TimeslotCancellable timeslot;
while (true)
{
    const TimePoint now = ::user_system_clock();
    timeslot.setDeadline(now + 20ms);
    
    auto maybe_error = libcyphal.run(now, &timeslot);

    // do some other user-specific stuff
    ...
} 

OR like this if we go with function:

...
    const TimePoint deadline = user_system_clock() + 20ms;
    auto maybe_error = libcyphal.run(now, [deadline]() { return ::user_system_clock() > deadline; });
...

@pavel-kirienko
Copy link
Member Author

@thirtytwobits Are you saying we need a different name?

@thirtytwobits
Copy link
Contributor

@thirtytwobits Are you saying we need a different name?

nope. I like what Serge is proposing.

@serges147
Copy link
Collaborator

@pavel-kirienko I believe this issue is not applicable anymore.

@pavel-kirienko pavel-kirienko closed this as not planned Won't fix, can't repro, duplicate, stale Aug 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
class-requirement Issue that can be traced back to a design requiement domain-production Pertains to the shippable code rather than any scaffolding priority-high
Projects
None yet
Development

No branches or pull requests

3 participants