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:
parent
3642eabac0
commit
db9db2cc40
|
@ -40,18 +40,24 @@ __BEGIN_DECLS
|
|||
#endif
|
||||
#undef __need_pthread_key_t
|
||||
|
||||
#if !defined(__pthread_mutex_t_defined) && (defined(__need_all_types) || defined(__need_pthread_mutex_t))
|
||||
#define __pthread_mutex_t_defined 1
|
||||
typedef int pthread_mutex_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_mutex_t
|
||||
#undef __need_pthread_t
|
||||
|
||||
#if !defined(__pthread_mutexattr_t_defined) && (defined(__need_all_types) || defined(__need_pthread_mutexattr_t))
|
||||
#define __pthread_mutexattr_t_defined 1
|
||||
typedef int pthread_mutexattr_t;
|
||||
typedef struct { int type; bool shared; } pthread_mutexattr_t;
|
||||
#endif
|
||||
#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))
|
||||
#define __pthread_once_t_defined 1
|
||||
typedef int pthread_once_t;
|
||||
|
@ -70,12 +76,6 @@ __BEGIN_DECLS
|
|||
#endif
|
||||
#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))
|
||||
#define __pthread_spinlock_t_defined 1
|
||||
typedef pthread_t pthread_spinlock_t;
|
||||
|
|
|
@ -46,23 +46,26 @@ struct uthread
|
|||
#define PTHREAD_CREATE_JOINABLE 8
|
||||
#define PTHREAD_EXPLICIT_SCHED 9
|
||||
#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_PRIO_INHERIT 18
|
||||
#define PTHREAD_PRIO_NONE 19
|
||||
#define PTHREAD_PRIO_PROTECT 20
|
||||
#define PTHREAD_PROCESS_SHARED 21
|
||||
#define PTHREAD_PROCESS_PRIVATE 22
|
||||
#define PTHREAD_SCOPE_PROCESS 23
|
||||
#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_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
|
||||
|
||||
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include <BAN/Assert.h>
|
||||
#include <BAN/Debug.h>
|
||||
#include <BAN/Atomic.h>
|
||||
#include <BAN/Debug.h>
|
||||
#include <BAN/PlacementNew.h>
|
||||
|
||||
#include <kernel/Arch.h>
|
||||
|
@ -349,6 +349,180 @@ int pthread_spin_unlock(pthread_spinlock_t* lock)
|
|||
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
|
||||
struct tls_index
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue