Handout
This commit is contained in:
67
kernel/sync/bellringer.cc
Normal file
67
kernel/sync/bellringer.cc
Normal file
@@ -0,0 +1,67 @@
|
||||
#include "./bellringer.h"
|
||||
|
||||
#include "../arch/lapic.h"
|
||||
#include "../debug/assert.h"
|
||||
#include "../interrupt/guard.h"
|
||||
#include "arch/core_interrupt.h"
|
||||
|
||||
// check: Checks whether bells are running out of time and rings them if
|
||||
// necessary
|
||||
void Bellringer::check(Vault &vault) {
|
||||
if (Bell *bell = bells.first()) {
|
||||
bell->counter--;
|
||||
while ((bell = bells.first()) && bell->counter == 0) {
|
||||
bells.dequeue();
|
||||
vault.scheduler.ready(bell->thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// job: Give a bell to the bellringer & ring it when the specified time ran out.
|
||||
void Bellringer::sleep(Vault &vault, unsigned int ms) {
|
||||
Bell bell_tmp;
|
||||
Bell *bell = &bell_tmp;
|
||||
bell->thread = vault.scheduler.active();
|
||||
|
||||
assert(bell != nullptr);
|
||||
unsigned int ticks = ms * 1000 / LAPIC::Timer::interval();
|
||||
assert(ticks != 0);
|
||||
if (bells.first() == nullptr) {
|
||||
// queue is empty; enqueue new bell as first element
|
||||
bells.enqueue(*bell);
|
||||
} else {
|
||||
// To reduce the amount of work done in Bellringer::check (which
|
||||
// is called frequently), we sort the queue by relative waiting
|
||||
// times: Each bell is assigned the delta between its waiting
|
||||
// time and its predecessor's waiting time.
|
||||
// This allows us to only "tick" the first bell.
|
||||
|
||||
Bell *next = nullptr;
|
||||
Bell *pred = nullptr;
|
||||
for (Bell *p = bells.first(); p != nullptr; p = bells.next(*p)) {
|
||||
if (ticks < p->counter) {
|
||||
next = p;
|
||||
break;
|
||||
}
|
||||
ticks -= p->counter;
|
||||
pred = p;
|
||||
}
|
||||
// If there is a predecessor, enqueue the bell after pred;
|
||||
// otherwise insert at the beginning.
|
||||
if (pred != nullptr) {
|
||||
bells.insertAfter(*pred, *bell);
|
||||
} else {
|
||||
bells.insertFirst(*bell);
|
||||
}
|
||||
// If we have a predecessor, reduce its waiting time by our waiting
|
||||
// time, as _next_ will have to wait until we finished waiting.
|
||||
if (next != nullptr) {
|
||||
next->counter -= ticks;
|
||||
}
|
||||
}
|
||||
bell->counter = ticks;
|
||||
vault.scheduler.resume(false);
|
||||
}
|
||||
|
||||
// Are there bells in the queue?
|
||||
bool Bellringer::bellPending() const { return !bells.is_empty(); }
|
||||
Reference in New Issue
Block a user