From 9bcbd965dc7ef0f4d79f3d0302444b72b4b42a1f Mon Sep 17 00:00:00 2001
From: Avi Kivity <avi.kivity@gmail.com>
Date: Wed, 2 Jan 2013 17:48:08 +0200
Subject: [PATCH] sched: switch main thread stack from original stack

This way everyone's running on a similar sized stack.  Theoretically the
main thread can be destroyed as well.
---
 arch/x64/arch-switch.hh | 15 +++++++++++++++
 arch/x64/entry.S        | 13 +++++++++++++
 loader.cc               |  2 +-
 sched.cc                |  4 ++--
 sched.hh                |  2 ++
 5 files changed, 33 insertions(+), 3 deletions(-)

diff --git a/arch/x64/arch-switch.hh b/arch/x64/arch-switch.hh
index 09ddce5b0..3ed343969 100644
--- a/arch/x64/arch-switch.hh
+++ b/arch/x64/arch-switch.hh
@@ -7,6 +7,8 @@
 extern "C" {
 void thread_main(void);
 void thread_main_c(sched::thread* t);
+void stack_trampoline(sched::thread* t, void (*func)(sched::thread*),
+                      void** stacktop);
 }
 
 namespace sched {
@@ -37,6 +39,19 @@ void thread::init_stack()
     _state.rsp = stacktop;
 }
 
+void thread::switch_to_thread_stack()
+{
+    void** stacktop = reinterpret_cast<void**>(_stack + sizeof(_stack));
+    stack_trampoline(this, &thread::on_thread_stack, stacktop);
+}
+
+void thread::on_thread_stack(thread* t)
+{
+    t->_func();
+    t->_waiting = true;
+    schedule();
+}
+
 void thread::setup_tcb()
 {
     // FIXME: respect alignment
diff --git a/arch/x64/entry.S b/arch/x64/entry.S
index a99cd3820..849cd9511 100644
--- a/arch/x64/entry.S
+++ b/arch/x64/entry.S
@@ -100,3 +100,16 @@ thread_main:
 	pop %rdi
 	call thread_main_c
 	.cfi_endproc
+
+.global stack_trampoline
+stack_trampoline:  # %rsi=arg, %rdi=func, %rdx=stack
+	.cfi_startproc simple
+	.cfi_def_cfa %rsp, 0
+	mov %rsp, -8(%rdx)
+	lea -8(%rdx), %rsp
+	.cfi_rel_offset %rsp, 0
+	call *%rsi
+	pop %rsp
+	.cfi_restore %rsp
+	ret
+	.cfi_endproc
diff --git a/loader.cc b/loader.cc
index a10f74bbb..fd9c571d9 100644
--- a/loader.cc
+++ b/loader.cc
@@ -157,7 +157,7 @@ int main(int ac, char **av)
 
 void main_thread(elf::program& prog)
 {
-    new thread([] { test_threads(); });
+    test_threads();
     prog.add("libjvm.so");
     auto JNI_GetDefaultJavaVMInitArgs
         = prog.lookup_function<void (void*)>("JNI_GetDefaultJavaVMInitArgs");
diff --git a/sched.cc b/sched.cc
index f39bd0156..0131a7c61 100644
--- a/sched.cc
+++ b/sched.cc
@@ -34,7 +34,7 @@ void schedule()
 
 thread::thread(std::function<void ()> func, bool main)
     : _func(func)
-    , _on_runqueue(true)
+    , _on_runqueue(!main)
     , _waiting(false)
 {
     if (!main) {
@@ -44,7 +44,7 @@ thread::thread(std::function<void ()> func, bool main)
     } else {
         setup_tcb_main();
         s_current = this;
-        func();
+        switch_to_thread_stack();
         abort();
     }
 }
diff --git a/sched.hh b/sched.hh
index 323137a56..19958a14b 100644
--- a/sched.hh
+++ b/sched.hh
@@ -32,6 +32,8 @@ private:
     void init_stack();
     void setup_tcb();
     void setup_tcb_main();
+    static void on_thread_stack(thread* t);
+    void switch_to_thread_stack();
 private:
     std::function<void ()> _func;
     thread_state _state;
-- 
GitLab