diff options
author | Andrew Kaster <andrewdkaster@gmail.com> | 2019-11-17 20:08:10 -0700 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-11-18 09:04:32 +0100 |
commit | 618aebdd8ab55f9b63256e8195fa4e0f6fe305aa (patch) | |
tree | c076bbff894ee4f0151ae91049d62bad1e499d32 /Libraries/LibPthread | |
parent | aae26a3a1ec059ca16cb7930f4f78b908ec6e8a1 (diff) | |
download | serenity-618aebdd8ab55f9b63256e8195fa4e0f6fe305aa.zip |
Kernel+LibPthread: pthread_create handles pthread_attr_t
Add an initial implementation of pthread attributes for:
* detach state (joinable, detached)
* schedule params (just priority)
* guard page size (as skeleton) (requires kernel support maybe?)
* stack size and user-provided stack location (4 or 8 MB only, must be aligned)
Add some tests too, to the thread test program.
Also, LibC: Move pthread declarations to sys/types.h, where they belong.
Diffstat (limited to 'Libraries/LibPthread')
-rw-r--r-- | Libraries/LibPthread/pthread.cpp | 266 | ||||
-rw-r--r-- | Libraries/LibPthread/pthread.h | 30 |
2 files changed, 280 insertions, 16 deletions
diff --git a/Libraries/LibPthread/pthread.cpp b/Libraries/LibPthread/pthread.cpp index ba844ce400..2057a25554 100644 --- a/Libraries/LibPthread/pthread.cpp +++ b/Libraries/LibPthread/pthread.cpp @@ -2,11 +2,22 @@ #include <AK/Atomic.h> #include <AK/StdLibExtras.h> #include <Kernel/Syscall.h> +#include <limits.h> #include <pthread.h> #include <stdio.h> #include <sys/mman.h> #include <unistd.h> +#define PTHREAD_DEBUG + +namespace { +using PthreadAttrImpl = Syscall::SC_create_thread_params; +} // end anonymous namespace + +constexpr size_t required_stack_alignment = 4 * MB; +constexpr size_t highest_reasonable_guard_size = 32 * PAGE_SIZE; +constexpr size_t highest_reasonable_stack_size = 8 * MB; // That's the default in Ubuntu? + extern "C" { static int create_thread(void* (*entry)(void*), void* argument, void* stack) @@ -25,12 +36,33 @@ int pthread_create(pthread_t* thread, pthread_attr_t* attributes, void* (*start_ { if (!thread) return -EINVAL; - UNUSED_PARAM(attributes); - const size_t stack_size = 4 * MB; - auto* stack = (u8*)mmap_with_name(nullptr, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 0, 0, "Thread stack"); - if (!stack) - return -1; - int rc = create_thread(start_routine, argument_to_start_routine, stack + stack_size); + + PthreadAttrImpl default_attributes {}; + PthreadAttrImpl** arg_attributes = reinterpret_cast<PthreadAttrImpl**>(attributes); + + PthreadAttrImpl* used_attributes = arg_attributes ? *arg_attributes : &default_attributes; + + if (!used_attributes->m_stack_location) { + // adjust stack size, user might have called setstacksize, which has no restrictions on size/alignment + if (0 != (used_attributes->m_stack_size % required_stack_alignment)) + used_attributes->m_stack_size += required_stack_alignment - (used_attributes->m_stack_size % required_stack_alignment); + + used_attributes->m_stack_location = mmap_with_name(nullptr, used_attributes->m_stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, 0, 0, "Thread stack"); + if (!used_attributes->m_stack_location) + return -1; + } + +#ifdef PTHREAD_DEBUG + printf("pthread_create: Creating thread with attributes at %p, detach state %s, priority %d, guard page size %d, stack size %d, stack location %p\n", + used_attributes, + (PTHREAD_CREATE_JOINABLE == used_attributes->m_detach_state) ? "joinable" : "detached", + used_attributes->m_schedule_priority, + used_attributes->m_guard_page_size, + used_attributes->m_stack_size, + used_attributes->m_stack_location); +#endif + + int rc = create_thread(start_routine, argument_to_start_routine, used_attributes); if (rc < 0) return rc; *thread = rc; @@ -73,4 +105,226 @@ int pthread_mutex_unlock(pthread_mutex_t* mutex) atomic->store(false, AK::memory_order_release); return 0; } + +int pthread_attr_init(pthread_attr_t* attributes) +{ + auto* impl = new PthreadAttrImpl {}; + *attributes = impl; + +#ifdef PTHREAD_DEBUG + printf("pthread_attr_init: New thread attributes at %p, detach state %s, priority %d, guard page size %d, stack size %d, stack location %p\n", + impl, + (PTHREAD_CREATE_JOINABLE == impl->m_detach_state) ? "joinable" : "detached", + impl->m_schedule_priority, + impl->m_guard_page_size, + impl->m_stack_size, + impl->m_stack_location); +#endif + + return 0; +} + +int pthread_attr_destroy(pthread_attr_t* attributes) +{ + auto* attributes_impl = *(reinterpret_cast<PthreadAttrImpl**>(attributes)); + delete attributes_impl; + return 0; +} + +int pthread_attr_getdetachstate(const pthread_attr_t* attributes, int* p_detach_state) +{ + auto* attributes_impl = *(reinterpret_cast<const PthreadAttrImpl* const*>(attributes)); + + if (!attributes_impl || !p_detach_state) + return EINVAL; + + *p_detach_state = attributes_impl->m_detach_state; + return 0; +} + +int pthread_attr_setdetachstate(pthread_attr_t* attributes, int detach_state) +{ + auto* attributes_impl = *(reinterpret_cast<PthreadAttrImpl**>(attributes)); + + if (!attributes_impl) + return EINVAL; + + if ((PTHREAD_CREATE_JOINABLE != detach_state) || PTHREAD_CREATE_DETACHED != detach_state) + return EINVAL; + + attributes_impl->m_detach_state = detach_state; + +#ifdef PTHREAD_DEBUG + printf("pthread_attr_setdetachstate: Thread attributes at %p, detach state %s, priority %d, guard page size %d, stack size %d, stack location %p\n", + attributes_impl, + (PTHREAD_CREATE_JOINABLE == attributes_impl->m_detach_state) ? "joinable" : "detached", + attributes_impl->m_schedule_priority, + attributes_impl->m_guard_page_size, + attributes_impl->m_stack_size, + attributes_impl->m_stack_location); +#endif + + return 0; +} + +int pthread_attr_getguardsize(const pthread_attr_t* attributes, size_t* p_guard_size) +{ + auto* attributes_impl = *(reinterpret_cast<const PthreadAttrImpl* const*>(attributes)); + + if (!attributes_impl || !p_guard_size) + return EINVAL; + + *p_guard_size = attributes_impl->m_reported_guard_page_size; + return 0; +} + +int pthread_attr_setguardsize(pthread_attr_t* attributes, size_t guard_size) +{ + auto* attributes_impl = *(reinterpret_cast<PthreadAttrImpl**>(attributes)); + + if (!attributes_impl) + return EINVAL; + + size_t actual_guard_size = guard_size; + // round up + if (0 != (guard_size % PAGE_SIZE)) + actual_guard_size += PAGE_SIZE - (guard_size % PAGE_SIZE); + + // what is the user even doing? + if (actual_guard_size > highest_reasonable_guard_size) { + return EINVAL; + } + + attributes_impl->m_guard_page_size = actual_guard_size; + attributes_impl->m_reported_guard_page_size = guard_size; // POSIX, why? + +#ifdef PTHREAD_DEBUG + printf("pthread_attr_setguardsize: Thread attributes at %p, detach state %s, priority %d, guard page size %d, stack size %d, stack location %p\n", + attributes_impl, + (PTHREAD_CREATE_JOINABLE == attributes_impl->m_detach_state) ? "joinable" : "detached", + attributes_impl->m_schedule_priority, + attributes_impl->m_guard_page_size, + attributes_impl->m_stack_size, + attributes_impl->m_stack_location); +#endif + + return 0; +} + +int pthread_attr_getschedparam(const pthread_attr_t* attributes, struct sched_param* p_sched_param) +{ + auto* attributes_impl = *(reinterpret_cast<const PthreadAttrImpl* const*>(attributes)); + + if (!attributes_impl || !p_sched_param) + return EINVAL; + + p_sched_param->sched_priority = attributes_impl->m_schedule_priority; + return 0; +} + +int pthread_attr_setschedparam(pthread_attr_t* attributes, const struct sched_param* p_sched_param) +{ + auto* attributes_impl = *(reinterpret_cast<PthreadAttrImpl**>(attributes)); + if (!attributes_impl || !p_sched_param) + return EINVAL; + + // NOTE: This must track sched_get_priority_[min,max] and ThreadPriority enum in Thread.h + if (p_sched_param->sched_priority < 0 || p_sched_param->sched_priority > 3) + return ENOTSUP; + + attributes_impl->m_schedule_priority = p_sched_param->sched_priority; + +#ifdef PTHREAD_DEBUG + printf("pthread_attr_setschedparam: Thread attributes at %p, detach state %s, priority %d, guard page size %d, stack size %d, stack location %p\n", + attributes_impl, + (PTHREAD_CREATE_JOINABLE == attributes_impl->m_detach_state) ? "joinable" : "detached", + attributes_impl->m_schedule_priority, + attributes_impl->m_guard_page_size, + attributes_impl->m_stack_size, + attributes_impl->m_stack_location); +#endif + + return 0; +} + +int pthread_attr_getstack(const pthread_attr_t* attributes, void** p_stack_ptr, size_t* p_stack_size) +{ + auto* attributes_impl = *(reinterpret_cast<const PthreadAttrImpl* const*>(attributes)); + + if (!attributes_impl || !p_stack_ptr || !p_stack_size) + return EINVAL; + + *p_stack_ptr = attributes_impl->m_stack_location; + *p_stack_size = attributes_impl->m_stack_size; + + return 0; +} + +int pthread_attr_setstack(pthread_attr_t* attributes, void* p_stack, size_t stack_size) +{ + auto* attributes_impl = *(reinterpret_cast<PthreadAttrImpl**>(attributes)); + + if (!attributes_impl || !p_stack) + return EINVAL; + + // Check for required alignment on size + if (0 != (stack_size % required_stack_alignment)) + return EINVAL; + + // FIXME: Check for required alignment on pointer? + + // FIXME: "[EACCES] The stack page(s) described by stackaddr and stacksize are not both readable and writable by the thread." + // Have to check that the whole range is mapped to this process/thread? Can we defer this to create_thread? + + attributes_impl->m_stack_size = stack_size; + attributes_impl->m_stack_location = p_stack; + +#ifdef PTHREAD_DEBUG + printf("pthread_attr_setstack: Thread attributes at %p, detach state %s, priority %d, guard page size %d, stack size %d, stack location %p\n", + attributes_impl, + (PTHREAD_CREATE_JOINABLE == attributes_impl->m_detach_state) ? "joinable" : "detached", + attributes_impl->m_schedule_priority, + attributes_impl->m_guard_page_size, + attributes_impl->m_stack_size, + attributes_impl->m_stack_location); +#endif + + return 0; +} + +int pthread_attr_getstacksize(const pthread_attr_t* attributes, size_t* p_stack_size) +{ + auto* attributes_impl = *(reinterpret_cast<const PthreadAttrImpl* const*>(attributes)); + + if (!attributes_impl || !p_stack_size) + return EINVAL; + + *p_stack_size = attributes_impl->m_stack_size; + return 0; +} + +int pthread_attr_setstacksize(pthread_attr_t* attributes, size_t stack_size) +{ + auto* attributes_impl = *(reinterpret_cast<PthreadAttrImpl**>(attributes)); + + if (!attributes_impl) + return EINVAL; + + if ((stack_size < PTHREAD_STACK_MIN) || stack_size > highest_reasonable_stack_size) + return EINVAL; + + attributes_impl->m_stack_size = stack_size; + +#ifdef PTHREAD_DEBUG + printf("pthread_attr_setstacksize: Thread attributes at %p, detach state %s, priority %d, guard page size %d, stack size %d, stack location %p\n", + attributes_impl, + (PTHREAD_CREATE_JOINABLE == attributes_impl->m_detach_state) ? "joinable" : "detached", + attributes_impl->m_schedule_priority, + attributes_impl->m_guard_page_size, + attributes_impl->m_stack_size, + attributes_impl->m_stack_location); +#endif + + return 0; +} } diff --git a/Libraries/LibPthread/pthread.h b/Libraries/LibPthread/pthread.h index 5320a88539..f5e02767f8 100644 --- a/Libraries/LibPthread/pthread.h +++ b/Libraries/LibPthread/pthread.h @@ -3,19 +3,10 @@ #include <sched.h> #include <stdint.h> #include <sys/cdefs.h> +#include <sys/types.h> __BEGIN_DECLS -typedef int pthread_t; -typedef void* pthread_key_t; -typedef void* pthread_once_t; -typedef uint32_t pthread_mutex_t; -typedef void* pthread_attr_t; -typedef void* pthread_mutexattr_t; -typedef void* pthread_cond_t; -typedef void* pthread_spinlock_t; -typedef void* pthread_condattr_t; - int pthread_create(pthread_t*, pthread_attr_t*, void* (*)(void*), void*); void pthread_exit(void*); int pthread_kill(pthread_t, int); @@ -27,9 +18,28 @@ int pthread_mutex_trylock(pthread_mutex_t* mutex); int pthread_mutex_unlock(pthread_mutex_t*); int pthread_mutex_init(pthread_mutex_t*, const pthread_mutexattr_t*); int pthread_mutex_destroy(pthread_mutex_t*); + int pthread_attr_init(pthread_attr_t*); int pthread_attr_destroy(pthread_attr_t*); +#define PTHREAD_CREATE_JOINABLE 0 +#define PTHREAD_CREATE_DETACHED 1 + +int pthread_attr_getdetachstate(const pthread_attr_t*, int*); +int pthread_attr_setdetachstate(pthread_attr_t*, int); + +int pthread_attr_getguardsize(const pthread_attr_t*, size_t*); +int pthread_attr_setguardsize(pthread_attr_t*, size_t); + +int pthread_attr_getschedparam(const pthread_attr_t*, struct sched_param*); +int pthread_attr_setschedparam(pthread_attr_t*, const struct sched_param*); + +int pthread_attr_getstack(const pthread_attr_t*, void**, size_t*); +int pthread_attr_setstack(pthread_attr_t* attr, void*, size_t); + +int pthread_attr_getstacksize(const pthread_attr_t*, size_t*); +int pthread_attr_setstacksize(pthread_attr_t*, size_t); + int pthread_once(pthread_once_t*, void (*)(void)); #define PTHREAD_ONCE_INIT 0 void* pthread_getspecific(pthread_key_t key); |