lib: c: add pthread implementation
This commit is contained in:
24
lib/libc/pthread/thread/pthread.h
Normal file
24
lib/libc/pthread/thread/pthread.h
Normal file
@@ -0,0 +1,24 @@
|
||||
#ifndef _THREAD_PTHREAD_H_
|
||||
#define _THREAD_PTHREAD_H_
|
||||
|
||||
#include <mango/types.h>
|
||||
|
||||
enum pthread_flags {
|
||||
THREAD_DETACHED = 0x01u,
|
||||
};
|
||||
|
||||
struct __pthread {
|
||||
struct __pthread *thr_self;
|
||||
enum pthread_flags thr_flags;
|
||||
kern_handle_t thr_handle;
|
||||
void *thr_map_base;
|
||||
size_t thr_map_size;
|
||||
void *thr_result;
|
||||
};
|
||||
|
||||
extern void __pthread_unmap_exit(
|
||||
kern_handle_t address_space,
|
||||
void *unmap_base,
|
||||
size_t unmap_length);
|
||||
|
||||
#endif
|
||||
0
lib/libc/pthread/thread/pthread_attr.h
Normal file
0
lib/libc/pthread/thread/pthread_attr.h
Normal file
89
lib/libc/pthread/thread/pthread_create.c
Normal file
89
lib/libc/pthread/thread/pthread_create.c
Normal file
@@ -0,0 +1,89 @@
|
||||
#include "pthread.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <mango/status.h>
|
||||
#include <mango/task.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define DEFAULT_STACK_SIZE 0x40000
|
||||
|
||||
static void thread_launchpad(uintptr_t thread, uintptr_t func, uintptr_t arg)
|
||||
{
|
||||
struct __pthread *self = (struct __pthread *)thread;
|
||||
void *(*start_func)(void *) = (void *(*)(void *))func;
|
||||
|
||||
void *result = start_func((void *)arg);
|
||||
|
||||
pthread_exit(result);
|
||||
}
|
||||
|
||||
int pthread_create(
|
||||
pthread_t *thread,
|
||||
const pthread_attr_t *attr,
|
||||
void *(*start_func)(void *),
|
||||
void *arg)
|
||||
{
|
||||
kern_status_t status = KERN_OK;
|
||||
kern_handle_t task;
|
||||
|
||||
status = task_self(&task);
|
||||
if (status != KERN_OK) {
|
||||
return __set_errno(EPERM);
|
||||
}
|
||||
|
||||
size_t stack_size = DEFAULT_STACK_SIZE;
|
||||
|
||||
void *base
|
||||
= mmap(NULL,
|
||||
stack_size,
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1,
|
||||
0);
|
||||
|
||||
if (!base) {
|
||||
return __set_errno(ENOMEM);
|
||||
}
|
||||
|
||||
virt_addr_t sp = (virt_addr_t)base + DEFAULT_STACK_SIZE;
|
||||
|
||||
sp -= sizeof(struct __pthread);
|
||||
struct __pthread *new = (struct __pthread *)sp;
|
||||
sp &= ~(virt_addr_t)0x10;
|
||||
|
||||
memset(new, 0x0, sizeof *new);
|
||||
new->thr_self = new;
|
||||
new->thr_map_base = base;
|
||||
new->thr_map_size = stack_size;
|
||||
|
||||
uintptr_t args[] = {
|
||||
(uintptr_t)new,
|
||||
(uintptr_t)start_func,
|
||||
(uintptr_t)arg,
|
||||
};
|
||||
size_t nr_args = sizeof args / sizeof args[0];
|
||||
|
||||
status = task_create_thread(
|
||||
task,
|
||||
(virt_addr_t)thread_launchpad,
|
||||
sp,
|
||||
args,
|
||||
nr_args,
|
||||
&new->thr_handle);
|
||||
if (status != KERN_OK) {
|
||||
munmap(base, stack_size);
|
||||
return __set_errno(__errno_from_kern_status(status));
|
||||
}
|
||||
|
||||
thread_config_set(
|
||||
new->thr_handle,
|
||||
THREAD_CFG_GSBASE,
|
||||
&new,
|
||||
sizeof(void *));
|
||||
thread_start(new->thr_handle);
|
||||
|
||||
*thread = new;
|
||||
return __set_errno(SUCCESS);
|
||||
}
|
||||
17
lib/libc/pthread/thread/pthread_detach.c
Normal file
17
lib/libc/pthread/thread/pthread_detach.c
Normal file
@@ -0,0 +1,17 @@
|
||||
#include "pthread.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <mango/handle.h>
|
||||
#include <mango/object.h>
|
||||
#include <mango/signal.h>
|
||||
#include <mango/task.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
int pthread_detach(struct __pthread *thread)
|
||||
{
|
||||
thread->thr_flags |= THREAD_DETACHED;
|
||||
kern_handle_close(thread->thr_handle);
|
||||
|
||||
return 0;
|
||||
}
|
||||
31
lib/libc/pthread/thread/pthread_exit.c
Normal file
31
lib/libc/pthread/thread/pthread_exit.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "pthread.h"
|
||||
|
||||
#include <mango/handle.h>
|
||||
#include <mango/task.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern void pthread_exit(void *retval)
|
||||
{
|
||||
struct __pthread *self = pthread_self();
|
||||
if (!self) {
|
||||
/* TODO: abort(); */
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->thr_flags & THREAD_DETACHED) {
|
||||
kern_handle_t task;
|
||||
kern_handle_t address_space;
|
||||
task_self(&task);
|
||||
task_get_address_space(task, &address_space);
|
||||
kern_handle_close(task);
|
||||
|
||||
__pthread_unmap_exit(
|
||||
address_space,
|
||||
self->thr_map_base,
|
||||
self->thr_map_size);
|
||||
} else {
|
||||
self->thr_result = retval;
|
||||
thread_exit();
|
||||
}
|
||||
}
|
||||
31
lib/libc/pthread/thread/pthread_join.c
Normal file
31
lib/libc/pthread/thread/pthread_join.c
Normal file
@@ -0,0 +1,31 @@
|
||||
#include "pthread.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <mango/handle.h>
|
||||
#include <mango/object.h>
|
||||
#include <mango/signal.h>
|
||||
#include <mango/task.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
int pthread_join(struct __pthread *thread, void **retval)
|
||||
{
|
||||
kern_wait_item_t wait;
|
||||
wait.w_handle = thread->thr_handle;
|
||||
wait.w_waitfor = THREAD_SIGNAL_STOPPED;
|
||||
wait.w_observed = 0;
|
||||
|
||||
kern_status_t status = kern_object_wait(&wait, 1);
|
||||
if (status != KERN_OK) {
|
||||
return __set_errno(EINVAL);
|
||||
}
|
||||
|
||||
if (retval) {
|
||||
*retval = thread->thr_result;
|
||||
}
|
||||
|
||||
kern_handle_close(thread->thr_handle);
|
||||
munmap(thread->thr_map_base, thread->thr_map_size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
0
lib/libc/pthread/thread/pthread_self.c
Normal file
0
lib/libc/pthread/thread/pthread_self.c
Normal file
Reference in New Issue
Block a user