1 /*
2  * Copyright (c) 2019 Intel corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <kernel.h>
8 #include <kernel_structs.h>
9 #include <spinlock.h>
10 #include <kswap.h>
11 #include <syscall_handler.h>
12 #include <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 z_object *obj;
18 
19 	obj = z_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 	z_reschedule(&futex_data->lock, key);
51 
52 	return woken;
53 }
54 
z_vrfy_k_futex_wake(struct k_futex * futex,bool wake_all)55 static inline int z_vrfy_k_futex_wake(struct k_futex *futex, bool wake_all)
56 {
57 	if (Z_SYSCALL_MEMORY_WRITE(futex, sizeof(struct k_futex)) != 0) {
58 		return -EACCES;
59 	}
60 
61 	return z_impl_k_futex_wake(futex, wake_all);
62 }
63 #include <syscalls/k_futex_wake_mrsh.c>
64 
z_impl_k_futex_wait(struct k_futex * futex,int expected,k_timeout_t timeout)65 int z_impl_k_futex_wait(struct k_futex *futex, int expected,
66 			k_timeout_t timeout)
67 {
68 	int ret;
69 	k_spinlock_key_t key;
70 	struct z_futex_data *futex_data;
71 
72 	futex_data = k_futex_find_data(futex);
73 	if (futex_data == NULL) {
74 		return -EINVAL;
75 	}
76 
77 	if (atomic_get(&futex->val) != (atomic_val_t)expected) {
78 		return -EAGAIN;
79 	}
80 
81 	key = k_spin_lock(&futex_data->lock);
82 
83 	ret = z_pend_curr(&futex_data->lock,
84 			key, &futex_data->wait_q, timeout);
85 	if (ret == -EAGAIN) {
86 		ret = -ETIMEDOUT;
87 	}
88 
89 	return ret;
90 }
91 
z_vrfy_k_futex_wait(struct k_futex * futex,int expected,k_timeout_t timeout)92 static inline int z_vrfy_k_futex_wait(struct k_futex *futex, int expected,
93 				      k_timeout_t timeout)
94 {
95 	if (Z_SYSCALL_MEMORY_WRITE(futex, sizeof(struct k_futex)) != 0) {
96 		return -EACCES;
97 	}
98 
99 	return z_impl_k_futex_wait(futex, expected, timeout);
100 }
101 #include <syscalls/k_futex_wait_mrsh.c>
102