LibC: Implement pthread_cond_* using a futex
This commit is contained in:
parent
dfdfb7cdaf
commit
eb7922ab88
|
@ -10,6 +10,8 @@ __BEGIN_DECLS
|
||||||
#include <bits/types/pthread_attr_t.h>
|
#include <bits/types/pthread_attr_t.h>
|
||||||
#include <bits/types/pthread_t.h>
|
#include <bits/types/pthread_t.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef int pthread_once_t;
|
typedef int pthread_once_t;
|
||||||
|
|
||||||
typedef unsigned pthread_key_t;
|
typedef unsigned pthread_key_t;
|
||||||
|
@ -36,7 +38,7 @@ typedef struct
|
||||||
struct _pthread_cond_block
|
struct _pthread_cond_block
|
||||||
{
|
{
|
||||||
struct _pthread_cond_block* next;
|
struct _pthread_cond_block* next;
|
||||||
int signaled;
|
uint32_t futex;
|
||||||
};
|
};
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/futex.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
@ -1113,7 +1114,12 @@ int pthread_cond_broadcast(pthread_cond_t* cond)
|
||||||
{
|
{
|
||||||
pthread_spin_lock(&cond->lock);
|
pthread_spin_lock(&cond->lock);
|
||||||
for (auto* block = cond->block_list; block; block = block->next)
|
for (auto* block = cond->block_list; block; block = block->next)
|
||||||
BAN::atomic_store(block->signaled, 1);
|
{
|
||||||
|
BAN::atomic_store(block->futex, 1);
|
||||||
|
|
||||||
|
const int op = FUTEX_WAKE | (cond->attr.shared ? 0 : FUTEX_PRIVATE);
|
||||||
|
futex(op, &block->futex, 1, nullptr);
|
||||||
|
}
|
||||||
pthread_spin_unlock(&cond->lock);
|
pthread_spin_unlock(&cond->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1121,8 +1127,13 @@ int pthread_cond_broadcast(pthread_cond_t* cond)
|
||||||
int pthread_cond_signal(pthread_cond_t* cond)
|
int pthread_cond_signal(pthread_cond_t* cond)
|
||||||
{
|
{
|
||||||
pthread_spin_lock(&cond->lock);
|
pthread_spin_lock(&cond->lock);
|
||||||
if (cond->block_list)
|
if (auto* block = cond->block_list)
|
||||||
BAN::atomic_store(cond->block_list->signaled, 1);
|
{
|
||||||
|
BAN::atomic_store(block->futex, 1);
|
||||||
|
|
||||||
|
const int op = FUTEX_WAKE | (cond->attr.shared ? 0 : FUTEX_PRIVATE);
|
||||||
|
futex(op, &block->futex, 1, nullptr);
|
||||||
|
}
|
||||||
pthread_spin_unlock(&cond->lock);
|
pthread_spin_unlock(&cond->lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1137,38 +1148,26 @@ int pthread_cond_timedwait(pthread_cond_t* __restrict cond, pthread_mutex_t* __r
|
||||||
{
|
{
|
||||||
pthread_testcancel();
|
pthread_testcancel();
|
||||||
|
|
||||||
constexpr auto has_timed_out =
|
|
||||||
[](const struct timespec* abstime, clockid_t clock_id) -> bool
|
|
||||||
{
|
|
||||||
if (abstime == nullptr)
|
|
||||||
return false;
|
|
||||||
struct timespec curtime;
|
|
||||||
clock_gettime(clock_id, &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;
|
|
||||||
};
|
|
||||||
|
|
||||||
pthread_spin_lock(&cond->lock);
|
pthread_spin_lock(&cond->lock);
|
||||||
_pthread_cond_block block = {
|
_pthread_cond_block block = {
|
||||||
.next = cond->block_list,
|
.next = cond->block_list,
|
||||||
.signaled = 0,
|
.futex = 0,
|
||||||
};
|
};
|
||||||
cond->block_list = █
|
cond->block_list = █
|
||||||
pthread_spin_unlock(&cond->lock);
|
pthread_spin_unlock(&cond->lock);
|
||||||
|
|
||||||
pthread_mutex_unlock(mutex);
|
pthread_mutex_unlock(mutex);
|
||||||
|
|
||||||
while (BAN::atomic_load(block.signaled) == 0)
|
while (BAN::atomic_load(block.futex) == 0)
|
||||||
{
|
{
|
||||||
if (has_timed_out(abstime, cond->attr.clock))
|
const int op = FUTEX_WAIT
|
||||||
|
| (cond->attr.shared ? 0 : FUTEX_PRIVATE)
|
||||||
|
| (cond->attr.clock == CLOCK_REALTIME ? FUTEX_REALTIME : 0);
|
||||||
|
if (futex(op, &block.futex, 0, abstime) == -1 && errno == ETIMEDOUT)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(mutex);
|
pthread_mutex_lock(mutex);
|
||||||
return ETIMEDOUT;
|
return ETIMEDOUT;
|
||||||
}
|
}
|
||||||
sched_yield();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_spin_lock(&cond->lock);
|
pthread_spin_lock(&cond->lock);
|
||||||
|
|
Loading…
Reference in New Issue