LibC: Implement basic pthread mutexes

This implementation is just calling sched_yield if it could not get
mutex. This is not optimal as it does not allow the CPU to idle, but it
works for now :)

Also I did not test this code at all, but it feels correct :D
This commit is contained in:
Bananymous 2025-04-20 03:01:33 +03:00
parent 3642eabac0
commit db9db2cc40
3 changed files with 198 additions and 21 deletions

View File

@ -40,18 +40,24 @@ __BEGIN_DECLS
#endif #endif
#undef __need_pthread_key_t #undef __need_pthread_key_t
#if !defined(__pthread_mutex_t_defined) && (defined(__need_all_types) || defined(__need_pthread_mutex_t)) #if !defined(__pthread_t_defined) && (defined(__need_all_types) || defined(__need_pthread_t))
#define __pthread_mutex_t_defined 1 #define __pthread_t_defined 1
typedef int pthread_mutex_t; typedef pid_t pthread_t;
#endif #endif
#undef __need_pthread_mutex_t #undef __need_pthread_t
#if !defined(__pthread_mutexattr_t_defined) && (defined(__need_all_types) || defined(__need_pthread_mutexattr_t)) #if !defined(__pthread_mutexattr_t_defined) && (defined(__need_all_types) || defined(__need_pthread_mutexattr_t))
#define __pthread_mutexattr_t_defined 1 #define __pthread_mutexattr_t_defined 1
typedef int pthread_mutexattr_t; typedef struct { int type; bool shared; } pthread_mutexattr_t;
#endif #endif
#undef __need_pthread_mutexattr_t #undef __need_pthread_mutexattr_t
#if !defined(__pthread_mutex_t_defined) && (defined(__need_all_types) || defined(__need_pthread_mutex_t))
#define __pthread_mutex_t_defined 1
typedef struct { pthread_mutexattr_t attr; pthread_t locker; unsigned lock_depth; } pthread_mutex_t;
#endif
#undef __need_pthread_mutex_t
#if !defined(__pthread_once_t_defined) && (defined(__need_all_types) || defined(__need_pthread_once_t)) #if !defined(__pthread_once_t_defined) && (defined(__need_all_types) || defined(__need_pthread_once_t))
#define __pthread_once_t_defined 1 #define __pthread_once_t_defined 1
typedef int pthread_once_t; typedef int pthread_once_t;
@ -70,12 +76,6 @@ __BEGIN_DECLS
#endif #endif
#undef __need_pthread_rwlockattr_t #undef __need_pthread_rwlockattr_t
#if !defined(__pthread_t_defined) && (defined(__need_all_types) || defined(__need_pthread_t))
#define __pthread_t_defined 1
typedef pid_t pthread_t;
#endif
#undef __need_pthread_t
#if !defined(__pthread_spinlock_t_defined) && (defined(__need_all_types) || defined(__need_pthread_spinlock_t)) #if !defined(__pthread_spinlock_t_defined) && (defined(__need_all_types) || defined(__need_pthread_spinlock_t))
#define __pthread_spinlock_t_defined 1 #define __pthread_spinlock_t_defined 1
typedef pthread_t pthread_spinlock_t; typedef pthread_t pthread_spinlock_t;

View File

@ -46,23 +46,26 @@ struct uthread
#define PTHREAD_CREATE_JOINABLE 8 #define PTHREAD_CREATE_JOINABLE 8
#define PTHREAD_EXPLICIT_SCHED 9 #define PTHREAD_EXPLICIT_SCHED 9
#define PTHREAD_INHERIT_SCHED 10 #define PTHREAD_INHERIT_SCHED 10
#define PTHREAD_MUTEX_DEFAULT 11
#define PTHREAD_MUTEX_ERRORCHECK 12
#define PTHREAD_MUTEX_NORMAL 13
#define PTHREAD_MUTEX_RECURSIVE 14
#define PTHREAD_MUTEX_ROBUST 15
#define PTHREAD_MUTEX_STALLED 16
#define PTHREAD_ONCE_INIT 17 #define PTHREAD_ONCE_INIT 17
#define PTHREAD_PRIO_INHERIT 18 #define PTHREAD_PRIO_INHERIT 18
#define PTHREAD_PRIO_NONE 19 #define PTHREAD_PRIO_NONE 19
#define PTHREAD_PRIO_PROTECT 20 #define PTHREAD_PRIO_PROTECT 20
#define PTHREAD_PROCESS_SHARED 21
#define PTHREAD_PROCESS_PRIVATE 22
#define PTHREAD_SCOPE_PROCESS 23 #define PTHREAD_SCOPE_PROCESS 23
#define PTHREAD_SCOPE_SYSTEM 24 #define PTHREAD_SCOPE_SYSTEM 24
#define PTHREAD_PROCESS_SHARED 0
#define PTHREAD_PROCESS_PRIVATE 1
#define PTHREAD_MUTEX_ROBUST 0
#define PTHREAD_MUTEX_STALLED 1
#define PTHREAD_MUTEX_DEFAULT 0
#define PTHREAD_MUTEX_ERRORCHECK 1
#define PTHREAD_MUTEX_NORMAL 2
#define PTHREAD_MUTEX_RECURSIVE 3
#define PTHREAD_COND_INITIALIZER (pthread_cond_t)0 #define PTHREAD_COND_INITIALIZER (pthread_cond_t)0
#define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t)0 #define PTHREAD_MUTEX_INITIALIZER (pthread_mutex_t){ { PTHREAD_MUTEX_DEFAULT, false }, 0, 0 }
#define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t)0 #define PTHREAD_RWLOCK_INITIALIZER (pthread_rwlock_t)0
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void)); int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void));

