zephyr/include/misc/mutex.h

150 lines
3.9 KiB
C

/*
* Copyright (c) 2019 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef ZEPHYR_INCLUDE_MISC_MUTEX_H_
#define ZEPHYR_INCLUDE_MISC_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 <atomic.h>
#include <zephyr/types.h>
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 <syscalls/mutex.h>
#else
#include <kernel.h>
#include <kernel_structs.h>
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_MISC_MUTEX_H_ */