SimpleOS

LXR

Navigation



Site hébergé par : enix

The LXR Cross Referencer for SOS

source navigation ]
diff markup ]
identifier search ]
general search ]
 
 
Article:1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 6.5 ] [ 7 ] [ 7.5 ] [ 8 ] [ 9 ] [ 9.5 ]

001 /* Copyright (C) 2004 David Decotigny
002 
003    This program is free software; you can redistribute it and/or
004    modify it under the terms of the GNU General Public License
005    as published by the Free Software Foundation; either version 2
006    of the License, or (at your option) any later version.
007    
008    This program is distributed in the hope that it will be useful,
009    but WITHOUT ANY WARRANTY; without even the implied warranty of
010    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
011    GNU General Public License for more details.
012    
013    You should have received a copy of the GNU General Public License
014    along with this program; if not, write to the Free Software
015    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
016    USA. 
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                           sos_kwaitq_ordering_t ordering)
030 {
031   memset(kwq, 0x0, sizeof(struct sos_kwaitq));
032 
033 #ifdef SOS_KWQ_DEBUG
034   if (! name)
035     name = "<unknown>";
036   strzcpy(kwq->name, name, SOS_KWQ_DEBUG_MAX_NAMELEN);
037 #endif
038   kwq->ordering = ordering;
039   list_init_named(kwq->waiting_list,
040                   prev_entry_in_kwaitq, next_entry_in_kwaitq);
041 
042   return SOS_OK;
043 }
044 
045 
046 sos_ret_t sos_kwaitq_dispose(struct sos_kwaitq *kwq)
047 {
048   sos_ui32_t flags;
049   sos_ret_t retval;
050 
051   sos_disable_IRQs(flags);
052   if (list_is_empty_named(kwq->waiting_list,
053                           prev_entry_in_kwaitq, next_entry_in_kwaitq))
054     retval = SOS_OK;
055   else
056     retval = -SOS_EBUSY;
057 
058   sos_restore_IRQs(flags);
059   return retval;
060 }
061 
062 
063 sos_bool_t sos_kwaitq_is_empty(const struct sos_kwaitq *kwq)
064 {
065   sos_ui32_t flags;
066   sos_ret_t retval;
067 
068   sos_disable_IRQs(flags);
069   retval = list_is_empty_named(kwq->waiting_list,
070                                prev_entry_in_kwaitq, next_entry_in_kwaitq);
071 
072   sos_restore_IRQs(flags);
073   return retval;  
074 }
075 
076 
077 sos_ret_t sos_kwaitq_init_entry(struct sos_kwaitq_entry *kwq_entry)
078 {
079   memset(kwq_entry, 0x0, sizeof(struct sos_kwaitq_entry));
080   kwq_entry->thread = sos_thread_get_current();
081   return SOS_OK;
082 }
083 
084 
085 /** Internal helper function equivalent to sos_kwaitq_add_entry(), but
086     without interrupt protection scheme */
087 inline static sos_ret_t
088 _kwaitq_add_entry(struct sos_kwaitq *kwq,
089                   struct sos_kwaitq_entry *kwq_entry,
090                   sos_sched_priority_t prio)
091 {
092   struct sos_kwaitq_entry *next_entry = NULL, *entry;
093   int nb_entries;
094 
095   /* This entry is already added in the kwaitq ! */
096   SOS_ASSERT_FATAL(NULL == kwq_entry->kwaitq);
097 
098   /* sos_kwaitq_init_entry() has not been called ?! */
099   SOS_ASSERT_FATAL(NULL != kwq_entry->thread);
100 
101   /* (Re-)Initialize wakeup status of the entry */
102   kwq_entry->wakeup_triggered = FALSE;
103   kwq_entry->wakeup_status    = SOS_OK;
104 
105   /* Insert this entry in the kwaitq waiting list */
106   switch (kwq->ordering)
107     {
108     case SOS_KWQ_ORDER_FIFO:
109       /* Insertion in the list in FIFO order */
110       {
111         /* Add the thread in the list */
112         list_add_tail_named(kwq->waiting_list, kwq_entry,
113                             prev_entry_in_kwaitq, next_entry_in_kwaitq);
114       }
115       break;
116       
117     case SOS_KWQ_ORDER_PRIO:
118       /* Priority-driven insertion in the list */
119       {
120         /* Look for the place where to insert the thread in the queue (we
121            want to order them in order of increasing priorities) */
122         list_foreach_forward_named(kwq->waiting_list, entry, nb_entries,
123                                    prev_entry_in_kwaitq, next_entry_in_kwaitq)
124           {
125             /* Does the thread we want to insert have higher priority than
126                the given thread in the queue ? */
127             if (SOS_SCHED_PRIO_CMP(prio,
128                                    sos_thread_get_priority(entry->thread))
129                 > 0)
130               {
131                 /* Yes: we insert before this given thread */
132                 next_entry = entry;
133                 break;
134               }
135           }
136 
137         /* Actually insert the entry in the list */
138         if (next_entry != NULL)
139           {
140             list_insert_before_named(kwq->waiting_list, kwq_entry, next_entry,
141                                      prev_entry_in_kwaitq,
142                                      next_entry_in_kwaitq);
143           }
144         else
145           {
146             /* The thread we want to insert has less priority than any
147                other in the list */
148             list_add_tail_named(kwq->waiting_list, kwq_entry,
149                                 prev_entry_in_kwaitq, next_entry_in_kwaitq);
150           }
151       }
152       break;
153 
154     default:
155       SOS_FATAL_ERROR("Invalid kwq ordering %d !\n", kwq->ordering);
156       break;
157     }
158 
159   /* Update the list of waitqueues for the thread */
160   list_add_tail_named(kwq_entry->thread->kwaitq_list, kwq_entry,
161                       prev_entry_for_thread, next_entry_for_thread);
162 
163   kwq_entry->kwaitq = kwq;
164   
165   return SOS_OK;
166 }
167 
168 
169 sos_ret_t sos_kwaitq_add_entry(struct sos_kwaitq *kwq,
170                                struct sos_kwaitq_entry *kwq_entry)
171 {
172   sos_ui32_t flags;
173   sos_ret_t retval;
174 
175   sos_disable_IRQs(flags);
176   retval = _kwaitq_add_entry(kwq, kwq_entry,
177                              sos_thread_get_priority(kwq_entry->thread));
178   sos_restore_IRQs(flags);
179 
180   return retval;
181 }
182 
183 
184 /** Internal helper function equivalent to sos_kwaitq_remove_entry(),
185     but without interrupt protection scheme */
186 inline static sos_ret_t
187 _kwaitq_remove_entry(struct sos_kwaitq *kwq,
188                      struct sos_kwaitq_entry *kwq_entry)
189 {
190   SOS_ASSERT_FATAL(kwq_entry->kwaitq == kwq);
191 
192   list_delete_named(kwq->waiting_list, kwq_entry,
193                     prev_entry_in_kwaitq, next_entry_in_kwaitq);
194 
195   list_delete_named(kwq_entry->thread->kwaitq_list, kwq_entry,
196                     prev_entry_for_thread, next_entry_for_thread);
197 
198   kwq_entry->kwaitq = NULL;
199   return SOS_OK;
200 }
201 
202 
203 sos_ret_t sos_kwaitq_remove_entry(struct sos_kwaitq *kwq,
204                                   struct sos_kwaitq_entry *kwq_entry)
205 {
206   sos_ui32_t flags;
207   sos_ret_t retval;
208 
209   sos_disable_IRQs(flags);
210   retval = _kwaitq_remove_entry(kwq, kwq_entry);
211   sos_restore_IRQs(flags);
212 
213   return retval;
214 }
215 
216 
217 sos_ret_t sos_kwaitq_wait(struct sos_kwaitq *kwq,
218                           struct sos_time *timeout)
219 {
220   sos_ui32_t flags;
221   sos_ret_t retval;
222   struct sos_kwaitq_entry kwq_entry;
223 
224   sos_kwaitq_init_entry(& kwq_entry);
225 
226   sos_disable_IRQs(flags);
227 
228   retval = _kwaitq_add_entry(kwq, & kwq_entry,
229                              sos_thread_get_priority(kwq_entry.thread));
230 
231   /* Wait for wakeup or timeout */
232   sos_thread_sleep(timeout);
233   /* Woken up ! */
234 
235   /* Sleep delay elapsed ? */
236   if (! kwq_entry.wakeup_triggered)
237     {
238       /* Yes (timeout occured, or wakeup on another waitqueue): remove
239          the waitq entry by ourselves */
240       _kwaitq_remove_entry(kwq, & kwq_entry);
241       retval = -SOS_EINTR;
242     }
243   else
244     {
245       retval = kwq_entry.wakeup_status;
246     }
247   
248   sos_restore_IRQs(flags);
249 
250   /* We were correctly awoken: position return status */
251   return retval;
252 }
253 
254 
255 sos_ret_t sos_kwaitq_wakeup(struct sos_kwaitq *kwq,
256                             unsigned int nb_threads,
257                             sos_ret_t wakeup_status)
258 {
259   sos_ui32_t flags;
260 
261   sos_disable_IRQs(flags);
262 
263   /* Wake up as much threads waiting in waitqueue as possible (up to
264      nb_threads), scanning the list in FIFO/decreasing priority order
265      (depends on the kwaitq ordering) */
266   while (! list_is_empty_named(kwq->waiting_list,
267                                prev_entry_in_kwaitq, next_entry_in_kwaitq))
268     {
269       struct sos_kwaitq_entry *kwq_entry
270         = list_get_head_named(kwq->waiting_list,
271                               prev_entry_in_kwaitq, next_entry_in_kwaitq);
272 
273       /* Enough threads woken up ? */
274       if (nb_threads <= 0)
275         break;
276 
277       /*
278        * Ok: wake up the thread for this entry
279        */
280 
281       /* Thread already woken up ? */
282       if (SOS_THR_RUNNING == sos_thread_get_state(kwq_entry->thread))
283         {
284           /* Yes => Do nothing because WE are that woken-up thread. In
285              particular: don't call set_ready() here because this
286              would result in an inconsistent configuration (currently
287              running thread marked as "waiting for CPU"...). */
288           continue;
289         }
290       else
291         {
292           /* No => wake it up now. */
293           sos_sched_set_ready(kwq_entry->thread);
294         }
295 
296       /* Remove this waitq entry */
297       _kwaitq_remove_entry(kwq, kwq_entry);
298       kwq_entry->wakeup_triggered = TRUE;
299       kwq_entry->wakeup_status    = wakeup_status;
300 
301       /* Next iteration... */
302       nb_threads --;
303     }
304 
305   sos_restore_IRQs(flags);
306 
307   return SOS_OK;
308 }
309 
310 
311 /* Internal function (callback for thread subsystem) */
312 sos_ret_t sos_kwaitq_change_priority(struct sos_kwaitq *kwq,
313                                      struct sos_kwaitq_entry *kwq_entry,
314                                      sos_sched_priority_t priority)
315 {
316   /* Reorder the waiting list */
317   _kwaitq_remove_entry(kwq, kwq_entry);
318   _kwaitq_add_entry(kwq, kwq_entry, priority);
319 
320   return SOS_OK;
321 }

source navigation ] diff markup ] identifier search ] general search ]