123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- /*
- * Copyright (c) 2019 Intel Corporation
- *
- * SPDX-License-Identifier: Apache-2.0
- */
- #include <sys/sem.h>
- #include <syscall_handler.h>
- #ifdef CONFIG_USERSPACE
- #define SYS_SEM_MINIMUM 0
- #define SYS_SEM_CONTENDED (SYS_SEM_MINIMUM - 1)
- static inline atomic_t bounded_dec(atomic_t *val, atomic_t minimum)
- {
- atomic_t old_value, new_value;
- do {
- old_value = atomic_get(val);
- if (old_value < minimum) {
- break;
- }
- new_value = old_value - 1;
- } while (atomic_cas(val, old_value, new_value) == 0);
- return old_value;
- }
- static inline atomic_t bounded_inc(atomic_t *val, atomic_t minimum,
- atomic_t maximum)
- {
- atomic_t old_value, new_value;
- do {
- old_value = atomic_get(val);
- if (old_value >= maximum) {
- break;
- }
- new_value = old_value < minimum ?
- minimum + 1 : old_value + 1;
- } while (atomic_cas(val, old_value, new_value) == 0U);
- return old_value;
- }
- int sys_sem_init(struct sys_sem *sem, unsigned int initial_count,
- unsigned int limit)
- {
- if (sem == NULL || limit == SYS_SEM_MINIMUM ||
- initial_count > limit || limit > INT_MAX) {
- return -EINVAL;
- }
- atomic_set(&sem->futex.val, initial_count);
- sem->limit = limit;
- return 0;
- }
- int sys_sem_give(struct sys_sem *sem)
- {
- int ret = 0;
- atomic_t old_value;
- old_value = bounded_inc(&sem->futex.val,
- SYS_SEM_MINIMUM, sem->limit);
- if (old_value < 0) {
- ret = k_futex_wake(&sem->futex, true);
- if (ret > 0) {
- return 0;
- }
- } else if (old_value >= sem->limit) {
- return -EAGAIN;
- } else {
- ;
- }
- return ret;
- }
- int sys_sem_take(struct sys_sem *sem, k_timeout_t timeout)
- {
- int ret = 0;
- atomic_t old_value;
- do {
- old_value = bounded_dec(&sem->futex.val,
- SYS_SEM_MINIMUM);
- if (old_value > 0) {
- return 0;
- }
- ret = k_futex_wait(&sem->futex,
- SYS_SEM_CONTENDED, timeout);
- } while (ret == 0 || ret == -EAGAIN);
- return ret;
- }
- unsigned int sys_sem_count_get(struct sys_sem *sem)
- {
- int value = atomic_get(&sem->futex.val);
- return value > SYS_SEM_MINIMUM ? value : SYS_SEM_MINIMUM;
- }
- #else
- int sys_sem_init(struct sys_sem *sem, unsigned int initial_count,
- unsigned int limit)
- {
- k_sem_init(&sem->kernel_sem, initial_count, limit);
- return 0;
- }
- int sys_sem_give(struct sys_sem *sem)
- {
- k_sem_give(&sem->kernel_sem);
- return 0;
- }
- int sys_sem_take(struct sys_sem *sem, k_timeout_t timeout)
- {
- int ret_value = 0;
- ret_value = k_sem_take(&sem->kernel_sem, timeout);
- if (ret_value == -EAGAIN || ret_value == -EBUSY) {
- ret_value = -ETIMEDOUT;
- }
- return ret_value;
- }
- unsigned int sys_sem_count_get(struct sys_sem *sem)
- {
- return k_sem_count_get(&sem->kernel_sem);
- }
- #endif
|