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:
parent
bdac8d070f
commit
216883ca82
5 changed files with 350 additions and 0 deletions
|
@ -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 */
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
287
kernel/posix/pthread_rwlock.c
Normal file
287
kernel/posix/pthread_rwlock.c
Normal 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;
|
||||
}
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue