zephyr/kernel/futex.c

117 lines
2.3 KiB
C

/*
* Copyright (c) 2019 Intel corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <kernel.h>
#include <kernel_structs.h>
#include <spinlock.h>
#include <kswap.h>
#include <syscall_handler.h>
#include <init.h>
#include <ksched.h>
static struct z_futex_data *k_futex_find_data(struct k_futex *futex)
{
struct _k_object *obj;
obj = z_object_find(futex);
if (obj == NULL || obj->type != K_OBJ_FUTEX) {
return NULL;
}
return (struct z_futex_data *)obj->data;
}
void z_impl_k_futex_init(struct k_futex *futex)
{
futex->val = 0U;
z_object_init(futex);
}
Z_SYSCALL_HANDLER(k_futex_init, futex)
{
if (Z_SYSCALL_MEMORY_WRITE(futex, sizeof(struct k_futex)) != 0) {
return -EACCES;
}
z_impl_k_futex_init((struct k_futex *)futex);
return 0;
}
int z_impl_k_futex_wake(struct k_futex *futex, bool wake_all)
{
k_spinlock_key_t key;
unsigned int woken = 0;
struct k_thread *thread;
struct z_futex_data *futex_data;
futex_data = k_futex_find_data(futex);
if (futex_data == NULL) {
return -EINVAL;
}
key = k_spin_lock(&futex_data->lock);
do {
thread = z_unpend_first_thread(&futex_data->wait_q);
if (thread) {
z_ready_thread(thread);
z_set_thread_return_value(thread, 0);
woken++;
}
} while (thread && wake_all);
z_reschedule(&futex_data->lock, key);
return woken;
}
Z_SYSCALL_HANDLER(k_futex_wake, futex, wake_all)
{
if (Z_SYSCALL_MEMORY_WRITE(futex, sizeof(struct k_futex)) != 0) {
return -EACCES;
}
return z_impl_k_futex_wake((struct k_futex *)futex, (bool)wake_all);
}
int z_impl_k_futex_wait(struct k_futex *futex, int expected, s32_t timeout)
{
int ret;
k_spinlock_key_t key;
struct z_futex_data *futex_data;
futex_data = k_futex_find_data(futex);
if (futex_data == NULL) {
return -EINVAL;
}
key = k_spin_lock(&futex_data->lock);
if (atomic_get(&futex->val) != (atomic_val_t)expected) {
k_spin_unlock(&futex_data->lock, key);
return -EAGAIN;
}
ret = z_pend_curr(&futex_data->lock,
key, &futex_data->wait_q, timeout);
if (ret == -EAGAIN) {
ret = -ETIMEDOUT;
}
return ret;
}
Z_SYSCALL_HANDLER(k_futex_wait, futex, expected, timeout)
{
if (Z_SYSCALL_MEMORY_WRITE(futex, sizeof(struct k_futex)) != 0) {
return -EACCES;
}
return z_impl_k_futex_wait((struct k_futex *)futex,
expected, (s32_t)timeout);
}