View File

@ -1,6 +1,6 @@
#include <BAN/Assert.h> #include <BAN/Assert.h>
#include <BAN/Debug.h>
#include <BAN/Atomic.h> #include <BAN/Atomic.h>
#include <BAN/Debug.h>
#include <BAN/PlacementNew.h> #include <BAN/PlacementNew.h>
#include <kernel/Arch.h> #include <kernel/Arch.h>
@ -349,6 +349,180 @@ int pthread_spin_unlock(pthread_spinlock_t* lock)
return 0; return 0;
} }
int pthread_mutexattr_destroy(pthread_mutexattr_t* attr)
{
(void)attr;
return 0;
}
int pthread_mutexattr_init(pthread_mutexattr_t* attr)
{
*attr = {
.type = PTHREAD_MUTEX_DEFAULT,
.shared = false,
};
return 0;
}
int pthread_mutexattr_getpshared(const pthread_mutexattr_t* __restrict attr, int* __restrict pshared)
{
*pshared = attr->shared ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE;
return 0;
}
int pthread_mutexattr_setpshared(pthread_mutexattr_t* attr, int pshared)
{
switch (pshared)
{
case PTHREAD_PROCESS_PRIVATE:
attr->shared = false;
return 0;
case PTHREAD_PROCESS_SHARED:
attr->shared = true;
return 0;
}
return EINVAL;
}
int pthread_mutexattr_gettype(const pthread_mutexattr_t* __restrict attr, int* __restrict type)
{
*type = attr->type;
return 0;
}
int pthread_mutexattr_settype(pthread_mutexattr_t* attr, int type)
{
switch (type)
{
case PTHREAD_MUTEX_DEFAULT:
case PTHREAD_MUTEX_ERRORCHECK:
case PTHREAD_MUTEX_NORMAL:
case PTHREAD_MUTEX_RECURSIVE:
attr->type = type;
return 0;
}
return EINVAL;
}
int pthread_mutex_destroy(pthread_mutex_t* mutex)
{
(void)mutex;
return 0;
}
int pthread_mutex_init(pthread_mutex_t* __restrict mutex, const pthread_mutexattr_t* __restrict attr)
{
const pthread_mutexattr_t default_attr = {
.type = PTHREAD_MUTEX_DEFAULT,
.shared = false,
};
if (attr == nullptr)
attr = &default_attr;
*mutex = {
.attr = *attr,
.locker = 0,
.lock_depth = 0,
};
return 0;
}
int pthread_mutex_lock(pthread_mutex_t* mutex)
{
// NOTE: current yielding implementation supports shared
const auto tid = pthread_self();
switch (mutex->attr.type)
{
case PTHREAD_MUTEX_RECURSIVE:
if (mutex->locker != tid)
break;
mutex->lock_depth++;
return 0;
case PTHREAD_MUTEX_ERRORCHECK:
if (mutex->locker != tid)
break;
return EDEADLK;
}
pthread_t expected = 0;
while (!BAN::atomic_compare_exchange(mutex->locker, expected, tid, BAN::MemoryOrder::memory_order_acquire))
{
sched_yield();
expected = 0;
}
mutex->lock_depth = 1;
return 0;
}
int pthread_mutex_timedlock(pthread_mutex_t* __restrict mutex, const struct timespec* __restrict abstime)
{
if (pthread_mutex_trylock(mutex) == 0)
return 0;
constexpr auto has_timed_out =
[](const struct timespec* abstime) -> bool
{
struct timespec curtime;
clock_gettime(CLOCK_REALTIME, &curtime);
if (curtime.tv_sec < abstime->tv_sec)
return false;
if (curtime.tv_sec > abstime->tv_sec)
return true;
return curtime.tv_nsec >= abstime->tv_nsec;
};
while (!has_timed_out(abstime))
{
if (pthread_mutex_trylock(mutex) == 0)
return 0;
sched_yield();
}
return ETIMEDOUT;
}
int pthread_mutex_trylock(pthread_mutex_t* mutex)
{
// NOTE: current yielding implementation supports shared
const auto tid = pthread_self();
switch (mutex->attr.type)
{
case PTHREAD_MUTEX_RECURSIVE:
if (mutex->locker != tid)
break;
mutex->lock_depth++;
return 0;
case PTHREAD_MUTEX_ERRORCHECK:
if (mutex->locker != tid)
break;
return EDEADLK;
}
pthread_t expected = 0;
if (!BAN::atomic_compare_exchange(mutex->locker, expected, tid, BAN::MemoryOrder::memory_order_acquire))
return EBUSY;
mutex->lock_depth = 1;
return 0;
}
int pthread_mutex_unlock(pthread_mutex_t* mutex)
{
// NOTE: current yielding implementation supports shared
ASSERT(mutex->locker == pthread_self());
mutex->lock_depth--;
if (mutex->lock_depth == 0)
BAN::atomic_store(mutex->locker, 0, BAN::MemoryOrder::memory_order_release);
return 0;
}
#if not __disable_thread_local_storage #if not __disable_thread_local_storage
struct tls_index struct tls_index
{ {