Page 1 of 1

OS_Yield new features (OS_Refresh)

PostPosted: Sun Dec 09, 2001 1:10 am
by aek
Hi Luben.

The situation you describe is essentially the same one that one might face with a priority inversion problem -- the low-priority tasks have no chance at running because the higher-priority tasks are hogging the processor.

There are a variety of ways to solve this, none of which are very simple. The general approach seems to be to "watch" the low-priority tasks and slowly elevate them in priority until they have a chance to run (once), at which point they revert to their older priority.

Note that you could implement something like this within Salvo currently, where you could assign the highest priority to a task that watched other tasks, say, every 10 system ticks, and slowly raised their priorities until they actually ran. I suppose it's a bit more complicated than that, but that's the general idea ...

Or you could drive such a "social justice monitor" from a periodic interrupt, etc. :-)


Re: OS_Yield new features (OS_Refresh)

PostPosted: Sun Dec 09, 2001 8:12 am
by luben

That's true - high priority tasks have more possibilities to run then lower once.
But I'm talking about one very often used case - high priority tasks finished their job, so they try to bring some "compassion" to low priority tasks. This could not be done with OS_Yield(). I don't know how to explain you - it's a case of "social injustice". Some tasks want to bring the control to lower priority tasks, but they can't , doesn't matter that there is enough time. I mean - OS_Yield is a way to bring control to equal or higher priority tasks, but not to lower one. So, it's easy now to see the "white spot" - absence of command to bring easily the control to low priority tasks, without carrying about priorities , etc.

So, you can mark - there is no quick and simple way in SALVO to bring fresh air to low priority tasks. Well - OS_Delay is OK, but this will slow down the high priority tasks. Wait some semaphore is OK too - but need resources. The way to increase slowly the priority is too complicated.

I'm talking about some totally new function, that changes for a while the hierarchy of tasks, something like "thanksgiving day" when rich people share their money with beggar. One of the way is to delay the checking in of the OS_Yield task into the queue. So there should be add new state - Running, Waiting.... Refreshing (Compassion). Maybe "compassion" is the exactly word for such state. Because the task doesn't need to bring any time to anybody else lower then it. So, it's only a "good will".

Here is something that came to me in the last moment (excuse me for that the letter has little strange structure - it's because I didn't send it and applied the new ideas to old letter - became little twisted). What about:


OS_Inactive(number_of_skips_in_OSShed, _LAble);

Description - the task contex switch to the kernel and waits "number" times to run OSShed. It's absolutely equal to OS_Delay, with this small difference, that the counts are taking not from OSTimer, but from OSSched(). Or, it even could be imitate with current SALVO with OS_Delay, if OSTimer() is called from the main loop, immediately before or after OSShed. In this case OSTimer will be run with frequency of calling of OSShed.

So, if we have similar function in SALVO, let's think more - what about second OSTimer().. let's say OSTimer1()? If the user has possibility to call more then 1 OSTimer function it will be possible to call it from OSShed too - this will cover all noise around "compassion" problem of the high priority tasks, without losing their priority and response speed. Imagine that you can call


OS_Delay(number_of_OSShed_calls, channel_1, _Label);

The new modified OS_Delay could do the priority "compassion" issue, if channel 2 is called just before OSShed with OSTimer1(). And the now existing OSTimer will become OSTimer0().

If there are 4 low priority tasks with equal low priority, you can call OS_Delay(4, channel_1, _Label) and this will ensure that all tasks will get fresh air, right?

Now, new horizons appeared for the applications of the functions. One if the Interval - you can very simply make any interval function, if you call OSTimer1 from TMR1 or TMR2 with desired baud rate. It will produce high accuracy delays, with any frequency and phase.

As you see the function became OS_Delay, the existing OS_Delay with small "improvements" and the OSTimer1() - second timer function. Even you can think about OSNUMBER_OF_TIMERS settings in salvocfg.h ! I don't insist to have multiple OSTimer.. only 2 are enough to cover the "compassion" issue of the tasks, something like twisters - you know 2 kids are growing better then single one :-) Well, two kids need more resources (money, attention) from the parents (my own experience) as well.

