pthread: implement condattr setclock

Normally CLOCK_REALTIME is used. However libraries, like glib, want to
use CLOCK_MONOTONIC. To make those users happy add setting the clock.

Note, the pthread_cond implementation uses the POSIX semaphore API
internally that does not have means to set the clock. For this reason,
the private 'sem_set_clock' function is introduced.

Fixes #3846.
This commit is contained in:
Josef Söntgen 2020-08-06 15:41:32 +02:00 committed by Norman Feske
parent 66ff18a53e
commit 157f4b1270
2 changed files with 61 additions and 9 deletions

View File

@ -505,6 +505,15 @@ struct Libc::Pthread_mutex_recursive : pthread_mutex
};
/*
* The pthread_cond implementation uses the POSIX semaphore API
* internally that does not have means to set the clock. For this
* reason the private 'sem_set_clock' function is introduced,
* see 'semaphore.cc' for the implementation.
*/
extern "C" int sem_set_clock(sem_t *sem, clockid_t clock_id);
extern "C" {
/* Thread */
@ -879,11 +888,16 @@ extern "C" {
sem_t signal_sem;
sem_t handshake_sem;
pthread_cond() : num_waiters(0), num_signallers(0)
pthread_cond(clockid_t clock_id) : num_waiters(0), num_signallers(0)
{
pthread_mutex_init(&counter_mutex, nullptr);
sem_init(&signal_sem, 0, 0);
sem_init(&handshake_sem, 0, 0);
if (sem_set_clock(&signal_sem, clock_id)) {
struct Invalid_timedwait_clock { };
throw Invalid_timedwait_clock();
}
}
~pthread_cond()
@ -895,12 +909,25 @@ extern "C" {
};
struct pthread_cond_attr
{
clockid_t clock_id { CLOCK_REALTIME };
};
int pthread_condattr_init(pthread_condattr_t *attr)
{
static Mutex condattr_init_mutex { };
if (!attr)
return EINVAL;
*attr = nullptr;
try {
Mutex::Guard guard(condattr_init_mutex);
Libc::Allocator alloc { };
*attr = new (alloc) pthread_cond_attr;
return 0;
} catch (...) { return ENOMEM; }
return 0;
}
@ -908,10 +935,13 @@ extern "C" {
int pthread_condattr_destroy(pthread_condattr_t *attr)
{
/* assert that the attr was produced by the init no-op */
if (!attr || *attr != nullptr)
if (!attr)
return EINVAL;
Libc::Allocator alloc { };
destroy(alloc, *attr);
*attr = nullptr;
return 0;
}
@ -919,11 +949,10 @@ extern "C" {
int pthread_condattr_setclock(pthread_condattr_t *attr,
clockid_t clock_id)
{
/* assert that the attr was produced by the init no-op */
if (!attr || *attr != nullptr)
if (!attr)
return EINVAL;
warning(__func__, " not implemented yet");
(*attr)->clock_id = clock_id;
return 0;
}
@ -940,7 +969,8 @@ extern "C" {
try {
Mutex::Guard guard(cond_init_mutex);
Libc::Allocator alloc { };
*cond = new (alloc) pthread_cond;
*cond = attr && *attr ? new (alloc) pthread_cond((*attr)->clock_id)
: new (alloc) pthread_cond(CLOCK_REALTIME);
return 0;
} catch (...) { return ENOMEM; }
}

View File

@ -64,6 +64,8 @@ struct sem : Genode::Noncopyable
int _count;
Mutex _data_mutex;
clockid_t _clock_id { CLOCK_REALTIME };
/* _data_mutex must be hold when calling the following methods */
void _append_applicant(Applicant *applicant)
@ -185,7 +187,7 @@ struct sem : Genode::Noncopyable
return 0;
timespec abs_now;
clock_gettime(CLOCK_REALTIME, &abs_now);
clock_gettime(_clock_id, &abs_now);
Libc::uint64_t const timeout_ms =
calculate_relative_timeout_ms(abs_now, abs_timeout);
@ -206,11 +208,31 @@ struct sem : Genode::Noncopyable
return 0;
}
int set_clock(clockid_t clock_id)
{
switch (clock_id) {
case CLOCK_REALTIME:
_clock_id = CLOCK_REALTIME;
return 0;
case CLOCK_MONOTONIC:
_clock_id = CLOCK_MONOTONIC;
return 0;
default:
break;
}
return -1;
}
};
extern "C" {
int sem_set_clock(sem_t *sem, clockid_t clock_id)
{
return (*sem)->set_clock(clock_id);
}
int sem_close(sem_t *)
{
warning(__func__, " not implemented");