Hi Jerome,

On 27.02.25 18:05, Jerome Forissier wrote:
Hi Stefan,

On 2/27/25 13:30, Stefan Roese wrote:
Hi Jerome,

On 25.02.25 17:34, Jerome Forissier wrote:
Make the schedule() call from the CYCLIC framework a uthread scheduling
point too. This makes sense since schedule() is called from a lot of
places where uthread_schedule() needs to be called.

Signed-off-by: Jerome Forissier <jerome.foriss...@linaro.org>

Frankly, at first I was wondering a bit, if and why another framework
for "multitasking" is needed in U-Boot, additionally to the cyclic
framework that I introduced a few years ago. Which was greatly enhanced
by Rasmus over the time. But looking at your "uthread" implementation
it makes sense to add such a probably more intuitive interface as well.

cyclic is clean and simple and certainly well suited when introducing new
code. But when reworking older code I find it somewhat difficult to use
due to the need to keep a context and pass it everywhere. This can lead
to lots of changes when call stacks are deep.

In general I'm really happy seeing activity in this "multitaking" area
in U-Boot. As it brings a lot of new possibilities and, as you've also
shown in your patchset, may greatly help reducing boot time in the
USB example. :)

Thank you.
One question though:
Do you have some means in your uthread framework, measuring and
perhaps limiting the time spent in these uthreads? If and how is a
preemption of a uthread possible? So that it does not consume too
much time resulting in e.g. things like dropping input chars on
the prompt? Sorry, I did not thoroughly go through all your code
to get the internals from there. It would be great if you could
elaborate a bit on this.

That's a very valid point. The short answer is no, there is no control
over how long a thread keeps the CPU busy. uthread is similar to cyclic
in that respect. That said, I occasionally noted the issue you mentioned
about the console dropping characters, and yes it is annoying. I believe
there is a simple solution though. If we can somehow make sure we're
always scheduling the main thread every other time, we're much less
likely to starve it from the CPU, especially when many threads are
active. That is, assume we have 2 threads in addition to the main thread.
The thread list is main -> thread1 -> thread2 and uthread_schedule() will
iterate in that order. So back to main only after thread1 *and* thread2
have run and called uthread_schedule(). The idea is to schedule in a
different order: main -> thread1 -> main -> thread2 -> main etc.,
effectively giving a higher priority to the main thread (which would be
the console parsing thread).

Sounds like a good idea / improvement to me.

Thanks,
Stefan

I feel that introducing preemption would be opening a can of worms...
Because in this case we would likely need locking everywhere. Without
preemption, we still do need locking in theory, it's just that I have
not yet identified critical sections where locks would be mandatory in
the code that I have "parallelized". BTW I believe a uthread lock would
be trivial to implement like so:

struct uthread_lock {
        bool locked;
};

void uthread_lock(struct uthread_lock *l)
{
        while (l->locked)
                uthread_schedule();
        l->locked = true;
}
void uthread_unlock(struct uthread_lock *l)
{
        l->locked = false;
}


For this patch:

Reviewed-by: Stefan Roese <s...@denx.de>

Thanks,
Stefan

Thanks,

Reply via email to