Compare commits

...

7 Commits

13 changed files with 216 additions and 20 deletions

View File

@ -36,6 +36,8 @@ start_kernel_thread:
.global start_userspace_thread .global start_userspace_thread
start_userspace_thread: start_userspace_thread:
call load_thread_sse
call get_thread_start_sp call get_thread_start_sp
movl %eax, %esp movl %eax, %esp

View File

@ -27,6 +27,8 @@ start_kernel_thread:
.global start_userspace_thread .global start_userspace_thread
start_userspace_thread: start_userspace_thread:
call load_thread_sse
call get_thread_start_sp call get_thread_start_sp
movq %rax, %rsp movq %rax, %rsp

View File

@ -182,8 +182,10 @@ namespace Kernel
BAN::ErrorOr<long> sys_sigpending(sigset_t* set); BAN::ErrorOr<long> sys_sigpending(sigset_t* set);
BAN::ErrorOr<long> sys_sigprocmask(int how, const sigset_t* set, sigset_t* oset); BAN::ErrorOr<long> sys_sigprocmask(int how, const sigset_t* set, sigset_t* oset);
BAN::ErrorOr<long> sys_yield();
BAN::ErrorOr<long> sys_pthread_create(const pthread_attr_t* __restrict attr, void (*entry)(void*), void* arg); BAN::ErrorOr<long> sys_pthread_create(const pthread_attr_t* __restrict attr, void (*entry)(void*), void* arg);
BAN::ErrorOr<long> sys_pthread_exit(void* value); BAN::ErrorOr<long> sys_pthread_exit(void* value);
BAN::ErrorOr<long> sys_pthread_join(pthread_t thread, void** value);
BAN::ErrorOr<long> sys_pthread_self(); BAN::ErrorOr<long> sys_pthread_self();
BAN::ErrorOr<long> sys_tcgetpgrp(int fd); BAN::ErrorOr<long> sys_tcgetpgrp(int fd);
@ -296,10 +298,11 @@ namespace Kernel
struct pthread_info_t struct pthread_info_t
{ {
Thread* thread; pthread_t thread;
void* value; void* value;
}; };
BAN::Vector<pthread_info_t> m_exited_pthreads; BAN::Vector<pthread_info_t> m_exited_pthreads;
ThreadBlocker m_pthread_exit_blocker;
uint64_t m_alarm_interval_ns { 0 }; uint64_t m_alarm_interval_ns { 0 };
uint64_t m_alarm_wake_time_ns { 0 }; uint64_t m_alarm_wake_time_ns { 0 };

View File

@ -354,6 +354,8 @@ namespace Kernel
asm volatile("cli; 1: hlt; jmp 1b"); asm volatile("cli; 1: hlt; jmp 1b");
} }
Thread::current().save_sse();
ASSERT(InterruptController::get().is_in_service(IRQ_TIMER - IRQ_VECTOR_BASE)); ASSERT(InterruptController::get().is_in_service(IRQ_TIMER - IRQ_VECTOR_BASE));
InterruptController::get().eoi(IRQ_TIMER - IRQ_VECTOR_BASE); InterruptController::get().eoi(IRQ_TIMER - IRQ_VECTOR_BASE);
@ -365,6 +367,8 @@ namespace Kernel
auto& current_thread = Thread::current(); auto& current_thread = Thread::current();
if (current_thread.can_add_signal_to_execute()) if (current_thread.can_add_signal_to_execute())
current_thread.handle_signal(); current_thread.handle_signal();
Thread::current().load_sse();
} }
extern "C" void cpp_irq_handler(uint32_t irq) extern "C" void cpp_irq_handler(uint32_t irq)

View File

