kernel: POSIX: Compatibility layer for POSIX read-write lock APIs.

This patch provides POSIX read-write lock APIs for POSIX 1003.1
PSE52 standard.

Signed-off-by: Youvedeep Singh <youvedeep.singh@intel.com>
This commit is contained in:
Youvedeep Singh 2018-02-28 15:37:00 +05:30 committed by Anas Nashif
commit 216883ca82
5 changed files with 350 additions and 0 deletions

View file

@ -39,6 +39,8 @@
#define timer_t zap_timer_t
#define sigval zap_sigval
#define sigevent zap_sigevent
#define pthread_rwlock_obj zap_pthread_rwlock_obj
#define pthread_rwlockattr_t zap_pthread_rwlockattr_t
/* Condition variables */
#define pthread_cond_init(...) zap_pthread_cond_init(__VA_ARGS__)
#define pthread_cond_destroy(...) zap_pthread_cond_destroy(__VA_ARGS__)
@ -116,6 +118,24 @@
#define timer_gettime(...) zap_timer_gettime(__VA_ARGS__)
#define timer_settime(...) zap_timer_settime(__VA_ARGS__)
/* Read/Write lock */
#define pthread_rwlock_destroy(...) zap_pthread_rwlock_destroy(__VA_ARGS__)
#define pthread_rwlock_init(...) zap_pthread_rwlock_init(__VA_ARGS__)
#define pthread_rwlock_rdlock(...) zap_pthread_rwlock_rdlock(__VA_ARGS__)
#define pthread_rwlock_unlock(...) zap_pthread_rwlock_unlock(__VA_ARGS__)
#define pthread_rwlock_wrlock(...) zap_pthread_rwlock_wrlock(__VA_ARGS__)
#define pthread_rwlockattr_init(...) zap_pthread_rwlockattr_init(__VA_ARGS__)
#define pthread_rwlock_timedrdlock(...)\
zap_pthread_rwlock_timedrdlock(__VA_ARGS__)
#define pthread_rwlock_timedwrlock(...)\
zap_pthread_rwlock_timedwrlock(__VA_ARGS__)
#define pthread_rwlock_tryrdlock(...)\
zap_pthread_rwlock_tryrdlock(__VA_ARGS__)
#define pthread_rwlock_trywrlock(...)\
zap_pthread_rwlock_trywrlock(__VA_ARGS__)
#define pthread_rwlockattr_destroy(...)\
zap_pthread_rwlockattr_destroy(__VA_ARGS__)
#endif /* CONFIG_PTHREAD_IPC */
#endif /* CONFIG_ARCH_POSIX */

View file

@ -411,6 +411,26 @@ static inline int pthread_equal(pthread_t pt1, pthread_t pt2)
return (pt1 == pt2);
}
/**
* @brief Destroy the read-write lock attributes object.
*
* See IEEE 1003.1
*/
static inline int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
{
return 0;
}
/**
* @brief initialize the read-write lock attributes object.
*
* See IEEE 1003.1
*/
static inline int pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
{
return 0;
}
int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);
int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
@ -437,5 +457,17 @@ int pthread_attr_setschedparam(pthread_attr_t *attr,
const struct sched_param *schedparam);
int pthread_setschedparam(pthread_t pthread, int policy,
const struct sched_param *param);
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
int pthread_rwlock_init(pthread_rwlock_t *rwlock,
const pthread_rwlockattr_t *attr);
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock,
const struct timespec *abstime);
int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock,
const struct timespec *abstime);
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
#endif /* __PTHREAD_H__ */

View file

@ -63,6 +63,16 @@ typedef u32_t clockid_t;
typedef unsigned long timer_t;
typedef unsigned long useconds_t;
typedef u32_t pthread_rwlockattr_t;
typedef struct pthread_rwlock_obj {
struct k_sem rd_sem;
struct k_sem wr_sem;
struct k_sem reader_active;/* blocks WR till reader has acquired lock */
s32_t status;
k_tid_t wr_owner;
} pthread_rwlock_t;
#endif /* CONFIG_PTHREAD_IPC */
#ifdef __cplusplus

