Cooperative Multitasking and gdb debugging

anonymous wrote on Tuesday, October 11, 2011:

I’m evaluating the use of FreeRTOS on a small amateur radio satellite.

We are debating whether we should use preemptive or cooperative multitasking.

First, is it practical to do single-step debugging using gdb with FreeRTOS preemptive multitasking?  I don’t see any indication that gdb is FreeRTOS kernel aware, so I assume the usual multitasking gdb features do not work?  Do attempts to break and single-step result in the timer context switching in the middle of the debug?

Second, no online documentation I can find on documents using cooperative multitasking with the configUSE_PREEMPTION compile flag.  Only co-routines are discussed.  Is use of configUSE_PREEMPTION still encouraged and actively in use?  Or has it somehow been deprecated in favor of co-routines?

Braddock Gaskill

williamdavy wrote on Tuesday, October 11, 2011:

Hi Braddock,

Firstly, you are correct about GDB and single stepping code. There are things that you can do to mitigate the consequences, such as raising the priority of the Task to maximum, disabling pre-emption, entering critical sections or temporarily suspending the Scheduler. These mitigations aren’t perfect in that they require you to modify your code a bit and typically you can’t call kernel API functions from inside critical sections.

However, when you are stepping through code, the debugger places the temporary break-point on the next line of C code and as long as no other tasks are executing the same code you should get away with it. Any shared/re-entrant code that is being executed by something else is liable to switch your debug context without you realising which is a pain.

With respect to Pre-emptive vs Co-operative, the configUSE_PREEMPTION flag simply prevents the system tick from performing a task context switch. Therefore, Tasks have to explicitly yield. When you call any of the queue functionality, semaphores, or task delay or specifically taskYIELD(), then your task will yield and the scheduler can select the next task. The system tick continues to fire and count up ticks but it the scheduler doesn’t get the opportunity to force the context switch. In some respects, this fixes your gdb single step problem because other tasks will not execute between each step, though the interrupt handlers.

Co-routines are heading towards being deprecated. They only provide the capability of running different functions from within a single task context, the IDLE task, and are intended for very low-memory systems. They are explicitly co-operative and in a system with pre-emption the IDLE task will be pre-empted meaning that the co-routines are pre-empted by other tasks, but not by each other.

I hope that answers your questions satisfactorily.