/* * Copyright (c) 2019 Intel Corporation * * SPDX-License-Identifier: Apache-2.0 */ #ifndef ZEPHYR_INCLUDE_SYS_MUTEX_H_ #define ZEPHYR_INCLUDE_SYS_MUTEX_H_ /* * sys_mutex behaves almost exactly like k_mutex, with the added advantage * that a sys_mutex instance can reside in user memory. * * Further enhancements will support locking/unlocking uncontended sys_mutexes * with simple atomic ops instead of syscalls, similar to Linux's * FUTEX_LOCK_PI and FUTEX_UNLOCK_PI */ #ifdef CONFIG_USERSPACE #include #include struct sys_mutex { /* Currently unused, but will be used to store state for fast mutexes * that can be locked/unlocked with atomic ops if there is no * contention */ atomic_t val; }; #define SYS_MUTEX_DEFINE(name) \ struct sys_mutex name /** * @brief Initialize a mutex. * * This routine initializes a mutex object, prior to its first use. * * Upon completion, the mutex is available and does not have an owner. * * This routine is only necessary to call when userspace is disabled * and the mutex was not created with SYS_MUTEX_DEFINE(). * * @param mutex Address of the mutex. * * @return N/A */ static inline void sys_mutex_init(struct sys_mutex *mutex) { ARG_UNUSED(mutex); /* Nothing to do, kernel-side data structures are initialized at * boot */ } __syscall int z_sys_mutex_kernel_lock(struct sys_mutex *mutex, s32_t timeout); __syscall int z_sys_mutex_kernel_unlock(struct sys_mutex *mutex); /** * @brief Lock a mutex. * * This routine locks @a mutex. If the mutex is locked by another thread, * the calling thread waits until the mutex becomes available or until * a timeout occurs. * * A thread is permitted to lock a mutex it has already locked. The operation * completes immediately and the lock count is increased by 1. * * @param mutex Address of the mutex, which may reside in user memory * @param timeout Waiting period to lock the mutex (in milliseconds), * or one of the special values K_NO_WAIT and K_FOREVER. * * @retval 0 Mutex locked. * @retval -EBUSY Returned without waiting. * @retval -EAGAIN Waiting period timed out. * @retval -EACCESS Caller has no access to provided mutex address * @retval -EINVAL Provided mutex not recognized by the kernel */ static inline int sys_mutex_lock(struct sys_mutex *mutex, s32_t timeout) { /* For now, make the syscall unconditionally */ return z_sys_mutex_kernel_lock(mutex, timeout); } /** * @brief Unlock a mutex. * * This routine unlocks @a mutex. The mutex must already be locked by the * calling thread. * * The mutex cannot be claimed by another thread until it has been unlocked by * the calling thread as many times as it was previously locked by that * thread. * * @param mutex Address of the mutex, which may reside in user memory * @retval -EACCESS Caller has no access to provided mutex address * @retval -EINVAL Provided mutex not recognized by the kernel or mutex wasn't * locked * @retval -EPERM Caller does not own the mutex */ static inline int sys_mutex_unlock(struct sys_mutex *mutex) { /* For now, make the syscall unconditionally */ return z_sys_mutex_kernel_unlock(mutex); } #include #else #include #include struct sys_mutex { struct k_mutex kernel_mutex; }; #define SYS_MUTEX_DEFINE(name) \ struct sys_mutex name = { \ .kernel_mutex = _K_MUTEX_INITIALIZER(name.kernel_mutex) \ } static inline void sys_mutex_init(struct sys_mutex *mutex) { k_mutex_init(&mutex->kernel_mutex); } static inline int sys_mutex_lock(struct sys_mutex *mutex, s32_t timeout) { return k_mutex_lock(&mutex->kernel_mutex, timeout); } static inline int sys_mutex_unlock(struct sys_mutex *mutex) { if (mutex->kernel_mutex.lock_count == 0) { return -EINVAL; } if (mutex->kernel_mutex.owner != _current) { return -EPERM; } k_mutex_unlock(&mutex->kernel_mutex); return 0; } #endif /* CONFIG_USERSPACE */ #endif /* ZEPHYR_INCLUDE_SYS_MUTEX_H_ */