From 33a9a63787154facfdaddaf719e727947c159800 Mon Sep 17 00:00:00 2001 From: Jari Vetoniemi Date: Thu, 15 Feb 2018 00:59:08 +0200 Subject: Initial commit Stuff in src/linker will get rewritten from scratch eventually, it's all horrible. But for now focus is getting on shit work. --- src/libpthread.c | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 src/libpthread.c (limited to 'src/libpthread.c') diff --git a/src/libpthread.c b/src/libpthread.c new file mode 100644 index 0000000..3359c4a --- /dev/null +++ b/src/libpthread.c @@ -0,0 +1,178 @@ +#include +#include +#include +#include +#include +#include +#include + +typedef struct { + union { +#if defined(__LP64__) + int32_t __private[10]; +#else + int32_t __private[1]; +#endif + void *glibc; + }; +} bionic_mutex_t; + +typedef struct { + union { + long __private; + void *glibc; + }; +} bionic_mutexattr_t; + +static const struct { + bionic_mutex_t bionic; + pthread_mutex_t glibc; +} bionic_mutex_init_map[] = { + { .bionic = {{{ ((PTHREAD_MUTEX_NORMAL & 3) << 14) }}}, .glibc = PTHREAD_MUTEX_INITIALIZER }, + { .bionic = {{{ ((PTHREAD_MUTEX_RECURSIVE & 3) << 14) }}}, .glibc = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP }, + { .bionic = {{{ ((PTHREAD_MUTEX_ERRORCHECK & 3) << 14) }}}, .glibc = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP }, +}; + +typedef struct { + union { +#if defined(__LP64__) + int32_t __private[12]; +#else + int32_t __private[1]; +#endif + void *glibc; + }; +} bionic_cond_t; + +typedef struct { + union { + long __private; + void *glibc; + }; +} bionic_condattr_t; + +typedef int bionic_key_t; + +_Static_assert(sizeof(bionic_key_t) == sizeof(pthread_key_t), "bionic_key_t and pthread_key_t size mismatch"); + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) +#define IS_MAPPED(x) is_mapped(x->glibc, sizeof(x)) +#define INIT_IF_NOT_MAPPED(x, init) do { if (!IS_MAPPED(x)) init(x); } while(0) + +static bool +is_mapped(void *mem, const size_t sz) +{ + const size_t ps = sysconf(_SC_PAGESIZE); + assert(ps > 0); + unsigned char vec[(sz + ps - 1) / ps]; + return !mincore(mem, sz, vec); +} + +int +bionic_pthread_cond_timedwait_monotonic_np(bionic_cond_t *cond, bionic_mutex_t *mutex, const struct timespec *abstime) +{ + return 0; +} + +int +bionic_pthread_mutexattr_settype(bionic_mutexattr_t *attr, int type) +{ + assert(attr && IS_MAPPED(attr)); + return pthread_mutexattr_settype(attr->glibc, type); +} + +int +bionic_pthread_mutexattr_destroy(bionic_mutexattr_t *attr) +{ + assert(attr); + int ret = 0; + if (IS_MAPPED(attr)) { + ret = pthread_mutexattr_destroy(attr->glibc); + munmap(attr->glibc, sizeof(pthread_mutexattr_t)); + } + return ret; +} + +int +bionic_pthread_mutexattr_init(bionic_mutexattr_t *attr) +{ + assert(attr); + if (!IS_MAPPED(attr)) + attr->glibc = mmap(NULL, sizeof(pthread_mutexattr_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); + return pthread_mutexattr_init(attr->glibc); +} + +int +bionic_pthread_mutex_destroy(bionic_mutex_t *mutex) +{ + assert(mutex); + int ret = 0; + if (IS_MAPPED(mutex)) { + ret = pthread_mutex_destroy(mutex->glibc); + munmap(mutex->glibc, sizeof(pthread_mutex_t)); + } + return ret; +} + +int +bionic_pthread_mutex_init(bionic_mutex_t *mutex, const bionic_mutexattr_t *attr) +{ + assert(mutex && (!attr || IS_MAPPED(attr))); + if (!IS_MAPPED(mutex)) + mutex->glibc = mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); + return pthread_mutex_init(mutex->glibc, (attr ? attr->glibc : NULL)); +} + +static void +default_pthread_mutex_init(bionic_mutex_t *mutex) +{ + assert(mutex && !IS_MAPPED(mutex)); + mutex->glibc = mmap(NULL, sizeof(pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); + + for (size_t i = 0; i < ARRAY_SIZE(bionic_mutex_init_map); ++i) { + if (!memcmp(&bionic_mutex_init_map[i].bionic, mutex, sizeof(*mutex))) + continue; + + memcpy(mutex->glibc, &bionic_mutex_init_map[i].glibc, sizeof(bionic_mutex_init_map[i].glibc)); + return; + } + + assert(0 && "no such default initializer???"); +} + +int +bionic_pthread_mutex_lock(bionic_mutex_t *mutex) +{ + assert(mutex); + INIT_IF_NOT_MAPPED(mutex, default_pthread_mutex_init); + return pthread_mutex_lock(mutex->glibc); +} + +int +bionic_pthread_cond_destroy(bionic_cond_t *cond) +{ + assert(cond); + int ret = 0; + if (IS_MAPPED(cond)) { + ret = pthread_cond_destroy(cond->glibc); + munmap(cond->glibc, sizeof(pthread_cond_t)); + } + return ret; +} + +int +bionic_pthread_cond_init(bionic_cond_t *cond, const bionic_condattr_t *attr) +{ + assert(cond && (!attr || IS_MAPPED(attr))); + if (!IS_MAPPED(cond)) + cond->glibc = mmap(NULL, sizeof(pthread_cond_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); + return pthread_cond_init(cond->glibc, (attr ? attr->glibc : NULL)); +} + +static void +default_pthread_cond_init(bionic_cond_t *cond) +{ + assert(cond && !IS_MAPPED(cond)); + cond->glibc = mmap(NULL, sizeof(pthread_cond_t), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0); + memset(cond->glibc, 0, sizeof(pthread_cond_t)); +} -- cgit v1.2.3