1 /*
2  * Copyright (c) 2019 Intel corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/kernel_structs.h>
9 #include <zephyr/spinlock.h>
10 #include <kswap.h>
11 #include <zephyr/internal/syscall_handler.h>
12 #include <zephyr/init.h>
13 #include <ksched.h>
14 
k_futex_find_data(struct k_futex * futex)15 static struct z_futex_data *k_futex_find_data(struct k_futex *futex)
16 {
17 	struct k_object *obj;
18 
19 	obj = k_object_find(futex);
20 	if ((obj == NULL) || (obj->type != K_OBJ_FUTEX)) {
21 		return NULL;
22 	}
23 
24 	return obj->data.futex_data;
25 }
26 
z_impl_k_futex_wake(struct k_futex * futex,bool wake_all)27 int z_impl_k_futex_wake(struct k_futex *futex, bool wake_all)
28 {
29 	k_spinlock_key_t key;
30 	unsigned int woken = 0U;
31 	struct k_thread *thread;
32 	struct z_futex_data *futex_data;
33 
34 	futex_data = k_futex_find_data(futex);
35 	if (futex_data == NULL) {
36 		return -EINVAL;
37 	}
38 
39 	key = k_spin_lock(&futex_data->lock);
40 
41 	do {
42 		thread = z_unpend_first_thread(&futex_data->wait_q);
43 		if (thread != NULL) {
44 			woken++;
45 			arch_thread_return_value_set(thread, 0);
46 			z_ready_thread(thread);
47 		}
48 	} while (thread && wake_all);
49 
50 	if (woken == 0) {
51 		k_spin_unlock(&futex_data->lock, key);
52 	} else {
53 		z_reschedule(&futex_data->lock, key);
54 	}
55 
56 	return woken;
57 }
58 
z_vrfy_k_futex_wake(struct k_futex * futex,bool wake_all)59 static inline int z_vrfy_k_futex_wake(struct k_futex *futex, bool wake_all)
60 {
61 	if (K_SYSCALL_MEMORY_WRITE(futex, sizeof(struct k_futex)) != 0) {
62 		return -EACCES;
63 	}
64 
65 	return z_impl_k_futex_wake(futex, wake_all);
66 }
67 #include <zephyr/syscalls/k_futex_wake_mrsh.c>
68 
z_impl_k_futex_wait(struct k_futex * futex,int expected,k_timeout_t timeout)69 int z_impl_k_futex_wait(struct k_futex *futex, int expected,
70 			k_timeout_t timeout)
71 {
72 	int ret;
73 	k_spinlock_key_t key;
74 	struct z_futex_data *futex_data;
75 
76 	futex_data = k_futex_find_data(futex);
77 	if (futex_data == NULL) {
78 		return -EINVAL;
79 	}
80 
81 	if (atomic_get(&futex->val) != (atomic_val_t)expected) {
82 		return -EAGAIN;
83 	}
84 
85 	key = k_spin_lock(&futex_data->lock);
86 
87 	ret = z_pend_curr(&futex_data->lock,
88 			key, &futex_data->wait_q, timeout);
89 	if (ret == -EAGAIN) {
90 		ret = -ETIMEDOUT;
91 	}
92 
93 	return ret;
94 }
95 
z_vrfy_k_futex_wait(struct k_futex * futex,int expected,k_timeout_t timeout)96 static inline int z_vrfy_k_futex_wait(struct k_futex *futex, int expected,
97 				      k_timeout_t timeout)
98 {
99 	if (K_SYSCALL_MEMORY_WRITE(futex, sizeof(struct k_futex)) != 0) {
100 		return -EACCES;
101 	}
102 
103 	return z_impl_k_futex_wait(futex, expected, timeout);
104 }
105 #include <zephyr/syscalls/k_futex_wait_mrsh.c>
106