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 /* CONFIG_OBJ_CORE_CONDVAR */
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 /* CONFIG_OBJ_CORE_CONDVAR */
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 <zephyr/syscalls/k_condvar_init_mrsh.c>
42 #endif /* CONFIG_USERSPACE */
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 (unlikely(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 <zephyr/syscalls/k_condvar_signal_mrsh.c>
74 #endif /* CONFIG_USERSPACE */
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 	for (pending_thread = z_unpend_first_thread(&condvar->wait_q); pending_thread != NULL;
88 		 pending_thread = z_unpend_first_thread(&condvar->wait_q)) {
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 
97 	if (woken == 0) {
98 		k_spin_unlock(&lock, key);
99 	} else {
100 		z_reschedule(&lock, key);
101 	}
102 
103 	return woken;
104 }
105 #ifdef CONFIG_USERSPACE
z_vrfy_k_condvar_broadcast(struct k_condvar * condvar)106 int z_vrfy_k_condvar_broadcast(struct k_condvar *condvar)
107 {
108 	K_OOPS(K_SYSCALL_OBJ(condvar, K_OBJ_CONDVAR));
109 	return z_impl_k_condvar_broadcast(condvar);
110 }
111 #include <zephyr/syscalls/k_condvar_broadcast_mrsh.c>
112 #endif /* CONFIG_USERSPACE */
113 
z_impl_k_condvar_wait(struct k_condvar * condvar,struct k_mutex * mutex,k_timeout_t timeout)114 int z_impl_k_condvar_wait(struct k_condvar *condvar, struct k_mutex *mutex,
115 			  k_timeout_t timeout)
116 {
117 	k_spinlock_key_t key;
118 	int ret;
119 
120 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_condvar, wait, condvar);
121 
122 	key = k_spin_lock(&lock);
123 	k_mutex_unlock(mutex);
124 
125 	ret = z_pend_curr(&lock, key, &condvar->wait_q, timeout);
126 	k_mutex_lock(mutex, K_FOREVER);
127 
128 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_condvar, wait, condvar, ret);
129 
130 	return ret;
131 }
132 #ifdef CONFIG_USERSPACE
z_vrfy_k_condvar_wait(struct k_condvar * condvar,struct k_mutex * mutex,k_timeout_t timeout)133 int z_vrfy_k_condvar_wait(struct k_condvar *condvar, struct k_mutex *mutex,
134 			  k_timeout_t timeout)
135 {
136 	K_OOPS(K_SYSCALL_OBJ(condvar, K_OBJ_CONDVAR));
137 	K_OOPS(K_SYSCALL_OBJ(mutex, K_OBJ_MUTEX));
138 	return z_impl_k_condvar_wait(condvar, mutex, timeout);
139 }
140 #include <zephyr/syscalls/k_condvar_wait_mrsh.c>
141 #endif /* CONFIG_USERSPACE */
142 
143 #ifdef CONFIG_OBJ_CORE_CONDVAR
init_condvar_obj_core_list(void)144 static int init_condvar_obj_core_list(void)
145 {
146 	/* Initialize condvar object type */
147 
148 	z_obj_type_init(&obj_type_condvar, K_OBJ_TYPE_CONDVAR_ID,
149 			offsetof(struct k_condvar, obj_core));
150 
151 	/* Initialize and link statically defined condvars */
152 
153 	STRUCT_SECTION_FOREACH(k_condvar, condvar) {
154 		k_obj_core_init_and_link(K_OBJ_CORE(condvar),
155 					 &obj_type_condvar);
156 	}
157 
158 	return 0;
159 }
160 
161 SYS_INIT(init_condvar_obj_core_list, PRE_KERNEL_1,
162 	 CONFIG_KERNEL_INIT_PRIORITY_OBJECTS);
163 #endif /* CONFIG_OBJ_CORE_CONDVAR */
164