1 /*
2 * Copyright (c) 2020 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/toolchain.h>
10 #include <ksched.h>
11 #include <wait_q.h>
12 #include <zephyr/internal/syscall_handler.h>
13 #include <zephyr/init.h>
14
15 #ifdef CONFIG_OBJ_CORE_CONDVAR
16 static struct k_obj_type obj_type_condvar;
17 #endif
18
19 static struct k_spinlock lock;
20
z_impl_k_condvar_init(struct k_condvar * condvar)21 int z_impl_k_condvar_init(struct k_condvar *condvar)
22 {
23 z_waitq_init(&condvar->wait_q);
24 k_object_init(condvar);
25
26 #ifdef CONFIG_OBJ_CORE_CONDVAR
27 k_obj_core_init_and_link(K_OBJ_CORE(condvar), &obj_type_condvar);
28 #endif
29
30 SYS_PORT_TRACING_OBJ_INIT(k_condvar, condvar, 0);
31
32 return 0;
33 }
34
35 #ifdef CONFIG_USERSPACE
z_vrfy_k_condvar_init(struct k_condvar * condvar)36 int z_vrfy_k_condvar_init(struct k_condvar *condvar)
37 {
38 K_OOPS(K_SYSCALL_OBJ_INIT(condvar, K_OBJ_CONDVAR));
39 return z_impl_k_condvar_init(condvar);
40 }
41 #include <syscalls/k_condvar_init_mrsh.c>
42 #endif
43
z_impl_k_condvar_signal(struct k_condvar * condvar)44 int z_impl_k_condvar_signal(struct k_condvar *condvar)
45 {
46 k_spinlock_key_t key = k_spin_lock(&lock);
47
48 SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_condvar, signal, condvar);
49
50 struct k_thread *thread = z_unpend_first_thread(&condvar->wait_q);
51
52 if (thread != NULL) {
53 SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_condvar, signal, condvar, K_FOREVER);
54
55 arch_thread_return_value_set(thread, 0);
56 z_ready_thread(thread);
57 z_reschedule(&lock, key);
58 } else {
59 k_spin_unlock(&lock, key);
60 }
61
62 SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_condvar, signal, condvar, 0);
63
64 return 0;
65 }
66
67 #ifdef CONFIG_USERSPACE
z_vrfy_k_condvar_signal(struct k_condvar * condvar)68 int z_vrfy_k_condvar_signal(struct k_condvar *condvar)
69 {
70 K_OOPS(K_SYSCALL_OBJ(condvar, K_OBJ_CONDVAR));
71 return z_impl_k_condvar_signal(condvar);
72 }
73 #include <syscalls/k_condvar_signal_mrsh.c>
74 #endif
75
z_impl_k_condvar_broadcast(struct k_condvar * condvar)76 int z_impl_k_condvar_broadcast(struct k_condvar *condvar)
77 {
78 struct k_thread *pending_thread;
79 k_spinlock_key_t key;
80 int woken = 0;
81
82 key = k_spin_lock(&lock);
83
84 SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_condvar, broadcast, condvar);
85
86 /* wake up any threads that are waiting to write */
87 while ((pending_thread = z_unpend_first_thread(&condvar->wait_q)) !=
88 NULL) {
89 woken++;
90 arch_thread_return_value_set(pending_thread, 0);
91 z_ready_thread(pending_thread);
92 }
93
94 SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_condvar, broadcast, condvar, woken);
95
96 z_reschedule(&lock, key);
97
98 return woken;
99 }
100 #ifdef CONFIG_USERSPACE
z_vrfy_k_condvar_broadcast(struct k_condvar * condvar)101 int z_vrfy_k_condvar_broadcast(struct k_condvar *condvar)
102 {
103 K_OOPS(K_SYSCALL_OBJ(condvar, K_OBJ_CONDVAR));
104 return z_impl_k_condvar_broadcast(condvar);
105 }
106 #include <syscalls/k_condvar_broadcast_mrsh.c>
107 #endif
108
z_impl_k_condvar_wait(struct k_condvar * condvar,struct k_mutex * mutex,k_timeout_t timeout)109 int z_impl_k_condvar_wait(struct k_condvar *condvar, struct k_mutex *mutex,
110 k_timeout_t timeout)
111 {
112 k_spinlock_key_t key;
113 int ret;
114
115 SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_condvar, wait, condvar);
116
117 key = k_spin_lock(&lock);
118 k_mutex_unlock(mutex);
119
120 ret = z_pend_curr(&lock, key, &condvar->wait_q, timeout);
121 k_mutex_lock(mutex, K_FOREVER);
122
123 SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_condvar, wait, condvar, ret);
124
125 return ret;
126 }
127 #ifdef CONFIG_USERSPACE
z_vrfy_k_condvar_wait(struct k_condvar * condvar,struct k_mutex * mutex,k_timeout_t timeout)128 int z_vrfy_k_condvar_wait(struct k_condvar *condvar, struct k_mutex *mutex,
129 k_timeout_t timeout)
130 {
131 K_OOPS(K_SYSCALL_OBJ(condvar, K_OBJ_CONDVAR));
132 K_OOPS(K_SYSCALL_OBJ(mutex, K_OBJ_MUTEX));
133 return z_impl_k_condvar_wait(condvar, mutex, timeout);
134 }
135 #include <syscalls/k_condvar_wait_mrsh.c>
136 #endif
137
138 #ifdef CONFIG_OBJ_CORE_CONDVAR
init_condvar_obj_core_list(void)139 static int init_condvar_obj_core_list(void)
140 {
141 /* Initialize condvar object type */
142
143 z_obj_type_init(&obj_type_condvar, K_OBJ_TYPE_CONDVAR_ID,
144 offsetof(struct k_condvar, obj_core));
145
146 /* Initialize and link statically defined condvars */
147
148 STRUCT_SECTION_FOREACH(k_condvar, condvar) {
149 k_obj_core_init_and_link(K_OBJ_CORE(condvar),
150 &obj_type_condvar);
151 }
152
153 return 0;
154 }
155
156 SYS_INIT(init_condvar_obj_core_list, PRE_KERNEL_1,
157 CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
158 #endif
159