genode/repos/libports/src/lib/libc/rwlock.cc
Norman Feske 648bcd1505 libc: unify use of namespaces
This patch unifies the patterns of using the 'Genode' and 'Libc'
namespaces.

Types defined in the 'internal/' headers reside in the 'Libc'
namespace. The code in the headers does not need to use the
'Libc::' prefix.

Compilation units import the 'Libc' namespace after the definition of
local types. Local types reside in the 'Libc' namespace (and should
eventually move to an 'internal/' header).

Since the 'Libc' namespace imports the 'Genode' namespace, there is
no need to use the 'Genode::' prefix. Consequently, code in the
compilation units rarely need to qualify the 'Genode' or 'Libc'
namespaces.

There are a few cases where the 'Libc', the 'Genode', and the global
(libc) namespaces are ambigious. In these cases, an explicit
clarification is needed:

- 'Genode::Allocator' differs from 'Libc::Allocator'.
- 'Genode::Env' differs from 'Libc::Env'.
- Genode's string functions (strcmp, memcpy, strcpy) conflict
  with the names of the (global) libc functions.
- There exist both 'Genode::uint64_t' and the libc'c 'uint64_t'.

Issue #3497
2019-11-19 14:10:55 +01:00

195 lines
3.8 KiB
C++

/*
* \brief POSIX readers/writer lock (rwlock) implementation
* \author Alexander Senier
* \date 2018-01-25
*/
/*
* Copyright (C) 2018 Componolit GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <base/log.h>
#include <base/lock.h>
#include <base/lock_guard.h>
#include <base/thread.h>
#include <libc/allocator.h>
/* libc includes */
#include <errno.h>
#include <pthread.h>
/* libc-internal includes */
#include <internal/types.h>
using namespace Libc;
/*
* A reader-preferring implementation of a readers-writer lock as described
* in Michael Raynal, "Concurrent Programming: Algorithms, Principles, and
* Foundations", ISBN 978-3-642-32026-2, page 75
*/
extern "C" {
/*
* This class is named 'struct pthread_rwlock' because the 'pthread_rwlock_t'
* type is defined as 'struct rwlock*' in 'sys/_pthreadtypes.h'
*/
struct pthread_rwlock
{
private:
Thread *_owner = nullptr;
Lock _nbr_mutex {};
Lock _global_mutex {};
int _nbr = 0;
public:
void rdlock()
{
Lock_guard<Lock> guard(_nbr_mutex);
++_nbr;
if (_nbr == 1) {
_global_mutex.lock();
_owner = nullptr;
}
}
void wrlock()
{
_global_mutex.lock();
_owner = Thread::myself();
}
int unlock()
{
/* Read lock */
if (_owner == nullptr) {
Lock_guard<Lock> guard(_nbr_mutex);
_nbr--;
if (_nbr == 0) {
_owner = nullptr;
_global_mutex.unlock();
}
return 0;
};
if (_owner != Thread::myself()) {
error("Unlocking writer lock owned by other thread");
errno = EPERM;
return -1;
};
/* Write lock owned by us */
_owner = nullptr;
_global_mutex.unlock();
return 0;
}
};
struct pthread_rwlockattr
{
};
static int rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
{
static Lock rwlock_init_lock { };
if (!rwlock)
return EINVAL;
try {
Lock::Guard g(rwlock_init_lock);
Libc::Allocator alloc { };
*rwlock = new (alloc) struct pthread_rwlock();
return 0;
} catch (...) { return ENOMEM; }
}
int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr)
{
return rwlock_init(rwlock, attr);
}
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
{
Libc::Allocator alloc { };
destroy(alloc, *rwlock);
return 0;
}
int pthread_rwlock_rdlock(pthread_rwlock_t * rwlock)
{
if (!rwlock)
return EINVAL;
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
if (rwlock_init(rwlock, NULL))
return ENOMEM;
(*rwlock)->rdlock();
return 0;
}
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
{
if (!rwlock)
return EINVAL;
if (*rwlock == PTHREAD_RWLOCK_INITIALIZER)
if (rwlock_init(rwlock, NULL))
return ENOMEM;
(*rwlock)->wrlock();
return 0;
}
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
{
return (*rwlock)->unlock();
}
int pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
{
Libc::Allocator alloc { };
*attr = new (alloc) struct pthread_rwlockattr();
return 0;
}
int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, int *pshared)
{
*pshared = PTHREAD_PROCESS_PRIVATE;
return 0;
}
int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared)
{
if (pshared != PTHREAD_PROCESS_PRIVATE) {
errno = EINVAL;
return -1;
}
return 0;
}
int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
{
Libc::Allocator alloc { };
destroy(alloc, *attr);
return 0;
}
/*
* Unimplemented functions:
* int pthread_rwlock_timedrdlock(pthread_rwlock_t *, const struct timespec *);
* int pthread_rwlock_timedwrlock(pthread_rwlock_t *, const struct timespec *);
* int pthread_rwlock_tryrdlock(pthread_rwlock_t *);
* int pthread_rwlock_trywrlock(pthread_rwlock_t *);
*/
}