So the issue can flow into new issue - "OS_Delay() improvements" or "The lost twister of OSTimer was finally found from FBI", or the current could be renamed.

I got these ideas from one of my projects where I marked that high priority tasks have one very bad character - they don't have "human compassion" - even if they have time and they could bring the time to low priority task, they don't do this. In fact with current functions there is no simple way to do this.

Other approach - define new state:
Such new state of the task doesn't change it's priority, but it eliminate high priority tasks from the "game" for some time. In this time low priority tasks could take control and celebrate.

In my opinion the approach is to create new state, similar to eligible, but the task should wait some number of OSSched() calls to become automatically eligible.

I have to think more about this, as I told you, this is only initial idea. Maybe there are possible good solutions with current SALVO functions. But this is one deep problem - the using of OS_Yield with different priority tasks.

I'll keep you in touch if something new passes trough my head :-)


Re: OS_Yield new features (OS_Refresh)

PostPosted: Sun Dec 09, 2001 12:36 pm
by luben

After working some time with SALVO I got some thoughts about OS_Yield().

Imagine that there are some tasks - TASK_A, TASK_B, TASK_C with priorities 2, 3, 4. TASK_C has lowest priority, TASK_A - highest.

So, if TASK_A issues OS_Yield() in endless loop, what will happen? TASK_B and TASK_C will never get the control (if I correctly understood SALVO). TASK_A will contex switch and return the control to the kernel, then the kernel will chose the next task to run... the task with highest priority. The result - program flow will "glue" to TASK_A. Solutions:
- to use OS_Delay() - this will solve the problem, but will slow down the response time of TASK_A
- to change the priority (decrease) before OS_Yield() and then to restore it - not good, because not in all cases is desirable to do this and in addition will break the SALVO elegant style.
- to use some BinSem that's set from other tasks... not good too.

So, OS_Yield() in current SALVO has some disadvantages when using tasks with different priorities and especially when issued from highest priority task. Let's say it in other way - it's a gate from where you can add to your project many problems, without even suspect about them. And in some rare case it could crash, just because low priority tasks didn't receive the control in some period of time.

My suggestions:
- the current OS_Yield() is good from the view point of multitasking ideas and there is no sense to change it - it really expresses the meaning - "return the control to the kernel". I insist that such function have to exist. What we need is maybe new function.
- create new function OS_Refresh(). The idea of such function is that the task returns the control to the kernel, and is checked into the task's queue (to this point it's equal to OS_Yield). Here are some of my visions about the next events:
. the task skips one OSShed() - I mean, after issue of OS_Refresh() the task is invisible for one calling of OSShed(), something like delayed entering into the task's queue with one OSShed cycle. This will allow to very low priority tasks to take the control, but after next OSShed() if the task has the highest priority it will gain its control and start again.
. if more then one tasks simultaneously call OS_Refresh, then is good to have a queue where "OS_Refresh" tasks will check in - not good because RAM needed. I hope you'll find better solution - like skip checking into task queue with variable number of delays or something like that.

In short - the idea of such new function is - "to bring fresh air to low priority tasks" without losing the control and the priority of the high priority tasks. Calling this function allows low priority tasks to gain the control with higher possibility, without breaking the priority hierarchy. It's something like "mercy and compassion" from high priority tasks to the poor once. Don't tell me that YOU (like high priority task) don't give a dime to a beggar (low priority task) on the street :-) The life needs both high and low priority tasks and some "compassion" should be allowed. For sure for the highest priority task is the best if it never shared any time and resources (money) with anybody else (it wants not multitasking, but single selfish tasking) - this is the current OS_Yield() approach. Well, it brings "compassion" only to same priority level task and of course bows to the boss. But such approach is not good for the whole project.

I know that this is only rough idea, but it's based on my observation - something could be improved into OS_Yield, but I don't know what exactly. But for sure OS_Yield could be very dangerous function in projects with different priority tasks. OS_Refresh will avoid this, without breaking the rules of multitasking.