Skip to content

Commit 7c9c4c3

Browse files
committed
lazy stack: ensure next stack page dynamically if preemption enabled
This patch modifies number of critical places mostly in the scheduler code to dynamically pre-fault the stack if preemption is enabled. In all these places we can be statically sure that interrupts are enabled but not so sure about preemption (maybe in future we can prove it is enabled at least in some of the cases and replace conditional ensure_next_stack_page_if_preemptable() with cheaper single-intruction ensure_next_stack_page()). The three call sites before irq_lock is taken (interrupts are disabled) include: - cpu::schedule() before WITH_LOCK(irq_lock) - thread::pin() before WITH_LOCK(irq_lock) - thread::yield() before guard*(irq_lock) The reasoning above goes like this: the methods were designed with intention to be used when interrupts are enabled because otherwise the act of using WITH_LOCK or guard construct would imply that interrupts would be re-enabled after the block so the code does not care about restoring interrupts to the proper state it was before. If that was the intension, these methods would use irq_save_lock_type. Two other call sites in the scheduler are: - timer_base destructor before calling timer_base::cancel() which disables interrupts - thread::wake_with_from_mutex() only called from waiter::wake() follow the reasoning that interrupts are enabled most of the time except few places in scheduler and interrupt handler. Also we assume the mutex is not used when interrupts are disabled. And based on my analysis of all the code that disables/enables interrupts that seems to be the case. In any case we put invariants in these two places to verify that interrupts are enabled indeed. The last call site in abort() assumes that calling irq_disable() implies that interrupts are enabled before and we only need to check preemption status. Signed-off-by: Waldemar Kozaczuk <jwkozaczuk@gmail.com>
1 parent 9b1e9b0 commit 7c9c4c3

File tree

3 files changed

+44
-0
lines changed

3 files changed

+44
-0
lines changed

core/sched.cc

+24
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,9 @@ void thread::cputime_estimator_get(
224224
// scheduler on a different CPU would be disastrous.
225225
void cpu::schedule()
226226
{
227+
#if CONF_lazy_stack
228+
sched::ensure_next_stack_page_if_preemptable();
229+
#endif
227230
WITH_LOCK(irq_lock) {
228231
#ifdef __aarch64__
229232
reschedule_from_interrupt(sched::cpu::current(), false, thyst);
@@ -566,6 +569,9 @@ void thread::pin(cpu *target_cpu)
566569
t.wake();
567570
}, sched::thread::attr().pin(source_cpu)));
568571
wakeme->start();
572+
#if CONF_lazy_stack
573+
sched::ensure_next_stack_page_if_preemptable();
574+
#endif
569575
WITH_LOCK(irq_lock) {
570576
trace_sched_migrate(&t, target_cpu->id);
571577
t.stat_migrations.incr();
@@ -822,6 +828,12 @@ void thread::yield(thread_runtime::duration preempt_after)
822828
{
823829
trace_sched_yield();
824830
auto t = current();
831+
#if CONF_lazy_stack_invariant
832+
assert(arch::irq_enabled());
833+
#endif
834+
#if CONF_lazy_stack
835+
sched::ensure_next_stack_page_if_preemptable();
836+
#endif
825837
std::lock_guard<irq_lock_type> guard(irq_lock);
826838
// FIXME: drive by IPI
827839
cpu::current()->handle_incoming_wakeups();
@@ -1258,6 +1270,12 @@ void thread::wake_impl(detached_state* st, unsigned allowed_initial_states_mask)
12581270

12591271
void thread::wake()
12601272
{
1273+
#if CONF_lazy_stack_invariant
1274+
assert(arch::irq_enabled());
1275+
#endif
1276+
#if CONF_lazy_stack
1277+
sched::ensure_next_stack_page_if_preemptable();
1278+
#endif
12611279
WITH_LOCK(rcu_read_lock) {
12621280
wake_impl(_detached_state.get());
12631281
}
@@ -1604,6 +1622,12 @@ timer_base::timer_base(timer_base::client& t)
16041622

16051623
timer_base::~timer_base()
16061624
{
1625+
#if CONF_lazy_stack_invariant
1626+
assert(arch::irq_enabled());
1627+
#endif
1628+
#if CONF_lazy_stack
1629+
sched::ensure_next_stack_page_if_preemptable();
1630+
#endif
16071631
cancel();
16081632
}
16091633

include/osv/sched.hh

+17
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,15 @@ inline bool preemptable()
10431043
return !get_preempt_counter();
10441044
}
10451045

1046+
#if CONF_lazy_stack
1047+
inline void ensure_next_stack_page_if_preemptable() {
1048+
if (!preemptable()) {
1049+
return;
1050+
}
1051+
arch::ensure_next_stack_page();
1052+
}
1053+
#endif
1054+
10461055
inline void preempt()
10471056
{
10481057
if (preemptable()) {
@@ -1350,6 +1359,14 @@ template <class Action>
13501359
inline
13511360
void thread::wake_with_from_mutex(Action action)
13521361
{
1362+
#if CONF_lazy_stack_invariant
1363+
assert(arch::irq_enabled());
1364+
#endif
1365+
#if CONF_lazy_stack
1366+
if (preemptable()) {
1367+
arch::ensure_next_stack_page();
1368+
}
1369+
#endif
13531370
return do_wake_with(action, (1 << unsigned(status::waiting))
13541371
| (1 << unsigned(status::sending_lock)));
13551372
}

runtime.cc

+3
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,9 @@ void abort(const char *fmt, ...)
113113
do {} while (true);
114114
}
115115

116+
#if CONF_lazy_stack
117+
sched::ensure_next_stack_page_if_preemptable();
118+
#endif
116119
arch::irq_disable();
117120

118121
static char msg[1024];

0 commit comments

Comments
 (0)