Kernel: Threads cannot take arguments anymore
This commit is contained in:
parent
4d8bdec16d
commit
1dd61e93b6
|
@ -5,23 +5,18 @@ read_rip:
|
||||||
jmp *%eax
|
jmp *%eax
|
||||||
|
|
||||||
exit_thread_trampoline:
|
exit_thread_trampoline:
|
||||||
addl $16, %esp
|
addl $4, %esp
|
||||||
popl %eax
|
pushl (%esp)
|
||||||
pushl $0x696969
|
|
||||||
pushl %eax
|
|
||||||
ret
|
ret
|
||||||
|
|
||||||
# void start_thread(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t rsp, uint32_t rip)
|
# void start_thread(uint32_t function, uint32_t esp, uint32_t eip)
|
||||||
.global start_thread
|
.global start_thread
|
||||||
start_thread:
|
start_thread:
|
||||||
movl %esp, %eax
|
movl 4(%esp), %eax
|
||||||
movl 24(%eax), %ecx
|
movl 12(%esp), %ecx
|
||||||
movl 20(%eax), %esp
|
movl 8(%esp), %esp
|
||||||
|
|
||||||
pushl 16(%eax)
|
pushl %eax
|
||||||
pushl 12(%eax)
|
|
||||||
pushl 8(%eax)
|
|
||||||
pushl 4(%eax)
|
|
||||||
pushl $exit_thread_trampoline
|
pushl $exit_thread_trampoline
|
||||||
|
|
||||||
movl $0, %ebp
|
movl $0, %ebp
|
||||||
|
|
|
@ -8,14 +8,14 @@ exit_thread_trampoline:
|
||||||
movq 8(%rsp), %rdi
|
movq 8(%rsp), %rdi
|
||||||
ret
|
ret
|
||||||
|
|
||||||
# void start_thread(uint64_t arg0, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t rsp, uint64_t rip)
|
# void start_thread(uint64_t function, uint64_t rsp, uint64_t rip)
|
||||||
.global start_thread
|
.global start_thread
|
||||||
start_thread:
|
start_thread:
|
||||||
movq %r8, %rsp
|
movq %rsi, %rsp
|
||||||
movq $0, %rbp
|
movq $0, %rbp
|
||||||
pushq $exit_thread_trampoline
|
pushq $exit_thread_trampoline
|
||||||
sti
|
sti
|
||||||
jmp *%r9
|
jmp *%rdx
|
||||||
|
|
||||||
# void continue_thread(uint64_t rsp, uint64_t rip)
|
# void continue_thread(uint64_t rsp, uint64_t rip)
|
||||||
.global continue_thread
|
.global continue_thread
|
||||||
|
|
|
@ -18,17 +18,7 @@ namespace Kernel
|
||||||
|
|
||||||
const Thread& current_thread() const;
|
const Thread& current_thread() const;
|
||||||
|
|
||||||
template<typename... Args>
|
BAN::ErrorOr<void> add_thread(const BAN::Function<void()>& function);
|
||||||
BAN::ErrorOr<void> add_thread(const BAN::Function<void(Args...)>& func, Args... args)
|
|
||||||
{
|
|
||||||
uintptr_t flags;
|
|
||||||
asm volatile("pushf; pop %0" : "=r"(flags));
|
|
||||||
asm volatile("cli");
|
|
||||||
TRY(m_threads.emplace_back(func, BAN::forward<Args>(args)...));
|
|
||||||
if (flags & (1 << 9))
|
|
||||||
asm volatile("sti");
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
void reschedule();
|
void reschedule();
|
||||||
void set_current_thread_sleeping();
|
void set_current_thread_sleeping();
|
||||||
|
|
|
@ -22,19 +22,10 @@ namespace Kernel
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
#pragma GCC diagnostic push
|
Thread(const BAN::Function<void()>&);
|
||||||
#pragma GCC diagnostic ignored "-Wpmf-conversions"
|
|
||||||
template<typename... Args>
|
|
||||||
Thread(const BAN::Function<void(Args...)>& func, Args... args)
|
|
||||||
: Thread((uintptr_t)(void*)&BAN::Function<void(Args...)>::operator(), (uintptr_t)&func, ((uintptr_t)args)...)
|
|
||||||
{
|
|
||||||
static_assert(((BAN::is_integral_v<Args> || BAN::is_pointer_v<Args>) && ...));
|
|
||||||
}
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
||||||
~Thread();
|
~Thread();
|
||||||
|
|
||||||
uint32_t id() const { return m_id; }
|
uint32_t tid() const { return m_tid; }
|
||||||
|
|
||||||
void set_rsp(uintptr_t rsp) { m_rsp = rsp; }
|
void set_rsp(uintptr_t rsp) { m_rsp = rsp; }
|
||||||
void set_rip(uintptr_t rip) { m_rip = rip; }
|
void set_rip(uintptr_t rip) { m_rip = rip; }
|
||||||
|
@ -43,21 +34,19 @@ namespace Kernel
|
||||||
uintptr_t rip() const { return m_rip; }
|
uintptr_t rip() const { return m_rip; }
|
||||||
State state() const { return m_state; }
|
State state() const { return m_state; }
|
||||||
|
|
||||||
const uintptr_t* args() const { return m_args; }
|
const BAN::Function<void()>* function() const { return &m_function; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Thread(uintptr_t rip, uintptr_t func, uintptr_t arg1 = 0, uintptr_t arg2 = 0, uintptr_t arg3 = 0);
|
|
||||||
void on_exit();
|
void on_exit();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void* m_stack_base = nullptr;
|
void* m_stack_base = nullptr;
|
||||||
State m_state = State::NotStarted;
|
State m_state = State::NotStarted;
|
||||||
uintptr_t m_args[4] = {};
|
|
||||||
uintptr_t m_rip = 0;
|
uintptr_t m_rip = 0;
|
||||||
uintptr_t m_rsp = 0;
|
uintptr_t m_rsp = 0;
|
||||||
const uint32_t m_id = 0;
|
const uint32_t m_tid = 0;
|
||||||
|
|
||||||
alignas(max_align_t) uint8_t m_function[BAN::Function<void()>::size()] { 0 };
|
BAN::Function<void()> m_function;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -7,7 +7,7 @@ namespace Kernel
|
||||||
|
|
||||||
static Scheduler* s_instance = nullptr;
|
static Scheduler* s_instance = nullptr;
|
||||||
|
|
||||||
extern "C" void start_thread(uintptr_t arg0, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3, uintptr_t rsp, uintptr_t rip);
|
extern "C" void start_thread(const BAN::Function<void()>* function, uintptr_t rsp, uintptr_t rip);
|
||||||
extern "C" void continue_thread(uintptr_t rsp, uintptr_t rip);
|
extern "C" void continue_thread(uintptr_t rsp, uintptr_t rip);
|
||||||
extern "C" uintptr_t read_rip();
|
extern "C" uintptr_t read_rip();
|
||||||
|
|
||||||
|
@ -30,6 +30,18 @@ namespace Kernel
|
||||||
return *m_current_iterator;
|
return *m_current_iterator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BAN::ErrorOr<void> Scheduler::add_thread(const BAN::Function<void()>& function)
|
||||||
|
{
|
||||||
|
uintptr_t flags;
|
||||||
|
asm volatile("pushf; pop %0" : "=r"(flags));
|
||||||
|
asm volatile("cli");
|
||||||
|
TRY(m_threads.emplace_back(function));
|
||||||
|
if (flags & (1 << 9))
|
||||||
|
asm volatile("sti");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
void Scheduler::reschedule()
|
void Scheduler::reschedule()
|
||||||
{
|
{
|
||||||
ASSERT(InterruptController::get().is_in_service(PIT_IRQ));
|
ASSERT(InterruptController::get().is_in_service(PIT_IRQ));
|
||||||
|
@ -62,9 +74,6 @@ namespace Kernel
|
||||||
|
|
||||||
Thread& current = *m_current_iterator;
|
Thread& current = *m_current_iterator;
|
||||||
|
|
||||||
//if (m_threads.size() == 2 && current.id() != 0 && current.state() == Thread::State::Running)
|
|
||||||
// return;
|
|
||||||
|
|
||||||
if (current.state() == Thread::State::Done)
|
if (current.state() == Thread::State::Done)
|
||||||
{
|
{
|
||||||
m_threads.remove(m_current_iterator);
|
m_threads.remove(m_current_iterator);
|
||||||
|
@ -91,7 +100,7 @@ namespace Kernel
|
||||||
{
|
{
|
||||||
case Thread::State::NotStarted:
|
case Thread::State::NotStarted:
|
||||||
next.set_state(Thread::State::Running);
|
next.set_state(Thread::State::Running);
|
||||||
start_thread(next.args()[0], next.args()[1], next.args()[2], next.args()[3], next.rsp(), next.rip());
|
start_thread(next.function(), next.rsp(), next.rip());
|
||||||
break;
|
break;
|
||||||
case Thread::State::Paused:
|
case Thread::State::Paused:
|
||||||
next.set_state(Thread::State::Running);
|
next.set_state(Thread::State::Running);
|
||||||
|
@ -123,8 +132,7 @@ namespace Kernel
|
||||||
ASSERT(current.state() == Thread::State::NotStarted);
|
ASSERT(current.state() == Thread::State::NotStarted);
|
||||||
current.set_state(Thread::State::Running);
|
current.set_state(Thread::State::Running);
|
||||||
|
|
||||||
const uintptr_t* args = current.args();
|
start_thread(current.function(), current.rsp(), current.rip());
|
||||||
start_thread(args[0], args[1], args[2], args[3], current.rsp(), current.rip());
|
|
||||||
|
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,21 +180,18 @@ argument_done:
|
||||||
{
|
{
|
||||||
static SpinLock s_thread_spinlock;
|
static SpinLock s_thread_spinlock;
|
||||||
|
|
||||||
// NOTE: This is a workaround to pass values as copies to threads.
|
|
||||||
// I have only implemented passing integer and pointers.
|
|
||||||
// We don't continue execution until the thread has unlocked
|
|
||||||
// the spinlock.
|
|
||||||
s_thread_spinlock.lock();
|
s_thread_spinlock.lock();
|
||||||
MUST(Scheduler::get().add_thread(Function<void(const Vector<String>*)>(
|
|
||||||
[this] (const Vector<String>* args_ptr)
|
MUST(Scheduler::get().add_thread(Function<void()>(
|
||||||
|
[this, &arguments]
|
||||||
{
|
{
|
||||||
auto args = *args_ptr;
|
auto args = arguments;
|
||||||
s_thread_spinlock.unlock();
|
|
||||||
args.remove(0);
|
args.remove(0);
|
||||||
|
s_thread_spinlock.unlock();
|
||||||
PIT::sleep(5000);
|
PIT::sleep(5000);
|
||||||
process_command(args);
|
process_command(args);
|
||||||
}
|
}
|
||||||
), &arguments));
|
)));
|
||||||
|
|
||||||
while (s_thread_spinlock.is_locked());
|
while (s_thread_spinlock.is_locked());
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
namespace Kernel
|
namespace Kernel
|
||||||
{
|
{
|
||||||
|
|
||||||
static uint32_t s_next_id = 0;
|
static uint32_t s_next_tid = 0;
|
||||||
|
|
||||||
static constexpr size_t thread_stack_size = 16384;
|
static constexpr size_t thread_stack_size = 16384;
|
||||||
|
|
||||||
|
@ -21,26 +21,19 @@ namespace Kernel
|
||||||
memcpy((void*)rsp, (void*)&value, size);
|
memcpy((void*)rsp, (void*)&value, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread::Thread(uintptr_t rip, uintptr_t func, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3)
|
Thread::Thread(const BAN::Function<void()>& function)
|
||||||
: m_id(s_next_id++)
|
: m_tid(s_next_tid++)
|
||||||
|
, m_function(function)
|
||||||
{
|
{
|
||||||
m_stack_base = kmalloc(thread_stack_size, PAGE_SIZE);
|
m_stack_base = kmalloc(thread_stack_size, PAGE_SIZE);
|
||||||
ASSERT(m_stack_base);
|
ASSERT(m_stack_base);
|
||||||
|
|
||||||
m_rsp = (uintptr_t)m_stack_base + thread_stack_size;
|
m_rsp = (uintptr_t)m_stack_base + thread_stack_size;
|
||||||
m_rip = rip;
|
|
||||||
m_args[1] = arg1;
|
|
||||||
m_args[2] = arg2;
|
|
||||||
m_args[3] = arg3;
|
|
||||||
|
|
||||||
// NOTE: in System V ABI arg0 is the pointer to 'this'
|
#pragma GCC diagnostic push
|
||||||
// we copy the function object to Thread object
|
#pragma GCC diagnostic ignored "-Wpmf-conversions"
|
||||||
// so we can ensure the lifetime of it. We store
|
m_rip = (uintptr_t)(void*)&BAN::Function<void()>::operator();
|
||||||
// it as raw bytes so that Thread can be non-templated.
|
#pragma GCC diagnostic pop
|
||||||
// This requires BAN::Function to be trivially copyable
|
|
||||||
// but for now it should be.
|
|
||||||
memcpy(m_function, (void*)func, sizeof(m_function));
|
|
||||||
m_args[0] = (uintptr_t)m_function;
|
|
||||||
|
|
||||||
write_to_stack<sizeof(void*)>(m_rsp, this);
|
write_to_stack<sizeof(void*)>(m_rsp, this);
|
||||||
write_to_stack<sizeof(void*)>(m_rsp, &Thread::on_exit);
|
write_to_stack<sizeof(void*)>(m_rsp, &Thread::on_exit);
|
||||||
|
|
Loading…
Reference in New Issue