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
|
#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;
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue