Skip to content

Commit fabacc4

Browse files
committed
lazy stack: do nothing in kernel threads and on populated stack
This patch annotates the relevant call sites with the invariant assert expressions to validate assumptions that let us do "nothing" in all these cases. We also reorganize some code in the scheduler to help differentiate between cases when given function/method is called with interrupts or preemption disabled or from kernel thread or by interrupt handler. Following methods get added to scheduler code with names describing state of interrupts or preemption or kernel caller: - timer_base::set_with_irq_disabled(osv::clock::uptime::time_point time) - timer_base::set_with_irq_disabled(std::chrono::duration<Rep, Period> duration) - thread::wake_with_irq_disabled() - thread::wake_with_irq_or_preemption_disabled(Action action) - thread_handle::wake_from_kernel_or_with_irq_disabled() In general: - we modify all interrupt handlers (those that are executed on interrupt stack) to call one of the 3 new wake_...() methods (mostly wake_with_irq_disabled()) to indicate we do not need/should not pre-fault the stack; most of those are in device drivers code - we modify all code executed on kernel threads that disables preemption or interrupts by adding relevant invariant - assert(!sched::thread::current()->is_app()); we do not need to pre-fault because the stack is populated - we also modify the code whhich is indirectly called from kernel threads like classifier::post_packet() in net channels - finally we also modify the scheduler code to use timer_bas::set_with_irq_disabled() mostly around preemption_timer to indicate that we should not pre-fault the stack downstream Signed-off-by: Waldemar Kozaczuk <[email protected]>
1 parent f5684d9 commit fabacc4

32 files changed

+157
-39
lines changed

arch/aarch64/exceptions.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ void interrupt_table::unregister_interrupt(interrupt *interrupt)
122122

