frabert wrote:
@Brendan I'm not sure if this should be addressed here or in the wiki's discussion page, I'll move the post if necessary.
The current issue I'm facing while following your tutorial is this: let's suppose I have a task A, which blocks because it needs to wait for B to finish.
Looking at the code for block_task and unblock_task:
Code:
void block_task(int reason) {
lock_scheduler();
current_task_TCB->state = reason;
schedule();
unlock_scheduler();
}
void unblock_task(thread_control_block * task) {
lock_scheduler();
if(first_ready_to_run_task == NULL) {
// Only one task was running before, so pre-empt
switch_to_task(task);
} else {
// There's at least one task on the "ready to run" queue already, so don't pre-empt
last_ready_to_run_task->next = task;
last_ready_to_run_task = task;
}
unlock_scheduler();
}
this happens:
Code:
// A is running, sched_lock_cnt=0:
lock_scheduler(); // sched_lock=1, interrupts disabled
schedule(); // Now B is running
// Something something...
// B ends, unblocks A
lock_scheduler(); // sched_lock_cnt=2
switch_tasks(); // Now A is running
unlock_scheduler(); // sched_lock_cnt=1
// A continues its way, never to be interrupted again...
There's a paragraph near the end of "Step 5: Race Conditions and Locking Version 1" that tries to explain this:
Note that this can be a little confusing depending on your perspective. From the perspective of one task, it locks the scheduler, does a task switch, and then when it gets CPU time again it unlocks the scheduler; and this is fine (the scheduler is always unlocked after its locked). From the perspective of the CPU, one task locks the scheduler then the scheduler does a task switch and a completely different task unlocks the scheduler; and this is also fine (the scheduler is still unlocked after its locked).In other words; this happens:
Code:
// A is running, sched_lock_cnt=0:
lock_scheduler(); // sched_lock=1, interrupts disabled
schedule(); // Now B is running
unlock_scheduler(); // B unlocks the scheduler, sched_lock_cnt=0
// Something something...
lock_scheduler(); // B locks the scheduler, sched_lock_cnt=1
switch_tasks(); // Now A is running
unlock_scheduler(); // A unlocks the scheduler, sched_lock_cnt=0
// A continues its way
Note that this is the same issue you were having
before you read the tutorial. This makes me wonder if the tutorial is adequate for other people (who don't have pre-existing expectations of a problem), or if the tutorial needs to explain it better (either because people without pre-existing expectations will also think there's a problem or because other people are likely to have pre-existing expectations).
Cheers,
Brendan