diff --git a/repos/libports/lib/mk/pthread.mk b/repos/libports/lib/mk/pthread.mk index 216cbcbd80..96b2648b5d 100644 --- a/repos/libports/lib/mk/pthread.mk +++ b/repos/libports/lib/mk/pthread.mk @@ -1,4 +1,4 @@ -SRC_CC = semaphore.cc \ +SRC_CC = semaphore.cc rwlock.cc \ thread.cc thread_create.cc LIBS += libc diff --git a/repos/libports/src/lib/pthread/rwlock.cc b/repos/libports/src/lib/pthread/rwlock.cc new file mode 100644 index 0000000000..0fd961174d --- /dev/null +++ b/repos/libports/src/lib/pthread/rwlock.cc @@ -0,0 +1,155 @@ +/* + * \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 +#include +#include +#include + +/* Libc includes */ +#include +#include + +/* + * 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: + + Genode::Thread *_owner; + Genode::Lock _nbr_mutex {}; + Genode::Lock _global_mutex {}; + int _nbr = 0; + + public: + + void rdlock() + { + Genode::Lock_guard guard(_nbr_mutex); + ++_nbr; + if (_nbr == 1) { + _global_mutex.lock(); + } + } + + void wrlock() + { + _global_mutex.lock(); + _owner = Genode::Thread::myself(); + } + + int unlock() + { + Genode::Lock_guard guard(_nbr_mutex); + + /* Read lock */ + if (_owner == nullptr) { + _nbr--; + if (_nbr == 0) { + _global_mutex.unlock(); + } + return 0; + }; + + if (_owner != Genode::Thread::myself()) { + Genode::error("Unlocking writer lock owned by other thread"); + errno = EPERM; + return -1; + }; + + /* Write lock owned by us */ + _global_mutex.unlock(); + return 0; + } + }; + + struct pthread_rwlockattr + { + }; + + int pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) + { + *rwlock = new struct pthread_rwlock(); + return 0; + } + + int pthread_rwlock_destroy(pthread_rwlock_t *rwlock) + { + delete *rwlock; + return 0; + } + + int pthread_rwlock_rdlock(pthread_rwlock_t * rwlock) + { + (*rwlock)->rdlock(); + return 0; + } + + int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) + { + (*rwlock)->wrlock(); + return 0; + } + + int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) + { + return (*rwlock)->unlock(); + } + + int pthread_rwlockattr_init(pthread_rwlockattr_t *attr) + { + *attr = new 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) + { + delete *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 *); + */ +}