williamdavy wrote on Tuesday, October 11, 2011:
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.