dragonflight1 wrote on Wednesday, December 11, 2013:

First, I want to confirm how configUSE_TIME_SLICING = 0 works.
Assuming two processes A and B at the same priority, I understand (I think)

as long as A calls no FreeRTOS functions or only *FromISR" functions it will not lose the CPU to B, but of course may lose the CPU to interrupts and higher priority tasks.

If A calls a function that blocks (send/receive with timeout, vDelayUtil with a timeout in the future), B will execute (assuming it is READY)

I am unsure of taskYield, and whether vDelay(1) guarantees a task switch to B (assuming B is READY).

Is there any other “standard” way of forcing the task switch?

In particular, I am considering how to share common resources (in my case I2C, SPI and DSP on a dsPIC33E processor and a non-reentrant sprintf), and think of placing all process that use the resource on the same priority level, in particular all process that use the math(DSP) functions. This seems easier (but perhaps not) than protecting the calculations with semaphores/mutexes, but certainly easier than trying to move everything to a single process.

edwards3 wrote on Wednesday, December 11, 2013:

It looks like configUSE_TIME_SLICING is only used in one place in the code, and its use prevents the scheduler switching between tasks of equal priority just because a tick interrupt fires. It cant prevent a change of tasks if the running task blocks, that wouldnt make sense, and a yield is always going to yield if there are other tasks at the same priority, so I think everything you say is right.

dragonflight1 wrote on Thursday, December 12, 2013:

While I would normally “use the source”, I thought it better to understand the intent, before commenting on the code (or what I understand of it) especially as on first/second reading I was confused! (getting easier and easier at my age!)

I disagree that yield must yield to a process of equal priority - it could be defined either way, though I agree that it would be reasonable to choose to define it so that it does.

In my reading of the code (flawed I am sure), yield always rotates the ready queue, so it operates the way you expect.

However, it now occurs to me that yield is also the way a high priority task blocking gives up the processor to a lower priority task, which would mean my first assumption is false.

In addition it seems that a yield is executed if reading an element from a queue, even using xQueueReceiveFromISR if it allows a >= priority to complete a send (despite the comment saying greater than). (In the case of xQueueReceiveFromISR obviously a yield is not executed, but the yield flag is set)

all of which would say that it is not a useful mechanism for sharing resources, or I just didn’t understand the code!

richard_damon wrote on Thursday, December 12, 2013:

Yield can NOT be used by a high priority task to give control to a lower priority task. Since the running task will always (if using preemption) be of the highest priority that has a ready task. Since Yield does not move a task out of the ready state, just “yields” to other ready tasks, those tasks must be of the same priority (or possibly higher if preemption is off).

I would not use USE_TIME_SLICING as a way to establish resource control as it seems very unstable. I would need to verify that things like a higher priority task becoming ready and then blocking couldn’t cause a switch.

dragonflight1 wrote on Thursday, December 12, 2013:


I realize taskYield will not give control to a lower priority task but I said when it blocks it internally uses yield (or more specifically listGET_OWNER_OF_NEXT_ENTRY) which rotates the queue.

I have pretty much convinced myself that it can’t be used for mutual exclusion as it now stands and that in fact it doesn’t work as described in the online description of configUSE_TIME_SLICING constituting (if I am correct) a bug in the code or the documentation.

I seems to me that it would be a useful mechanism and even more so if it were configurable on a per priority or even a per task basis

rtel wrote on Thursday, December 12, 2013:

it doesn’t work as described in the online description

If that is the case, please post a link to where the description is wrong and I will ensure it gets fixed.

It might be that you can achieve what you want using the co-operative scheduler rather than the preemptive scheduler without time slicing. From V7.6.0 the co-operative scheduler will only switch to another task if the current task enters the blocked state or explicitly yields.


dragonflight1 wrote on Thursday, December 12, 2013:

in particular

If configUSE_TIME_SLICING is set to 0 then the RTOS scheduler will still run the highest priority task that is in the Ready state, but will not switch between tasks of equal priority until the Running state task enters the Blocked state as a result of calling a Blocking FreeRTOS API function.

As I understand the code it will switch in many situations (Higher priority task running and then blocking, interrupt causing unblocking of a task of the same priority (if the yield flag is used), and depending on your definition of “Blocking FreeRTOS API function”, a send/recieve that unblocks a task of the same priority)

As for the co-operative scheduler - I have always considered that a wimp’s/lazy way out though more robust (and one that I have used many times!).
No time slicing seemed to be a way of having my cake and eating it too.

I will probably look at V7.6.0 to see what changes you have made and change it to work as I think it should (at first glance it doesn’t seem too hard …). It is a personal project so I can play.

If it doesn’t work out I will probably just use semaphores/mutexes, particularly for the math stuff.

As a final aside do you remember offhand why in the code (this is from xTaskRemoveFromEventList) >= is used. This same snippet is used in many places.

	if( pxUnblockedTCB->uxPriority >= pxCurrentTCB->uxPriority )
		/* Return true if the task removed from the event list has
		a higher priority than the calling task.  This allows
		the calling task to know if it should force a context
		switch now. */
		xReturn = pdTRUE;

It would seem to me, even with time slicing, that FreeRTOS shouldn’t switch just because some other task at the same priority has become unblocked

rtel wrote on Thursday, December 12, 2013:

If configUSE_TIME_SLICING is set to 0 then the RTOS

Agreed that the documentation needs updating. I will see to that. The configuration option only prevents a context switch purely because a time slice has come to an end (in the tick interrupt), and not for any other reason.

As a final aside do you remember offhand why

It was done that way because of the original linked list implementation needed it to be to prevent the same task being selected again before a newly woken task. Since then the linked list implementation has been improved to remove the inefficiency. The only reason the code has not been updated is because there is a mass of documentation that says it is done the way it is (the books in particular). When time allows all the documentation to be updated (which is now somewhat inconsistent) then the code will also be updated.


rtel wrote on Friday, December 13, 2013:

The wording has been changed.