1 /*
2  * Copyright (c) 2020 Intel Corporation.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <kernel.h>
8 #include <kernel_structs.h>
9 #include <toolchain.h>
10 #include <ksched.h>
11 #include <wait_q.h>
12 #include <syscall_handler.h>
13 
14 static struct k_spinlock lock;
15 
z_impl_k_condvar_init(struct k_condvar * condvar)16 int z_impl_k_condvar_init(struct k_condvar *condvar)
17 {
18 	z_waitq_init(&condvar->wait_q);
19 	z_object_init(condvar);
20 
21 	SYS_PORT_TRACING_OBJ_INIT(k_condvar, condvar, 0);
22 
23 	return 0;
24 }
25 
26 #ifdef CONFIG_USERSPACE
z_vrfy_k_condvar_init(struct k_condvar * condvar)27 int z_vrfy_k_condvar_init(struct k_condvar *condvar)
28 {
29 	Z_OOPS(Z_SYSCALL_OBJ_INIT(condvar, K_OBJ_CONDVAR));
30 	return z_impl_k_condvar_init(condvar);
31 }
32 #include <syscalls/k_condvar_init_mrsh.c>
33 #endif
34 
z_impl_k_condvar_signal(struct k_condvar * condvar)35 int z_impl_k_condvar_signal(struct k_condvar *condvar)
36 {
37 	k_spinlock_key_t key = k_spin_lock(&lock);
38 
39 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_condvar, signal, condvar);
40 
41 	struct k_thread *thread = z_unpend_first_thread(&condvar->wait_q);
42 
43 	if (thread != NULL) {
44 		SYS_PORT_TRACING_OBJ_FUNC_BLOCKING(k_condvar, signal, condvar, K_FOREVER);
45 
46 		arch_thread_return_value_set(thread, 0);
47 		z_ready_thread(thread);
48 		z_reschedule(&lock, key);
49 	} else {
50 		k_spin_unlock(&lock, key);
51 	}
52 
53 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_condvar, signal, condvar, 0);
54 
55 	return 0;
56 }
57 
58 #ifdef CONFIG_USERSPACE
z_vrfy_k_condvar_signal(struct k_condvar * condvar)59 int z_vrfy_k_condvar_signal(struct k_condvar *condvar)
60 {
61 	Z_OOPS(Z_SYSCALL_OBJ(condvar, K_OBJ_CONDVAR));
62 	return z_impl_k_condvar_signal(condvar);
63 }
64 #include <syscalls/k_condvar_signal_mrsh.c>
65 #endif
66 
z_impl_k_condvar_broadcast(struct k_condvar * condvar)67 int z_impl_k_condvar_broadcast(struct k_condvar *condvar)
68 {
69 	struct k_thread *pending_thread;
70 	k_spinlock_key_t key;
71 	int woken = 0;
72 
73 	key = k_spin_lock(&lock);
74 
75 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_condvar, broadcast, condvar);
76 
77 	/* wake up any threads that are waiting to write */
78 	while ((pending_thread = z_unpend_first_thread(&condvar->wait_q)) !=
79 	       NULL) {
80 		woken++;
81 		arch_thread_return_value_set(pending_thread, 0);
82 		z_ready_thread(pending_thread);
83 	}
84 
85 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_condvar, broadcast, condvar, woken);
86 
87 	z_reschedule(&lock, key);
88 
89 	return woken;
90 }
91 #ifdef CONFIG_USERSPACE
z_vrfy_k_condvar_broadcast(struct k_condvar * condvar)92 int z_vrfy_k_condvar_broadcast(struct k_condvar *condvar)
93 {
94 	Z_OOPS(Z_SYSCALL_OBJ(condvar, K_OBJ_CONDVAR));
95 	return z_impl_k_condvar_broadcast(condvar);
96 }
97 #include <syscalls/k_condvar_broadcast_mrsh.c>
98 #endif
99 
z_impl_k_condvar_wait(struct k_condvar * condvar,struct k_mutex * mutex,k_timeout_t timeout)100 int z_impl_k_condvar_wait(struct k_condvar *condvar, struct k_mutex *mutex,
101 			  k_timeout_t timeout)
102 {
103 	k_spinlock_key_t key;
104 	int ret;
105 
106 	SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_condvar, wait, condvar);
107 
108 	key = k_spin_lock(&lock);
109 	k_mutex_unlock(mutex);
110 
111 	ret = z_pend_curr(&lock, key, &condvar->wait_q, timeout);
112 	k_mutex_lock(mutex, K_FOREVER);
113 
114 	SYS_PORT_TRACING_OBJ_FUNC_EXIT(k_condvar, wait, condvar, ret);
115 
116 	return ret;
117 }
118 #ifdef CONFIG_USERSPACE
z_vrfy_k_condvar_wait(struct k_condvar * condvar,struct k_mutex * mutex,k_timeout_t timeout)119 int z_vrfy_k_condvar_wait(struct k_condvar *condvar, struct k_mutex *mutex,
120 			  k_timeout_t timeout)
121 {
122 	Z_OOPS(Z_SYSCALL_OBJ(condvar, K_OBJ_CONDVAR));
123 	Z_OOPS(Z_SYSCALL_OBJ(mutex, K_OBJ_MUTEX));
124 	return z_impl_k_condvar_wait(condvar, mutex, timeout);
125 }
126 #include <syscalls/k_condvar_wait_mrsh.c>
127 #endif
128