LibC: Make pthread_t pointer to uthread instead of a thread id
This will allow getting info about other threads in userspace!
This commit is contained in:
@@ -431,52 +431,41 @@ namespace Kernel
|
||||
O_EXEC | O_RDWR
|
||||
));
|
||||
|
||||
BAN::Vector<uint8_t> temp_buffer;
|
||||
TRY(temp_buffer.resize(BAN::Math::min<size_t>(master_size, PAGE_SIZE)));
|
||||
|
||||
size_t bytes_copied = 0;
|
||||
while (bytes_copied < master_size)
|
||||
{
|
||||
const size_t to_copy = BAN::Math::min(master_size - bytes_copied, temp_buffer.size());
|
||||
uint8_t buffer[PAGE_SIZE];
|
||||
const size_t to_copy = BAN::Math::min(master_size - bytes_copied, sizeof(buffer));
|
||||
|
||||
const vaddr_t vaddr = master_addr + bytes_copied;
|
||||
const paddr_t paddr = page_table.physical_address_of(vaddr & PAGE_ADDR_MASK);
|
||||
PageTable::with_fast_page(paddr, [&] {
|
||||
memcpy(temp_buffer.data(), PageTable::fast_page_as_ptr(vaddr % PAGE_SIZE), to_copy);
|
||||
memcpy(buffer, PageTable::fast_page_as_ptr(vaddr % PAGE_SIZE), to_copy);
|
||||
});
|
||||
|
||||
TRY(region->copy_data_to_region(bytes_copied, temp_buffer.data(), to_copy));
|
||||
TRY(region->copy_data_to_region(bytes_copied, buffer, to_copy));
|
||||
bytes_copied += to_copy;
|
||||
}
|
||||
|
||||
auto uthread = TRY(BAN::UniqPtr<struct uthread>::create());
|
||||
*uthread = {
|
||||
.self = reinterpret_cast<struct uthread*>(region->vaddr() + master_size),
|
||||
.master_tls_addr = reinterpret_cast<void*>(master_addr),
|
||||
.master_tls_size = master_size,
|
||||
.master_tls_module_count = 1,
|
||||
.dynamic_tls = nullptr,
|
||||
.cleanup_stack = nullptr,
|
||||
.id = 0,
|
||||
.errno_ = 0,
|
||||
.cancel_type = 0,
|
||||
.cancel_state = 0,
|
||||
.canceled = 0,
|
||||
.specific_keys = {},
|
||||
.specific_values = {},
|
||||
.dtv = { 0, region->vaddr() }
|
||||
};
|
||||
uthread uthread {};
|
||||
uthread.self = reinterpret_cast<struct uthread*>(region->vaddr() + master_size);
|
||||
uthread.master_tls_addr = reinterpret_cast<void*>(master_addr),
|
||||
uthread.master_tls_size = master_size,
|
||||
uthread.master_tls_module_count = 1;
|
||||
uthread.dynamic_tls = nullptr;
|
||||
uthread.dtv[0] = 0;
|
||||
uthread.dtv[1] = region->vaddr();
|
||||
|
||||
TRY(region->copy_data_to_region(
|
||||
master_size,
|
||||
reinterpret_cast<const uint8_t*>(uthread.ptr()),
|
||||
reinterpret_cast<const uint8_t*>(&uthread),
|
||||
sizeof(struct uthread)
|
||||
));
|
||||
|
||||
TLSResult result;
|
||||
result.addr = region->vaddr() + master_size;;
|
||||
result.region = BAN::move(region);
|
||||
return result;
|
||||
return TLSResult {
|
||||
.region = BAN::move(region),
|
||||
.addr = region->vaddr() + master_size,
|
||||
};
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Process::add_mapped_region(BAN::UniqPtr<MemoryRegion>&& region)
|
||||
|
||||
@@ -7,10 +7,7 @@
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define __need_pid_t
|
||||
#include <sys/types.h>
|
||||
|
||||
typedef pid_t pthread_t;
|
||||
typedef struct uthread* pthread_t;
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
#define __need_pid_t
|
||||
#define __need_size_t
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <bits/types/pthread_attr_t.h>
|
||||
#include <bits/types/pthread_key_t.h>
|
||||
#include <bits/types/pthread_t.h>
|
||||
#include <limits.h>
|
||||
@@ -36,18 +38,24 @@ typedef struct _dynamic_tls_t
|
||||
struct uthread
|
||||
{
|
||||
struct uthread* self;
|
||||
|
||||
// TLS
|
||||
void* master_tls_addr;
|
||||
size_t master_tls_size;
|
||||
size_t master_tls_module_count;
|
||||
_dynamic_tls_t* dynamic_tls;
|
||||
_pthread_cleanup_t* cleanup_stack;
|
||||
pthread_t id;
|
||||
|
||||
// LIBC
|
||||
pid_t id;
|
||||
pthread_attr_t attr;
|
||||
int errno_;
|
||||
int cancel_type;
|
||||
int cancel_state;
|
||||
volatile int canceled;
|
||||
_pthread_cleanup_t* cleanup_funcs;
|
||||
pthread_key_t specific_keys[PTHREAD_KEYS_MAX];
|
||||
void* specific_values[PTHREAD_KEYS_MAX];
|
||||
void* specific_vals[PTHREAD_KEYS_MAX];
|
||||
|
||||
// FIXME: make this dynamic
|
||||
uintptr_t dtv[1 + 256];
|
||||
};
|
||||
|
||||
@@ -168,7 +168,7 @@ void pthread_cleanup_push(void (*routine)(void*), void* arg);
|
||||
|
||||
#define _pthread_equal(t1, t2) ((t1) == (t2))
|
||||
|
||||
#define _pthread_self() (_get_uthread()->id)
|
||||
#define _pthread_self() (_get_uthread())
|
||||
|
||||
#define _pthread_testcancel() do { \
|
||||
struct uthread* uthread = _get_uthread(); \
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
struct pthread_trampoline_info_t
|
||||
{
|
||||
struct uthread* uthread;
|
||||
bool detached;
|
||||
void* (*start_routine)(void*);
|
||||
void* arg;
|
||||
};
|
||||
@@ -61,8 +60,10 @@ asm(
|
||||
|
||||
extern "C" void _pthread_trampoline_cpp(void* arg)
|
||||
{
|
||||
auto info = *reinterpret_cast<pthread_trampoline_info_t*>(arg);
|
||||
auto info = *static_cast<pthread_trampoline_info_t*>(arg);
|
||||
|
||||
info.uthread->id = syscall(SYS_THREAD_GETID);
|
||||
|
||||
#if defined(__x86_64__)
|
||||
syscall(SYS_SET_FSBASE, info.uthread);
|
||||
#elif defined(__i686__)
|
||||
@@ -70,10 +71,14 @@ extern "C" void _pthread_trampoline_cpp(void* arg)
|
||||
#else
|
||||
#error
|
||||
#endif
|
||||
|
||||
// NOTE: we have to get id and set TLS to for free to be able to use pthread_self
|
||||
free(arg);
|
||||
|
||||
signal(SIGCANCEL, &_pthread_cancel_handler);
|
||||
if (info.detached)
|
||||
pthread_detach(info.uthread->id);
|
||||
if (info.uthread->attr.detachstate == PTHREAD_CREATE_DETACHED)
|
||||
pthread_detach(info.uthread);
|
||||
|
||||
pthread_exit(info.start_routine(info.arg));
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
@@ -115,10 +120,10 @@ static void free_uthread(uthread* uthread)
|
||||
void pthread_cleanup_pop(int execute)
|
||||
{
|
||||
uthread* uthread = _get_uthread();
|
||||
ASSERT(uthread->cleanup_stack);
|
||||
ASSERT(uthread->cleanup_funcs);
|
||||
|
||||
auto* cleanup = uthread->cleanup_stack;
|
||||
uthread->cleanup_stack = cleanup->next;
|
||||
auto* cleanup = uthread->cleanup_funcs;
|
||||
uthread->cleanup_funcs = cleanup->next;
|
||||
|
||||
if (execute)
|
||||
cleanup->routine(cleanup->arg);
|
||||
@@ -135,9 +140,9 @@ void pthread_cleanup_push(void (*routine)(void*), void* arg)
|
||||
|
||||
cleanup->routine = routine;
|
||||
cleanup->arg = arg;
|
||||
cleanup->next = uthread->cleanup_stack;
|
||||
cleanup->next = uthread->cleanup_funcs;
|
||||
|
||||
uthread->cleanup_stack = cleanup;
|
||||
uthread->cleanup_funcs = cleanup;
|
||||
}
|
||||
|
||||
static pthread_key_t s_pthread_key_current = 1;
|
||||
@@ -197,9 +202,9 @@ void* pthread_getspecific(pthread_key_t key)
|
||||
if (uthread->specific_keys[i] != key)
|
||||
{
|
||||
uthread->specific_keys[i] = key;
|
||||
uthread->specific_values[i] = nullptr;
|
||||
uthread->specific_vals[i] = nullptr;
|
||||
}
|
||||
ret = uthread->specific_values[i];
|
||||
ret = uthread->specific_vals[i];
|
||||
break;
|
||||
}
|
||||
pthread_spin_unlock(&s_pthread_key_lock);
|
||||
@@ -220,7 +225,7 @@ int pthread_setspecific(pthread_key_t key, const void* value)
|
||||
continue;
|
||||
if (uthread->specific_keys[i] != key)
|
||||
uthread->specific_keys[i] = key;
|
||||
uthread->specific_values[i] = const_cast<void*>(value);
|
||||
uthread->specific_vals[i] = const_cast<void*>(value);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
@@ -375,11 +380,16 @@ int pthread_attr_getstacksize(const pthread_attr_t* __restrict attr, size_t* __r
|
||||
|
||||
int pthread_attr_setstacksize(pthread_attr_t* attr, size_t stacksize)
|
||||
{
|
||||
if (stacksize < PTHREAD_STACK_MIN)
|
||||
return EINVAL;
|
||||
if (auto rem = stacksize % getpagesize())
|
||||
stacksize += getpagesize() - rem;
|
||||
attr->stackaddr = nullptr;
|
||||
attr->stacksize = stacksize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_create(pthread_t* __restrict thread_id, const pthread_attr_t* __restrict attr, void* (*start_routine)(void*), void* __restrict arg)
|
||||
int pthread_create(pthread_t* __restrict thread, const pthread_attr_t* __restrict attr, void* (*start_routine)(void*), void* __restrict arg)
|
||||
{
|
||||
auto* info = static_cast<pthread_trampoline_info_t*>(malloc(sizeof(pthread_trampoline_info_t)));
|
||||
if (info == nullptr)
|
||||
@@ -387,12 +397,11 @@ int pthread_create(pthread_t* __restrict thread_id, const pthread_attr_t* __rest
|
||||
|
||||
*info = {
|
||||
.uthread = nullptr,
|
||||
.detached = attr ? (attr->detachstate == PTHREAD_CREATE_DETACHED) : false,
|
||||
.start_routine = start_routine,
|
||||
.arg = arg,
|
||||
};
|
||||
|
||||
long syscall_ret = 0;
|
||||
uthread* result = nullptr;
|
||||
|
||||
{
|
||||
uthread* self = _get_uthread();
|
||||
@@ -413,14 +422,15 @@ int pthread_create(pthread_t* __restrict thread_id, const pthread_attr_t* __rest
|
||||
.master_tls_size = self->master_tls_size,
|
||||
.master_tls_module_count = self->master_tls_module_count,
|
||||
.dynamic_tls = self->dynamic_tls,
|
||||
.cleanup_stack = nullptr,
|
||||
.id = -1,
|
||||
.attr = attr ? *attr : s_default_pthread_attr,
|
||||
.errno_ = 0,
|
||||
.cancel_type = PTHREAD_CANCEL_DEFERRED,
|
||||
.cancel_state = PTHREAD_CANCEL_ENABLE,
|
||||
.canceled = 0,
|
||||
.cleanup_funcs = nullptr,
|
||||
.specific_keys = {},
|
||||
.specific_values = {},
|
||||
.specific_vals = {},
|
||||
.dtv = { self->dtv[0] }
|
||||
};
|
||||
|
||||
@@ -430,14 +440,14 @@ int pthread_create(pthread_t* __restrict thread_id, const pthread_attr_t* __rest
|
||||
uthread->dtv[i] = self->dtv[i] - self_addr + uthread_addr;
|
||||
|
||||
info->uthread = uthread;
|
||||
result = uthread;
|
||||
}
|
||||
|
||||
syscall_ret = syscall(SYS_THREAD_CREATE, _pthread_trampoline, info);
|
||||
if (syscall_ret == -1)
|
||||
if (syscall(SYS_THREAD_CREATE, _pthread_trampoline, info) == -1)
|
||||
goto pthread_create_error;
|
||||
|
||||
if (thread_id)
|
||||
*thread_id = syscall_ret;
|
||||
if (thread)
|
||||
*thread = result;
|
||||
return 0;
|
||||
|
||||
pthread_create_error:
|
||||
@@ -450,13 +460,17 @@ pthread_create_error:
|
||||
|
||||
int pthread_detach(pthread_t thread)
|
||||
{
|
||||
return syscall(SYS_THREAD_DETACH, thread);
|
||||
// FIXME: race if detached thread exits before assigning detachstate
|
||||
if (syscall(SYS_THREAD_DETACH, thread->id) == -1)
|
||||
return errno;
|
||||
thread->attr.detachstate = PTHREAD_CREATE_DETACHED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void pthread_exit(void* value_ptr)
|
||||
{
|
||||
uthread* uthread = _get_uthread();
|
||||
while (uthread->cleanup_stack)
|
||||
while (uthread->cleanup_funcs)
|
||||
pthread_cleanup_pop(1);
|
||||
|
||||
for (size_t iteration = 0; iteration < PTHREAD_DESTRUCTOR_ITERATIONS; iteration++)
|
||||
@@ -471,8 +485,8 @@ void pthread_exit(void* value_ptr)
|
||||
if (s_pthread_key_map[i] && uthread->specific_keys[i] == s_pthread_key_map[i])
|
||||
{
|
||||
destructor = s_pthread_key_destructors[i];
|
||||
value = uthread->specific_values[i];
|
||||
uthread->specific_values[i] = nullptr;
|
||||
value = uthread->specific_vals[i];
|
||||
uthread->specific_vals[i] = nullptr;
|
||||
}
|
||||
pthread_spin_unlock(&s_pthread_key_lock);
|
||||
|
||||
@@ -485,6 +499,7 @@ void pthread_exit(void* value_ptr)
|
||||
break;
|
||||
}
|
||||
|
||||
if (uthread->attr.detachstate == PTHREAD_CREATE_DETACHED)
|
||||
free_uthread(uthread);
|
||||
syscall(SYS_THREAD_EXIT, value_ptr);
|
||||
ASSERT_NOT_REACHED();
|
||||
@@ -492,11 +507,18 @@ void pthread_exit(void* value_ptr)
|
||||
|
||||
int pthread_join(pthread_t thread, void** value_ptr)
|
||||
{
|
||||
if (thread->attr.detachstate != PTHREAD_CREATE_JOINABLE)
|
||||
return EINVAL;
|
||||
|
||||
do {
|
||||
pthread_testcancel();
|
||||
errno = 0;
|
||||
} while (syscall(SYS_THREAD_JOIN, thread, value_ptr) == -1 && errno == EINTR);
|
||||
return errno;
|
||||
} while (syscall(SYS_THREAD_JOIN, thread->id, value_ptr) == -1 && errno == EINTR);
|
||||
|
||||
const int ret = errno;
|
||||
if (ret == 0)
|
||||
free_uthread(thread);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pthread_once(pthread_once_t* once_control, void (*init_routine)(void))
|
||||
@@ -802,7 +824,7 @@ int pthread_mutex_lock(pthread_mutex_t* mutex)
|
||||
|
||||
int pthread_mutex_trylock(pthread_mutex_t* mutex)
|
||||
{
|
||||
const uint32_t tid = pthread_self();
|
||||
const uint32_t tid = pthread_self()->id;
|
||||
|
||||
switch (mutex->attr.type)
|
||||
{
|
||||
@@ -831,7 +853,7 @@ int pthread_mutex_timedlock(pthread_mutex_t* __restrict mutex, const struct time
|
||||
if (const int ret = pthread_mutex_trylock(mutex); ret != EBUSY)
|
||||
return ret;
|
||||
|
||||
const uint32_t tid = pthread_self();
|
||||
const uint32_t tid = pthread_self()->id;
|
||||
|
||||
uint32_t expected = 0;
|
||||
while (!BAN::atomic_compare_exchange(mutex->futex, expected, tid, BAN::memory_order_acquire))
|
||||
@@ -854,7 +876,7 @@ int pthread_mutex_timedlock(pthread_mutex_t* __restrict mutex, const struct time
|
||||
|
||||
int pthread_mutex_unlock(pthread_mutex_t* mutex)
|
||||
{
|
||||
ASSERT(mutex->futex == static_cast<uint32_t>(pthread_self()));
|
||||
ASSERT(mutex->futex == static_cast<uint32_t>(pthread_self()->id));
|
||||
|
||||
mutex->lock_depth--;
|
||||
if (mutex->lock_depth == 0)
|
||||
|
||||
@@ -41,7 +41,7 @@ void psignal(int signum, const char* message)
|
||||
|
||||
int pthread_kill(pthread_t thread, int sig)
|
||||
{
|
||||
if (syscall(SYS_THREAD_KILL, thread, sig) == -1)
|
||||
if (syscall(SYS_THREAD_KILL, thread->id, sig) == -1)
|
||||
return errno;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -65,12 +65,12 @@ extern "C" void _init_libc(char** environ, init_funcs_t init_funcs, init_funcs_t
|
||||
#error
|
||||
#endif
|
||||
{
|
||||
self->cleanup_stack = nullptr;
|
||||
self->id = syscall(SYS_THREAD_GETID);
|
||||
self->errno_ = 0;
|
||||
self->cancel_type = PTHREAD_CANCEL_DEFERRED;
|
||||
self->cancel_state = PTHREAD_CANCEL_ENABLE;
|
||||
self->canceled = false;
|
||||
self->cleanup_funs = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -83,14 +83,14 @@ extern "C" void _init_libc(char** environ, init_funcs_t init_funcs, init_funcs_t
|
||||
.master_tls_size = 0,
|
||||
.master_tls_module_count = 1,
|
||||
.dynamic_tls = nullptr,
|
||||
.cleanup_stack = nullptr,
|
||||
.id = static_cast<pthread_t>(syscall(SYS_THREAD_GETID)),
|
||||
.errno_ = 0,
|
||||
.cancel_type = PTHREAD_CANCEL_DEFERRED,
|
||||
.cancel_state = PTHREAD_CANCEL_ENABLE,
|
||||
.canceled = false,
|
||||
.cleanup_funs = nullptr,
|
||||
.specific_keys = {},
|
||||
.specific_values = {},
|
||||
.specific_vals = {},
|
||||
.dtv = { 0 },
|
||||
};
|
||||
|
||||
|
||||
@@ -216,16 +216,16 @@ static _dynamic_tls_t* s_dynamic_tls = nullptr;
|
||||
|
||||
static const char* s_ld_library_path = nullptr;
|
||||
|
||||
static BAN::Atomic<pthread_t> s_global_locker = 0;
|
||||
static BAN::Atomic<pid_t> s_global_locker = 0;
|
||||
static uint32_t s_global_lock_depth = 0;
|
||||
|
||||
constexpr uintptr_t SYM_NOT_FOUND = -1;
|
||||
|
||||
static void lock_global_lock()
|
||||
{
|
||||
const pthread_t tid = syscall(SYS_THREAD_GETID);
|
||||
const pid_t tid = syscall(SYS_THREAD_GETID);
|
||||
|
||||
pthread_t expected = 0;
|
||||
pid_t expected = 0;
|
||||
while (!s_global_locker.compare_exchange(expected, tid))
|
||||
{
|
||||
if (expected == tid)
|
||||
@@ -1349,25 +1349,21 @@ static void initialize_tls(MasterTLS master_tls)
|
||||
memcpy(tls_addr, master_tls.addr, master_tls.size);
|
||||
|
||||
uthread& uthread = *reinterpret_cast<struct uthread*>(tls_addr + master_tls.size);
|
||||
memset(&uthread, 0, sizeof(uthread));
|
||||
|
||||
// uthread is prepared in libc init, but some other stuff may be calling pthread functions
|
||||
uthread.self = &uthread;
|
||||
uthread.master_tls_addr = master_tls.addr,
|
||||
uthread.master_tls_size = master_tls.size,
|
||||
uthread.master_tls_module_count = master_tls.module_count,
|
||||
uthread.dynamic_tls = s_dynamic_tls,
|
||||
|
||||
// these are prepared in libc init, but some other stuff may be calling pthread functions
|
||||
// for example __cxa_guard_release calls pthread_cond_broadcast
|
||||
uthread = {
|
||||
.self = &uthread,
|
||||
.master_tls_addr = master_tls.addr,
|
||||
.master_tls_size = master_tls.size,
|
||||
.master_tls_module_count = master_tls.module_count,
|
||||
.dynamic_tls = s_dynamic_tls,
|
||||
.cleanup_stack = nullptr,
|
||||
.id = static_cast<pthread_t>(syscall(SYS_THREAD_GETID)),
|
||||
.errno_ = 0,
|
||||
.cancel_type = PTHREAD_CANCEL_DEFERRED,
|
||||
.cancel_state = PTHREAD_CANCEL_ENABLE,
|
||||
.canceled = false,
|
||||
.specific_keys = {},
|
||||
.specific_values = {},
|
||||
.dtv = {},
|
||||
};
|
||||
uthread.id = syscall(SYS_THREAD_GETID);
|
||||
uthread.errno_ = 0;
|
||||
uthread.cancel_type = PTHREAD_CANCEL_DEFERRED;
|
||||
uthread.cancel_state = PTHREAD_CANCEL_ENABLE;
|
||||
uthread.canceled = false;
|
||||
|
||||
uthread.dtv[0] = master_tls.module_count;
|
||||
for (size_t i = 0; i < s_loaded_file_count; i++)
|
||||
|
||||
Reference in New Issue
Block a user