libc: pthread cond/rwlock improvements

- add a check to detect if a different thread has
  initialized the internal object in the meantime
- remove ENOMEM error since the 'Libc::Allocator'
  is not supposed to throw exceptions
- remove init mutex from 'pthread_condattr_init()'
  since there is no implicit initialization which
  could happen in parallel like with mutex/cond/rwlock

Issue #5386
This commit is contained in:
Christian Prochaska 2024-11-26 01:08:19 +01:00
parent 37842757ac
commit 35a679d861
2 changed files with 51 additions and 32 deletions

View File

@ -1086,6 +1086,15 @@ extern "C" {
sem_t signal_sem; sem_t signal_sem;
sem_t handshake_sem; sem_t handshake_sem;
struct Invalid_timedwait_clock { };
void _cleanup()
{
sem_destroy(&handshake_sem);
sem_destroy(&signal_sem);
pthread_mutex_destroy(&counter_mutex);
}
pthread_cond(clockid_t clock_id) : num_waiters(0), num_signallers(0) pthread_cond(clockid_t clock_id) : num_waiters(0), num_signallers(0)
{ {
pthread_mutex_init(&counter_mutex, nullptr); pthread_mutex_init(&counter_mutex, nullptr);
@ -1093,17 +1102,12 @@ extern "C" {
sem_init(&handshake_sem, 0, 0); sem_init(&handshake_sem, 0, 0);
if (sem_set_clock(&signal_sem, clock_id)) { if (sem_set_clock(&signal_sem, clock_id)) {
struct Invalid_timedwait_clock { }; _cleanup();
throw Invalid_timedwait_clock(); throw Invalid_timedwait_clock();
} }
} }
~pthread_cond() ~pthread_cond() { _cleanup(); }
{
sem_destroy(&handshake_sem);
sem_destroy(&signal_sem);
pthread_mutex_destroy(&counter_mutex);
}
}; };
@ -1115,17 +1119,11 @@ extern "C" {
int pthread_condattr_init(pthread_condattr_t *attr) int pthread_condattr_init(pthread_condattr_t *attr)
{ {
static Mutex condattr_init_mutex { };
if (!attr) if (!attr)
return EINVAL; return EINVAL;
try { Libc::Allocator alloc { };
Mutex::Guard guard(condattr_init_mutex); *attr = new (alloc) pthread_cond_attr;
Libc::Allocator alloc { };
*attr = new (alloc) pthread_cond_attr;
return 0;
} catch (...) { return ENOMEM; }
return 0; return 0;
} }
@ -1161,22 +1159,35 @@ extern "C" {
{ {
static Mutex cond_init_mutex { }; static Mutex cond_init_mutex { };
if (!cond) Mutex::Guard guard(cond_init_mutex);
return EINVAL;
/*
* '*cond' could have been initialized by a different
* thread which got the init mutex earlier.
*/
if (*cond != PTHREAD_COND_INITIALIZER)
return 0;
Libc::Allocator alloc { };
try { try {
Mutex::Guard guard(cond_init_mutex);
Libc::Allocator alloc { };
*cond = attr && *attr ? new (alloc) pthread_cond((*attr)->clock_id) *cond = attr && *attr ? new (alloc) pthread_cond((*attr)->clock_id)
: new (alloc) pthread_cond(CLOCK_REALTIME); : new (alloc) pthread_cond(CLOCK_REALTIME);
return 0; } catch (pthread_cond::Invalid_timedwait_clock) { return EINVAL; }
} catch (...) { return ENOMEM; }
return 0;
} }
int pthread_cond_init(pthread_cond_t *__restrict cond, int pthread_cond_init(pthread_cond_t *__restrict cond,
const pthread_condattr_t *__restrict attr) const pthread_condattr_t *__restrict attr)
{ {
if (!cond)
return EINVAL;
/* mark as uninitialized for 'cond_init()' */
*cond = PTHREAD_COND_INITIALIZER;
return cond_init(cond, attr); return cond_init(cond, attr);
} }

View File

@ -104,20 +104,30 @@ extern "C" {
{ {
static Mutex rwlock_init_mutex { }; static Mutex rwlock_init_mutex { };
if (!rwlock) Mutex::Guard g(rwlock_init_mutex);
return EINVAL;
try { /*
Mutex::Guard g(rwlock_init_mutex); * '*rwlock' could have been initialized by a different
Libc::Allocator alloc { }; * thread which got the init mutex earlier.
*rwlock = new (alloc) struct pthread_rwlock(); */
if (*rwlock != PTHREAD_RWLOCK_INITIALIZER)
return 0; return 0;
} catch (...) { return ENOMEM; }
Libc::Allocator alloc { };
*rwlock = new (alloc) struct pthread_rwlock();
return 0;
} }
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
{ {
if (!rwlock)
return EINVAL;
/* mark as uninitialized for 'rwlock_init()' */
*rwlock = PTHREAD_RWLOCK_INITIALIZER;
return rwlock_init(rwlock, attr); return rwlock_init(rwlock, attr);
} }
@ -142,8 +152,7 @@ extern "C" {
return EINVAL; return EINVAL;
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
if (rwlock_init(rwlock, NULL)) rwlock_init(rwlock, NULL);
return ENOMEM;
(*rwlock)->rdlock(); (*rwlock)->rdlock();
return 0; return 0;
@ -159,8 +168,7 @@ extern "C" {
return EINVAL; return EINVAL;
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER) if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
if (rwlock_init(rwlock, NULL)) rwlock_init(rwlock, NULL);
return ENOMEM;
(*rwlock)->wrlock(); (*rwlock)->wrlock();
return 0; return 0;