Если вы посмотрите на код для освобождения блокировки a>, вы увидите, что он не разрешает прерывания явно. Вместо этого он использует функцию popcli
.
void release ( struct spinlock* lk )
{
...
popcli(); // enable interrupts
}
Функция popcli
не всегда разрешает прерывания. Он используется вместе с pushcli
для отслеживания уровня вложенности. «Pushcli / popcli похожи на cli / sti, за исключением того, что они совпадают: требуется два popcli, чтобы отменить два pushcli». 1
void popcli ( void )
{
// If interrupts are enabled, panic...
if ( readeflags() & FL_IF )
{
panic( "popcli: interruptible" );
}
// Track depth of cli nesting
mycpu()->ncli -= 1;
// Popped more than were pushed...
if ( mycpu()->ncli < 0 )
{
panic( "popcli" );
}
// Reached outermost, so restore interrupt state
if ( mycpu()->ncli == 0 && mycpu()->intena )
{
sti(); // enable interrupts
}
}
В то время как popcli
иногда разрешает прерывания, pushcli
всегда запрещает прерывания.
void pushcli ( void )
{
int eflags;
eflags = readeflags();
// Disable interrupts
cli();
// Save interrupt state at start of outermost
if ( mycpu()->ncli == 0 )
{
mycpu()->intena = eflags & FL_IF;
}
// Track depth of cli nesting
mycpu()->ncli += 1;
}
Явным вызовом sti
планировщик отменяет текущее состояние push / popcli. Я думаю, что это дает краткое окно, необходимое для прерывания ввода-вывода. Т.е. период времени между вызовом sti
и вызовом cli
(через acquire
-> pushcli
-> cli
).
void scheduler ( void )
{
...
for ( ;; )
{
// Enable interrupts on this processor.
sti();
// Acquire process table lock
acquire( &ptable.lock );
// Loop over process table looking for process to run.
for ( p = ptable.proc; p < &ptable.proc[ NPROC ]; p += 1 )
{
...
}
// Release process table lock
release( &ptable.lock );
}
}
person
Jet Blue
schedule
16.06.2020
sti
и посмотреть, зависает ли планировщик или продолжает нормально. - person smac89   schedule 26.11.2016