View file

@ -6,3 +6,4 @@ target_sources(kernel PRIVATE posix/pthread.c)
target_sources(kernel PRIVATE posix/pthread_sched.c)
target_sources(kernel PRIVATE posix/clock.c)
target_sources(kernel PRIVATE posix/timer.c)
target_sources(kernel PRIVATE posix/pthread_rwlock.c)

View file

@ -0,0 +1,287 @@
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel.h>
#include <time.h>
#include <errno.h>
#include <sys/types.h>
#define INITIALIZED 1
#define NOT_INITIALIZED 0
#define CONCURRENT_READER_LIMIT (CONFIG_MAX_PTHREAD_COUNT + 1)
static s64_t calculate_timeout(const struct timespec *abstime);
static u32_t read_lock_acquire(pthread_rwlock_t *rwlock, s32_t timeout);
static u32_t write_lock_acquire(pthread_rwlock_t *rwlock, s32_t timeout);
/**
* @brief Initialize read-write lock object.
*
* See IEEE 1003.1
*/
int pthread_rwlock_init(pthread_rwlock_t *rwlock,
const pthread_rwlockattr_t *attr)
{
k_sem_init(&rwlock->rd_sem, CONCURRENT_READER_LIMIT,
CONCURRENT_READER_LIMIT);
k_sem_init(&rwlock->wr_sem, 1, 1);
k_sem_init(&rwlock->reader_active, 1, 1);
rwlock->wr_owner = NULL;
rwlock->status = INITIALIZED;
return 0;
}
/**
* @brief Destroy read-write lock object.
*
* See IEEE 1003.1
*/
int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
{
if (rwlock->status == NOT_INITIALIZED) {
return EINVAL;
}
if (rwlock->wr_owner != NULL) {
return EBUSY;
}
if (rwlock->status == INITIALIZED) {
rwlock->status = NOT_INITIALIZED;
return 0;
}
return EINVAL;
}
/**
* @brief Lock a read-write lock object for reading.
*
* API behaviour is unpredictable if number of concurrent reader
* lock held is greater than CONCURRENT_READER_LIMIT.
*
* See IEEE 1003.1
*/
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
{
if (rwlock->status == NOT_INITIALIZED) {
return EINVAL;
}
return read_lock_acquire(rwlock, K_FOREVER);
}
/**
* @brief Lock a read-write lock object for reading within specific time.
*
* API behaviour is unpredictable if number of concurrent reader
* lock held is greater than CONCURRENT_READER_LIMIT.
*
* See IEEE 1003.1
*/
int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock,
const struct timespec *abstime)
{
s32_t timeout;
u32_t ret = 0;
if (rwlock->status == NOT_INITIALIZED || abstime->tv_nsec < 0 ||
abstime->tv_nsec > NSEC_PER_SEC) {
return EINVAL;
}
timeout = (s32_t) calculate_timeout(abstime);
if (read_lock_acquire(rwlock, timeout) != 0) {
ret = ETIMEDOUT;
}
return ret;
}
/**
* @brief Lock a read-write lock object for reading immedately.
*
* API behaviour is unpredictable if number of concurrent reader
* lock held is greater than CONCURRENT_READER_LIMIT.
*
* See IEEE 1003.1
*/
int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
{
if (rwlock->status == NOT_INITIALIZED) {
return EINVAL;
}
return read_lock_acquire(rwlock, K_NO_WAIT);
}
/**
* @brief Lock a read-write lock object for writing.
*
* Write lock does not have priority over reader lock,
* threads get lock based on priority.
*
* See IEEE 1003.1
*/
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
{
if (rwlock->status == NOT_INITIALIZED) {
return EINVAL;
}
return write_lock_acquire(rwlock, K_FOREVER);
}
/**
* @brief Lock a read-write lock object for writing within specific time.
*
* Write lock does not have priority over reader lock,
* threads get lock based on priority.
*
* See IEEE 1003.1
*/
int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock,
const struct timespec *abstime)
{
s32_t timeout;
u32_t ret = 0;
if (rwlock->status == NOT_INITIALIZED || abstime->tv_nsec < 0 ||
abstime->tv_nsec > NSEC_PER_SEC) {
return EINVAL;
}
timeout = (s32_t) calculate_timeout(abstime);
if (write_lock_acquire(rwlock, timeout) != 0) {
ret = ETIMEDOUT;
}
return ret;
}
/**
* @brief Lock a read-write lock object for writing immedately.
*
* Write lock does not have priority over reader lock,
* threads get lock based on priority.
*
* See IEEE 1003.1
*/
int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
{
if (rwlock->status == NOT_INITIALIZED) {
return EINVAL;
}
return write_lock_acquire(rwlock, K_NO_WAIT);
}
/**
*
* @brief Unlock a read-write lock object.
*
* See IEEE 1003.1
*/
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
{
if (rwlock->status == NOT_INITIALIZED) {
return EINVAL;
}
if (k_current_get() == rwlock->wr_owner) {
/* Write unlock */
rwlock->wr_owner = NULL;
k_sem_give(&rwlock->reader_active);
k_sem_give(&rwlock->wr_sem);
} else {
/* Read unlock */
if (k_sem_count_get(&rwlock->rd_sem) ==
(CONCURRENT_READER_LIMIT - 1)) {
/* Last read lock, unlock writer */
k_sem_give(&rwlock->reader_active);
}
k_sem_give(&rwlock->rd_sem);
}
return 0;
}
static u32_t read_lock_acquire(pthread_rwlock_t *rwlock, s32_t timeout)
{
u32_t ret = 0;
if (k_sem_take(&rwlock->wr_sem, timeout) == 0) {
k_sem_take(&rwlock->reader_active, K_NO_WAIT);
k_sem_take(&rwlock->rd_sem, K_NO_WAIT);
k_sem_give(&rwlock->wr_sem);
} else {
ret = EBUSY;
}
return ret;
}
static u32_t write_lock_acquire(pthread_rwlock_t *rwlock, s32_t timeout)
{
u32_t ret = 0;
s64_t elapsed_time, st_time = k_uptime_get();
/* waiting for release of write lock */
if (k_sem_take(&rwlock->wr_sem, timeout) == 0) {
if (timeout > K_NO_WAIT) {
elapsed_time = k_uptime_get() - st_time;
timeout = timeout <= elapsed_time ? K_NO_WAIT :
timeout - elapsed_time;
}
/* waiting for reader to complete operation */
if (k_sem_take(&rwlock->reader_active, timeout) == 0) {
rwlock->wr_owner = k_current_get();
} else {
k_sem_give(&rwlock->wr_sem);
ret = EBUSY;
}
} else {
ret = EBUSY;
}
return ret;
}
static s64_t calculate_timeout(const struct timespec *abstime)
{
s64_t milli_secs;
s32_t secs;
struct timespec curtime;
/* FIXME: Zephyr does have CLOCK_REALTIME to get time.
* As per POSIX standard time should be calculated wrt CLOCK_REALTIME.
* Zephyr deviates from POSIX 1003.1 standard on this aspect.
*/
clock_gettime(CLOCK_MONOTONIC, &curtime);
secs = abstime->tv_sec - curtime.tv_sec;
if (abstime->tv_sec < curtime.tv_sec ||
(secs == 0 && abstime->tv_nsec <= curtime.tv_nsec)) {
milli_secs = K_NO_WAIT;
} else {
milli_secs = (abstime->tv_nsec - curtime.tv_nsec) /
NSEC_PER_MSEC;
if (milli_secs < 0) {
milli_secs += MSEC_PER_SEC;
secs -= 1;
}
milli_secs += (long)secs * MSEC_PER_SEC;
}
return milli_secs;
}