001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019 #include <sos/klibc.h>
020 #include <sos/list.h>
021 #include <sos/assert.h>
022 #include <hwcore/irq.h>
023
024 #include "kwaitq.h"
025
026
027 sos_ret_t sos_kwaitq_init(struct sos_kwaitq *kwq,
028 const char *name)
029 {
030 memset(kwq, 0x0, sizeof(struct sos_kwaitq));
031
032 #ifdef SOS_KWQ_DEBUG
033 if (! name)
034 name = "<unknown>";
035 strzcpy(kwq->name, name, SOS_KWQ_DEBUG_MAX_NAMELEN);
036 #endif
037 list_init_named(kwq->waiting_list,
038 prev_entry_in_kwaitq, next_entry_in_kwaitq);
039
040 return SOS_OK;
041 }
042
043
044 sos_ret_t sos_kwaitq_dispose(struct sos_kwaitq *kwq)
045 {
046 sos_ui32_t flags;
047 sos_ret_t retval;
048
049 sos_disable_IRQs(flags);
050 if (list_is_empty_named(kwq->waiting_list,
051 prev_entry_in_kwaitq, next_entry_in_kwaitq))
052 retval = SOS_OK;
053 else
054 retval = -SOS_EBUSY;
055
056 sos_restore_IRQs(flags);
057 return retval;
058 }
059
060
061 sos_bool_t sos_kwaitq_is_empty(const struct sos_kwaitq *kwq)
062 {
063 sos_ui32_t flags;
064 sos_ret_t retval;
065
066 sos_disable_IRQs(flags);
067 retval = list_is_empty_named(kwq->waiting_list,
068 prev_entry_in_kwaitq, next_entry_in_kwaitq);
069
070 sos_restore_IRQs(flags);
071 return retval;
072 }
073
074
075 sos_ret_t sos_kwaitq_init_entry(struct sos_kwaitq_entry *kwq_entry)
076 {
077 memset(kwq_entry, 0x0, sizeof(struct sos_kwaitq_entry));
078 kwq_entry->thread = sos_thread_get_current();
079 return SOS_OK;
080 }
081
082
083
084
085
086 inline static sos_ret_t _kwaitq_add_entry(struct sos_kwaitq *kwq,
087 struct sos_kwaitq_entry *kwq_entry)
088 {
089
090 SOS_ASSERT_FATAL(NULL == kwq_entry->kwaitq);
091
092
093 SOS_ASSERT_FATAL(NULL != kwq_entry->thread);
094
095
096 kwq_entry->wakeup_triggered = FALSE;
097 kwq_entry->wakeup_status = SOS_OK;
098
099
100 list_add_tail_named(kwq->waiting_list, kwq_entry,
101 prev_entry_in_kwaitq, next_entry_in_kwaitq);
102
103
104 list_add_tail_named(kwq_entry->thread->kwaitq_list, kwq_entry,
105 prev_entry_for_thread, next_entry_for_thread);
106
107 kwq_entry->kwaitq = kwq;
108
109 return SOS_OK;
110 }
111
112
113 sos_ret_t sos_kwaitq_add_entry(struct sos_kwaitq *kwq,
114 struct sos_kwaitq_entry *kwq_entry)
115 {
116 sos_ui32_t flags;
117 sos_ret_t retval;
118
119 sos_disable_IRQs(flags);
120 retval = _kwaitq_add_entry(kwq, kwq_entry);
121 sos_restore_IRQs(flags);
122
123 return retval;
124 }
125
126
127
128
129 inline static sos_ret_t
130 _kwaitq_remove_entry(struct sos_kwaitq *kwq,
131 struct sos_kwaitq_entry *kwq_entry)
132 {
133 SOS_ASSERT_FATAL(kwq_entry->kwaitq == kwq);
134
135 list_delete_named(kwq->waiting_list, kwq_entry,
136 prev_entry_in_kwaitq, next_entry_in_kwaitq);
137
138 list_delete_named(kwq_entry->thread->kwaitq_list, kwq_entry,
139 prev_entry_for_thread, next_entry_for_thread);
140
141 kwq_entry->kwaitq = NULL;
142 return SOS_OK;
143 }
144
145
146 sos_ret_t sos_kwaitq_remove_entry(struct sos_kwaitq *kwq,
147 struct sos_kwaitq_entry *kwq_entry)
148 {
149 sos_ui32_t flags;
150 sos_ret_t retval;
151
152 sos_disable_IRQs(flags);
153 retval = _kwaitq_remove_entry(kwq, kwq_entry);
154 sos_restore_IRQs(flags);
155
156 return retval;
157 }
158
159
160 sos_ret_t sos_kwaitq_wait(struct sos_kwaitq *kwq,
161 struct sos_time *timeout)
162 {
163 sos_ui32_t flags;
164 sos_ret_t retval;
165 struct sos_kwaitq_entry kwq_entry;
166
167 sos_kwaitq_init_entry(& kwq_entry);
168
169 sos_disable_IRQs(flags);
170
171 retval = _kwaitq_add_entry(kwq, & kwq_entry);
172
173
174 sos_thread_sleep(timeout);
175
176
177
178 if (! kwq_entry.wakeup_triggered)
179 {
180
181
182 _kwaitq_remove_entry(kwq, & kwq_entry);
183 retval = -SOS_EINTR;
184 }
185 else
186 {
187 retval = kwq_entry.wakeup_status;
188 }
189
190 sos_restore_IRQs(flags);
191
192
193 return retval;
194 }
195
196
197 sos_ret_t sos_kwaitq_wakeup(struct sos_kwaitq *kwq,
198 unsigned int nb_threads,
199 sos_ret_t wakeup_status)
200 {
201 sos_ui32_t flags;
202
203 sos_disable_IRQs(flags);
204
205
206
207 while (! list_is_empty_named(kwq->waiting_list,
208 prev_entry_in_kwaitq, next_entry_in_kwaitq))
209 {
210 struct sos_kwaitq_entry *kwq_entry
211 = list_get_head_named(kwq->waiting_list,
212 prev_entry_in_kwaitq, next_entry_in_kwaitq);
213
214
215 if (nb_threads <= 0)
216 break;
217
218
219
220
221
222
223 if (SOS_THR_RUNNING == sos_thread_get_state(kwq_entry->thread))
224 {
225
226
227
228
229 continue;
230 }
231 else
232 {
233
234 sos_sched_set_ready(kwq_entry->thread);
235 }
236
237
238 _kwaitq_remove_entry(kwq, kwq_entry);
239 kwq_entry->wakeup_triggered = TRUE;
240 kwq_entry->wakeup_status = wakeup_status;
241
242
243 nb_threads --;
244 }
245
246 sos_restore_IRQs(flags);
247
248 return SOS_OK;
249 }