123123
bool interrupt_table::invoke_interrupt(unsigned int id)
124124
{
125+
#if CONF_lazy_stack_invariant
126+
assert(!arch::irq_enabled());
127+
#endif
125128
WITH_LOCK(osv::rcu_read_lock) {
126129
assert(id < this->nr_irqs);
127130
interrupt_desc *desc = this->irq_desc[id].read();

arch/aarch64/interrupt.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ sgi_interrupt::~sgi_interrupt()
2222

2323
void sgi_interrupt::send(sched::cpu* cpu)
2424
{
25+
#if CONF_lazy_stack_invariant
26+
assert(!arch::irq_enabled() || !sched::preemptable());
27+
#endif
2528
gic::gic->send_sgi(gic::sgi_filter::SGI_TARGET_LIST,
2629
cpu->arch.smp_idx, get_id());
2730
}

arch/x64/exceptions.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,9 @@ void interrupt_descriptor_table::unregister_interrupt(gsi_level_interrupt *inter
220220

221221
void interrupt_descriptor_table::invoke_interrupt(unsigned vector)
222222
{
223+
#if CONF_lazy_stack_invariant
224+
assert(!arch::irq_enabled());
225+
#endif
223226
WITH_LOCK(osv::rcu_read_lock) {
224227
unsigned i, nr_shared;
225228
bool handled = false;

arch/x64/mmu.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ std::atomic<int> tlb_flush_pendingconfirms;
6464
inter_processor_interrupt tlb_flush_ipi{IPI_TLB_FLUSH, [] {
6565
mmu::flush_tlb_local();
6666
if (tlb_flush_pendingconfirms.fetch_add(-1) == 1) {
67-
tlb_flush_waiter.wake();
67+
tlb_flush_waiter.wake_from_kernel_or_with_irq_disabled();
6868
}
6969
}};
7070

arch/x64/msi.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ static inline void set_affinity_and_wake(
126126
v->msix_unmask_entries();
127127
}
128128

129-
t->wake();
129+
t->wake_with_irq_disabled();
130130
}
131131

132132
bool interrupt_manager::easy_register(std::initializer_list<msix_binding> bindings)

core/async.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,9 @@ class async_worker {
160160
return _timer.expired() || !_queue.empty();
161161
});
162162

163+
#if CONF_lazy_stack_invariant
164+
assert(!sched::thread::current()->is_app());
165+
#endif
163166
WITH_LOCK(preempt_lock) {
164167
_timer.cancel();
165168

@@ -224,6 +227,9 @@ class async_worker {
224227
}
225228

226229
auto& master = *task.master;
230+
#if CONF_lazy_stack_invariant
231+
assert(!sched::thread::current()->is_app());
232+
#endif
227233
DROP_LOCK(preempt_lock) {
228234
master.fire(task);
229235
}

core/epoll.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ class epoll_file final : public special_file {
245245
if (!_activity_ring.push(key)) {
246246
_activity_ring_overflow.store(true, std::memory_order_relaxed);
247247
}
248-
_activity_ring_owner.wake();
248+
_activity_ring_owner.wake_from_kernel_or_with_irq_disabled();
249249
}
250250
};
251251

core/mempool.cc

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,9 @@ void pool::collect_garbage()
154154

155155
static void garbage_collector_fn()
156156
{
157+
#if CONF_lazy_stack_invariant
158+
assert(!sched::thread::current()->is_app());
159+
#endif
157160
WITH_LOCK(preempt_lock) {
158161
pool::collect_garbage();
159162
}
@@ -1352,9 +1355,12 @@ void l1::fill_thread()
13521355
auto& pbuf = get_l1();
13531356
for (;;) {
13541357
sched::thread::wait_until([&] {
1355-
WITH_LOCK(preempt_lock) {
1356-
return pbuf.nr < pbuf.watermark_lo || pbuf.nr > pbuf.watermark_hi;
1357-
}
1358+
#if CONF_lazy_stack_invariant
1359+
assert(!sched::thread::current()->is_app());
1360+
#endif
1361+
WITH_LOCK(preempt_lock) {
1362+
return pbuf.nr < pbuf.watermark_lo || pbuf.nr > pbuf.watermark_hi;
1363+
}
13581364
});
13591365
if (pbuf.nr < pbuf.watermark_lo) {
13601366
while (pbuf.nr + page_batch::nr_pages < pbuf.max / 2) {

core/net_channel.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,16 @@ void net_channel::process_queue()
4040

4141
void net_channel::wake_pollers()
4242
{
43+
#if CONF_lazy_stack_invariant
44+
assert(!sched::thread::current()->is_app());
45+
#endif
4346
WITH_LOCK(osv::rcu_read_lock) {
4447
auto pl = _pollers.read();
4548
if (pl) {
4649
for (pollreq* pr : *pl) {
4750
// net_channel is self synchronizing
4851
pr->_awake.store(true, std::memory_order_relaxed);
49-
pr->_poll_thread.wake();
52+
pr->_poll_thread.wake_from_kernel_or_with_irq_disabled();
5053
}
5154
}
5255
// can't call epoll_wake from rcu, so copy the data
@@ -128,6 +131,9 @@ void classifier::remove(ipv4_tcp_conn_id id)
128131

129132
bool classifier::post_packet(mbuf* m)
130133
{
134+
#if CONF_lazy_stack_invariant
135+
assert(!sched::thread::current()->is_app());
136+
#endif
131137
WITH_LOCK(osv::rcu_read_lock) {
132138
if (auto nc = classify_ipv4_tcp(m)) {
133139
log_packet_in(m, NETISR_ETHER);

core/rcu.cc

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,9 @@ void cpu_quiescent_state_thread::do_work()
118118
{
119119
while (true) {
120120
bool toclean = false;
121+
#if CONF_lazy_stack_invariant
122+
assert(!sched::thread::current()->is_app());
123+
#endif
121124
WITH_LOCK(preempt_lock) {
122125
auto p = &*percpu_callbacks;
123126
if (p->ncallbacks[p->buf]) {
@@ -242,7 +245,7 @@ void rcu_flush()
242245
rcu_defer([&] { s.post(); });
243246
// rcu_defer() might not wake the cleanup thread until enough deferred
244247
// callbacks have accumulated, so wake it up now.
245-
percpu_quiescent_state_thread->wake();
248+
percpu_quiescent_state_thread->wake_from_kernel_or_with_irq_disabled();
246249
}, sched::thread::attr().pin(c)));
247250
t->start();
248251
t->join();

0 commit comments

Comments
 (0)