@ -2084,6 +2084,12 @@ namespace Kernel
return 0; return 0;
} }
BAN::ErrorOr<long> Process::sys_yield()
{
Processor::yield();
return 0;
}
BAN::ErrorOr<long> Process::sys_pthread_create(const pthread_attr_t* __restrict attr, void (*entry)(void*), void* arg) BAN::ErrorOr<long> Process::sys_pthread_create(const pthread_attr_t* __restrict attr, void (*entry)(void*), void* arg)
{ {
if (attr != nullptr) if (attr != nullptr)
@ -2109,11 +2115,12 @@ namespace Kernel
if (&Thread::current() == m_threads.front()) if (&Thread::current() == m_threads.front())
return BAN::Error::from_errno(EINVAL); return BAN::Error::from_errno(EINVAL);
TRY(m_exited_pthreads.emplace_back(&Thread::current(), value)); TRY(m_exited_pthreads.emplace_back(Thread::current().tid(), value));
for (auto* thread : m_threads) for (auto* thread : m_threads)
{ {
if (thread != &Thread::current()) if (thread != &Thread::current())
continue; continue;
m_pthread_exit_blocker.unblock();
m_process_lock.unlock(); m_process_lock.unlock();
thread->on_exit(); thread->on_exit();
} }
@ -2121,6 +2128,58 @@ namespace Kernel
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
BAN::ErrorOr<long> Process::sys_pthread_join(pthread_t thread, void** value)
{
LockGuard _(m_process_lock);
if (value)
TRY(validate_pointer_access(value, sizeof(void*), true));
if (thread == Thread::current().tid())
return BAN::Error::from_errno(EINVAL);
const auto wait_thread =
[&]() -> bool
{
for (size_t i = 0; i < m_exited_pthreads.size(); i++)
{
if (m_exited_pthreads[i].thread != thread)
continue;
if (value)
*value = m_exited_pthreads[i].value;
m_exited_pthreads.remove(i);
return true;
}
return false;
};
if (wait_thread())
return 0;
{
bool found = false;
for (auto* _thread : m_threads)
if (_thread->tid() == thread)
found = true;
if (!found)
return BAN::Error::from_errno(EINVAL);
}
for (;;)
{
{
LockFreeGuard _(m_process_lock);
m_pthread_exit_blocker.block_with_timeout_ms(100);
}
if (wait_thread())
return 0;
}
}
BAN::ErrorOr<long> Process::sys_pthread_self() BAN::ErrorOr<long> Process::sys_pthread_self()
{ {
return Thread::current().tid(); return Thread::current().tid();

View File

@ -34,6 +34,11 @@ namespace Kernel
return Thread::current().userspace_stack_top() - 4 * sizeof(uintptr_t); return Thread::current().userspace_stack_top() - 4 * sizeof(uintptr_t);
} }
extern "C" void load_thread_sse()
{
Thread::current().load_sse();
}
static pid_t s_next_tid = 1; static pid_t s_next_tid = 1;
alignas(16) static uint8_t s_default_sse_storage[512]; alignas(16) static uint8_t s_default_sse_storage[512];
@ -168,6 +173,7 @@ namespace Kernel
{ {
auto* thread = TRY(create_userspace(m_process, m_process->page_table())); auto* thread = TRY(create_userspace(m_process, m_process->page_table()));
save_sse();
memcpy(thread->m_sse_storage, m_sse_storage, sizeof(m_sse_storage)); memcpy(thread->m_sse_storage, m_sse_storage, sizeof(m_sse_storage));
thread->setup_exec_impl( thread->setup_exec_impl(
@ -202,6 +208,7 @@ namespace Kernel
thread->m_interrupt_stack.sp = sp; thread->m_interrupt_stack.sp = sp;
thread->m_interrupt_stack.ss = 0x10; thread->m_interrupt_stack.ss = 0x10;
save_sse();
memcpy(thread->m_sse_storage, m_sse_storage, sizeof(m_sse_storage)); memcpy(thread->m_sse_storage, m_sse_storage, sizeof(m_sse_storage));
#if ARCH(x86_64) #if ARCH(x86_64)

View File

@ -20,6 +20,7 @@ set(LIBC_SOURCES
pthread.cpp pthread.cpp
pwd.cpp pwd.cpp
scanf_impl.cpp scanf_impl.cpp
sched.cpp
setjmp.cpp setjmp.cpp
signal.cpp signal.cpp
stdio.cpp stdio.cpp

View File

@ -70,16 +70,16 @@ __BEGIN_DECLS
#endif #endif
#undef __need_pthread_rwlockattr_t #undef __need_pthread_rwlockattr_t
#if !defined(__pthread_spinlock_t_defined) && (defined(__need_all_types) || defined(__need_pthread_spinlock_t))
#define __pthread_spinlock_t_defined 1
typedef int pthread_spinlock_t;
#endif
#undef __need_pthread_spinlock_t
#if !defined(__pthread_t_defined) && (defined(__need_all_types) || defined(__need_pthread_t)) #if !defined(__pthread_t_defined) && (defined(__need_all_types) || defined(__need_pthread_t))
#define __pthread_t_defined 1 #define __pthread_t_defined 1
typedef int pthread_t; typedef pid_t pthread_t;
#endif #endif
#undef __need_pthread_t #undef __need_pthread_t
#if !defined(__pthread_spinlock_t_defined) && (defined(__need_all_types) || defined(__need_pthread_spinlock_t))
#define __pthread_spinlock_t_defined 1
typedef pthread_t pthread_spinlock_t;
#endif
#undef __need_pthread_spinlock_t
__END_DECLS __END_DECLS

View File

@ -90,8 +90,10 @@ __BEGIN_DECLS
O(SYS_FSYNC, fsync) \ O(SYS_FSYNC, fsync) \
O(SYS_SYMLINKAT, symlinkat) \ O(SYS_SYMLINKAT, symlinkat) \
O(SYS_HARDLINKAT, hardlinkat) \ O(SYS_HARDLINKAT, hardlinkat) \
O(SYS_YIELD, yield) \
O(SYS_PTHREAD_CREATE, pthread_create) \ O(SYS_PTHREAD_CREATE, pthread_create) \
O(SYS_PTHREAD_EXIT, pthread_exit) \ O(SYS_PTHREAD_EXIT, pthread_exit) \
O(SYS_PTHREAD_JOIN, pthread_join) \
O(SYS_PTHREAD_SELF, pthread_self) \ O(SYS_PTHREAD_SELF, pthread_self) \
enum Syscall enum Syscall

View File

@ -132,6 +132,10 @@ __BEGIN_DECLS
#endif #endif
#undef __need_off_t #undef __need_off_t
#ifdef __need_pthread_t
#define __need_pid_t
#endif
#if !defined(__pid_t_defined) && (defined(__need_all_types) || defined(__need_pid_t)) #if !defined(__pid_t_defined) && (defined(__need_all_types) || defined(__need_pid_t))
#define __pid_t_defined 1 #define __pid_t_defined 1
typedef int pid_t; typedef int pid_t;

View File

@ -1,5 +1,8 @@
#include <BAN/Assert.h> #include <BAN/Assert.h>
#include <BAN/Atomic.h>
#include <BAN/PlacementNew.h>
#include <errno.h>
#include <pthread.h> #include <pthread.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -12,7 +15,11 @@ struct pthread_trampoline_info_t
void* arg; void* arg;
}; };
static void pthread_trampoline(void* arg) // stack is 16 byte aligned on entry, this `call` is used to align it
extern "C" void pthread_trampoline(void*);
asm("pthread_trampoline: call pthread_trampoline_cpp");
extern "C" void pthread_trampoline_cpp(void* arg)
{ {
pthread_trampoline_info_t info; pthread_trampoline_info_t info;
memcpy(&info, arg, sizeof(pthread_trampoline_info_t)); memcpy(&info, arg, sizeof(pthread_trampoline_info_t));
@ -48,7 +55,71 @@ void pthread_exit(void* value_ptr)
ASSERT_NOT_REACHED(); ASSERT_NOT_REACHED();
} }
int pthread_join(pthread_t thread, void** value_ptr)
{
return syscall(SYS_PTHREAD_JOIN, thread, value_ptr);
}
pthread_t pthread_self(void) pthread_t pthread_self(void)
{ {
return syscall(SYS_PTHREAD_SELF); return syscall(SYS_PTHREAD_SELF);
} }
static inline BAN::Atomic<pthread_t>& pthread_spin_get_atomic(pthread_spinlock_t* lock)
{
static_assert(sizeof(pthread_spinlock_t) <= sizeof(BAN::Atomic<pthread_t>));
static_assert(alignof(pthread_spinlock_t) <= alignof(BAN::Atomic<pthread_t>));
return *reinterpret_cast<BAN::Atomic<pthread_t>*>(lock);
}
int pthread_spin_destroy(pthread_spinlock_t* lock)
{
pthread_spin_get_atomic(lock).~Atomic<pthread_t>();
return 0;
}
int pthread_spin_init(pthread_spinlock_t* lock, int pshared)
{
(void)pshared;
new (lock) BAN::Atomic<pthread_t>();
pthread_spin_get_atomic(lock) = false;
return 0;
}
int pthread_spin_lock(pthread_spinlock_t* lock)
{
auto& atomic = pthread_spin_get_atomic(lock);
const pthread_t tid = pthread_self();
ASSERT(atomic.load(BAN::MemoryOrder::memory_order_relaxed) != tid);
pthread_t expected = 0;
while (!atomic.compare_exchange(expected, tid, BAN::MemoryOrder::memory_order_acquire))
{
sched_yield();
expected = 0;
}
return 0;
}
int pthread_spin_trylock(pthread_spinlock_t* lock)
{
auto& atomic = pthread_spin_get_atomic(lock);
const pthread_t tid = pthread_self();
ASSERT(atomic.load(BAN::MemoryOrder::memory_order_relaxed) != tid);
pthread_t expected = 0;
if (atomic.compare_exchange(expected, tid, BAN::MemoryOrder::memory_order_acquire))
return 0;
return EBUSY;
}
int pthread_spin_unlock(pthread_spinlock_t* lock)
{
auto& atomic = pthread_spin_get_atomic(lock);
ASSERT(atomic.load(BAN::MemoryOrder::memory_order_relaxed) == pthread_self());
atomic.store(0, BAN::MemoryOrder::memory_order_release);
return 0;
}

View File

@ -0,0 +1,8 @@
#include <sched.h>
#include <sys/syscall.h>
#include <unistd.h>
int sched_yield(void)
{
return syscall(SYS_YIELD);
}

View File

@ -1,10 +1,12 @@
#include <BAN/Assert.h> #include <BAN/Assert.h>
#include <BAN/Debug.h> #include <BAN/Atomic.h>
#include <BAN/Math.h> #include <BAN/Math.h>
#include <BAN/PlacementNew.h>
#include <bits/printf.h> #include <bits/printf.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <pthread.h>
#include <scanf_impl.h> #include <scanf_impl.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdio.h> #include <stdio.h>
@ -31,7 +33,14 @@ struct FILE
unsigned char unget_buffer[12]; unsigned char unget_buffer[12];
uint32_t unget_buf_idx; uint32_t unget_buf_idx;
// TODO: use recursive pthread_mutex when implemented?
// this storage hack is to keep FILE pod (init order)
BAN::Atomic<pthread_t>& locker() { return *reinterpret_cast<BAN::Atomic<pthread_t>*>(locker_storage); }
unsigned char locker_storage[sizeof(pthread_t)];
uint32_t lock_depth;
}; };
static_assert(BAN::is_pod_v<FILE>);
struct ScopeLock struct ScopeLock
{ {
@ -88,8 +97,14 @@ static int drop_read_buffer(FILE* file)
void _init_stdio() void _init_stdio()
{ {
for (size_t i = 0; i < FOPEN_MAX; i++) for (size_t i = 0; i < FOPEN_MAX; i++)
{
init_closed_file(&s_files[i]); init_closed_file(&s_files[i]);
new (&s_files[i].locker()) BAN::Atomic<pthread_t>();
s_files[i].locker() = -1;
s_files[i].lock_depth = 0;
}
s_files[STDIN_FILENO].fd = STDIN_FILENO; s_files[STDIN_FILENO].fd = STDIN_FILENO;
s_files[STDIN_FILENO].mode = O_RDONLY; s_files[STDIN_FILENO].mode = O_RDONLY;
s_files[STDIN_FILENO].buffer_type = _IOLBF; s_files[STDIN_FILENO].buffer_type = _IOLBF;
@ -170,7 +185,6 @@ FILE* fdopen(int fd, const char* mode_str)
return nullptr; return nullptr;
} }
// FIXME: when threads are implemented
for (int i = 0; i < FOPEN_MAX; i++) for (int i = 0; i < FOPEN_MAX; i++)
{ {
ScopeLock _(&s_files[i]); ScopeLock _(&s_files[i]);
@ -292,9 +306,20 @@ int fileno(FILE* fp)
return fp->fd; return fp->fd;
} }
void flockfile(FILE*) void flockfile(FILE* fp)
{ {
// FIXME: when threads are implemented const pthread_t tid = pthread_self();
pthread_t expected = -1;
while (!fp->locker().compare_exchange(expected, tid, BAN::MemoryOrder::memory_order_acq_rel))
{
if (expected == tid)
break;
sched_yield();
expected = -1;
}
fp->lock_depth++;
} }
FILE* fopen(const char* pathname, const char* mode_str) FILE* fopen(const char* pathname, const char* mode_str)
@ -310,7 +335,6 @@ FILE* fopen(const char* pathname, const char* mode_str)
if (fd == -1) if (fd == -1)
return nullptr; return nullptr;
// FIXME: when threads are implemented
for (int i = 0; i < FOPEN_MAX; i++) for (int i = 0; i < FOPEN_MAX; i++)
{ {
ScopeLock _(&s_files[i]); ScopeLock _(&s_files[i]);
@ -458,15 +482,25 @@ off_t ftello(FILE* file)
return ret; return ret;
} }
int ftrylockfile(FILE*) int ftrylockfile(FILE* fp)
{ {
// FIXME: when threads are implemented const pthread_t tid = pthread_self();
pthread_t expected = -1;
if (!fp->locker().compare_exchange(expected, tid, BAN::MemoryOrder::memory_order_acq_rel))
if (expected != tid)
return 1;
fp->lock_depth++;
return 0; return 0;
} }
void funlockfile(FILE*) void funlockfile(FILE* fp)
{ {
// FIXME: when threads are implemented ASSERT(fp->locker() == pthread_self());
ASSERT(fp->lock_depth > 0);
if (--fp->lock_depth == 0)
fp->locker().store(-1, BAN::MemoryOrder::memory_order_release);
} }
size_t fwrite(const void* buffer, size_t size, size_t nitems, FILE* file) size_t fwrite(const void* buffer, size_t size, size_t nitems, FILE* file)
@ -706,7 +740,6 @@ FILE* popen(const char* command, const char* mode_str)
close(read ? fds[1] : fds[0]); close(read ? fds[1] : fds[0]);
// FIXME: when threads are implemented
for (int i = 0; i < FOPEN_MAX; i++) for (int i = 0; i < FOPEN_MAX; i++)
{ {
ScopeLock _(&s_files[i]); ScopeLock _(&s_files[i]);