libtock-c icon indicating copy to clipboard operation
libtock-c copied to clipboard

Deprecate `yield_for()`

Open bradjc opened this issue 8 months ago • 1 comments

The yield_for(&bool) function provides synchronous-like functionality, but crucially allows any upcall to run while checking for the bool to be true. This design requires programmers to have a reasonably strong understanding of upcall, yield, and yield_for semantics to use correctly. Notably, calling yield_for() within a callback often leads to very unintuitive results, as the callback can run again before yield_for() returns. This typically crashes the app with a stack overflow.

With Yield-WaitFor support in the kernel, the yield_wait_for() function provides true synchronous functionality. That is, no upcalls will fire before yield_wait_for() returns. This diminishes the need for having yield_for(bool).

We should deprecate yield_for(&bool) to discourage its use (and the associated pitfalls).

Case for retaining yield_for(&bool)

There is nothing specifically invalid about using yield_for(&bool), it just is a little odd to want to have synchronous-looking code while also enabling other async operations (as in not using YWF).

However, there may be cases where yield_for(&bool) is still appropriate. For example, an interactive screen app needs to update the screen, but only when a button is pressed by the user which controls the screen. However, in the meantime other events can fire in the system. E.g.:


void motion_detection_callback() {
  // handle this event
}

void button_callback() {action = true;}

void main() {
  while (1) {
    screen_draw();

    // wait for button press
    action = false;
    yield_for(&action);
  }
}

bradjc avatar Jul 10 '25 16:07 bradjc

Given that the implementation of yield_for() is so simple, maybe the correct answer for apps like this interactive screen app is to implement it manually. In that way, the true behavior is more clear.

Implementation of yield_for():

void yield_for(bool* cond) {
  while (!*cond) {
    yield();
  }
}

Proposed more verbose application:

void motion_detection_callback() {
  // handle this event
}

void button_callback() {action = true;}

void main() {
  while (1) {
    screen_draw();

    // wait for button press
    action = false;
    while (!action) {
      yield(); // clear that this yield enables any upcalls to occur, not just the one waited for
    }
  }
}

brghena avatar Jul 10 '25 16:07 brghena