Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / lwip / core / sys.c
1 /**
2  * @file
3  * lwIP Operating System abstraction
4  *
5  */
6
7 /*
8  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without modification,
12  * are permitted provided that the following conditions are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright notice,
15  *    this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright notice,
17  *    this list of conditions and the following disclaimer in the documentation
18  *    and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31  * OF SUCH DAMAGE.
32  *
33  * This file is part of the lwIP TCP/IP stack.
34  *
35  * Author: Adam Dunkels <adam@sics.se>
36  *
37  */
38
39 #include "lwip/opt.h"
40
41 #if (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */
42
43 #include "lwip/sys.h"
44 #include "lwip/def.h"
45 #include "lwip/memp.h"
46 #include "lwip/tcpip.h"
47
48 /**
49  * Struct used for sys_sem_wait_timeout() to tell wether the time
50  * has run out or the semaphore has really become available.
51  */
52 struct sswt_cb
53 {
54   s16_t timeflag;
55   sys_sem_t *psem;
56 };
57
58 /**
59  * Wait (forever) for a message to arrive in an mbox.
60  * While waiting, timeouts (for this thread) are processed.
61  *
62  * @param mbox the mbox to fetch the message from
63  * @param msg the place to store the message
64  */
65 void
66 sys_mbox_fetch(sys_mbox_t mbox, void **msg)
67 {
68   u32_t time;
69   struct sys_timeouts *timeouts;
70   struct sys_timeo *tmptimeout;
71   sys_timeout_handler h;
72   void *arg;
73
74  again:
75   timeouts = sys_arch_timeouts();
76
77   if (!timeouts || !timeouts->next) {
78     UNLOCK_TCPIP_CORE();
79     time = sys_arch_mbox_fetch(mbox, msg, 0);
80     LOCK_TCPIP_CORE();
81   } else {
82     if (timeouts->next->time > 0) {
83       UNLOCK_TCPIP_CORE();
84       time = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);
85       LOCK_TCPIP_CORE();
86     } else {
87       time = SYS_ARCH_TIMEOUT;
88     }
89
90     if (time == SYS_ARCH_TIMEOUT) {
91       /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
92          could be fetched. We should now call the timeout handler and
93          deallocate the memory allocated for the timeout. */
94       tmptimeout = timeouts->next;
95       timeouts->next = tmptimeout->next;
96       h   = tmptimeout->h;
97       arg = tmptimeout->arg;
98       memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
99       if (h != NULL) {
100         LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", (void*)&h, arg));
101         h(arg);
102       }
103
104       /* We try again to fetch a message from the mbox. */
105       goto again;
106     } else {
107       /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
108          occured. The time variable is set to the number of
109          milliseconds we waited for the message. */
110       if (time < timeouts->next->time) {
111         timeouts->next->time -= time;
112       } else {
113         timeouts->next->time = 0;
114       }
115     }
116   }
117 }
118
119 /**
120  * Wait (forever) for a semaphore to become available.
121  * While waiting, timeouts (for this thread) are processed.
122  *
123  * @param sem semaphore to wait for
124  */
125 void
126 sys_sem_wait(sys_sem_t sem)
127 {
128   u32_t time;
129   struct sys_timeouts *timeouts;
130   struct sys_timeo *tmptimeout;
131   sys_timeout_handler h;
132   void *arg;
133
134  again:
135
136   timeouts = sys_arch_timeouts();
137
138   if (!timeouts || !timeouts->next) {
139     sys_arch_sem_wait(sem, 0);
140   } else {
141     if (timeouts->next->time > 0) {
142       time = sys_arch_sem_wait(sem, timeouts->next->time);
143     } else {
144       time = SYS_ARCH_TIMEOUT;
145     }
146
147     if (time == SYS_ARCH_TIMEOUT) {
148       /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
149         could be fetched. We should now call the timeout handler and
150         deallocate the memory allocated for the timeout. */
151       tmptimeout = timeouts->next;
152       timeouts->next = tmptimeout->next;
153       h = tmptimeout->h;
154       arg = tmptimeout->arg;
155       memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
156       if (h != NULL) {
157         LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", (void*)&h, (void *)arg));
158         h(arg);
159       }
160
161       /* We try again to fetch a message from the mbox. */
162       goto again;
163     } else {
164       /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
165          occured. The time variable is set to the number of
166          milliseconds we waited for the message. */
167       if (time < timeouts->next->time) {
168         timeouts->next->time -= time;
169       } else {
170         timeouts->next->time = 0;
171       }
172     }
173   }
174 }
175
176 /**
177  * Create a one-shot timer (aka timeout). Timeouts are processed in the
178  * following cases:
179  * - while waiting for a message using sys_mbox_fetch()
180  * - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout()
181  * - while sleeping using the inbuilt sys_msleep()
182  *
183  * @param msecs time in milliseconds after that the timer should expire
184  * @param h callback function to call when msecs have elapsed
185  * @param arg argument to pass to the callback function
186  */
187 void
188 sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
189 {
190   struct sys_timeouts *timeouts;
191   struct sys_timeo *timeout, *t;
192
193   timeout = memp_malloc(MEMP_SYS_TIMEOUT);
194   if (timeout == NULL) {
195     LWIP_ASSERT("sys_timeout: timeout != NULL", timeout != NULL);
196     return;
197   }
198   timeout->next = NULL;
199   timeout->h = h;
200   timeout->arg = arg;
201   timeout->time = msecs;
202
203   timeouts = sys_arch_timeouts();
204
205   LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",
206     (void *)timeout, msecs, (void*)&h, (void *)arg));
207
208   if (timeouts == NULL) {
209     LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);
210     return;
211   }
212
213   if (timeouts->next == NULL) {
214     timeouts->next = timeout;
215     return;
216   }
217
218   if (timeouts->next->time > msecs) {
219     timeouts->next->time -= msecs;
220     timeout->next = timeouts->next;
221     timeouts->next = timeout;
222   } else {
223     for(t = timeouts->next; t != NULL; t = t->next) {
224       timeout->time -= t->time;
225       if (t->next == NULL || t->next->time > timeout->time) {
226         if (t->next != NULL) {
227           t->next->time -= timeout->time;
228         }
229         timeout->next = t->next;
230         t->next = timeout;
231         break;
232       }
233     }
234   }
235 }
236
237 /**
238  * Go through timeout list (for this task only) and remove the first matching
239  * entry, even though the timeout has not triggered yet.
240  *
241  * @note This function only works as expected if there is only one timeout
242  * calling 'h' in the list of timeouts.
243  *
244  * @param h callback function that would be called by the timeout
245  * @param arg callback argument that would be passed to h
246 */
247 void
248 sys_untimeout(sys_timeout_handler h, void *arg)
249 {
250   struct sys_timeouts *timeouts;
251   struct sys_timeo *prev_t, *t;
252
253   timeouts = sys_arch_timeouts();
254
255   if (timeouts == NULL) {
256     LWIP_ASSERT("sys_untimeout: timeouts != NULL", timeouts != NULL);
257     return;
258   }
259   if (timeouts->next == NULL) {
260     return;
261   }
262
263   for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
264     if ((t->h == h) && (t->arg == arg)) {
265       /* We have a match */
266       /* Unlink from previous in list */
267       if (prev_t == NULL)
268         timeouts->next = t->next;
269       else
270         prev_t->next = t->next;
271       /* If not the last one, add time of this one back to next */
272       if (t->next != NULL)
273         t->next->time += t->time;
274       memp_free(MEMP_SYS_TIMEOUT, t);
275       return;
276     }
277   }
278   return;
279 }
280
281 /**
282  * Timeout handler function for sys_sem_wait_timeout()
283  *
284  * @param arg struct sswt_cb* used to signal a semaphore and end waiting.
285  */
286 static void
287 sswt_handler(void *arg)
288 {
289   struct sswt_cb *sswt_cb = (struct sswt_cb *) arg;
290
291   /* Timeout. Set flag to TRUE and signal semaphore */
292   sswt_cb->timeflag = 1;
293   sys_sem_signal(*(sswt_cb->psem));
294 }
295
296 /**
297  * Wait for a semaphore with timeout (specified in ms)
298  *
299  * @param sem semaphore to wait
300  * @param timeout timeout in ms (0: wait forever)
301  * @return 0 on timeout, 1 otherwise
302  */
303 int
304 sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout)
305 {
306   struct sswt_cb sswt_cb;
307
308   sswt_cb.psem = &sem;
309   sswt_cb.timeflag = 0;
310
311   /* If timeout is zero, then just wait forever */
312   if (timeout > 0) {
313     /* Create a timer and pass it the address of our flag */
314     sys_timeout(timeout, sswt_handler, &sswt_cb);
315   }
316   sys_sem_wait(sem);
317   /* Was it a timeout? */
318   if (sswt_cb.timeflag) {
319     /* timeout */
320     return 0;
321   } else {
322     /* Not a timeout. Remove timeout entry */
323     sys_untimeout(sswt_handler, &sswt_cb);
324     return 1;
325   }
326 }
327
328 /**
329  * Sleep for some ms. Timeouts are processed while sleeping.
330  *
331  * @param ms number of milliseconds to sleep
332  */
333 void
334 sys_msleep(u32_t ms)
335 {
336   sys_sem_t delaysem = sys_sem_new(0);
337
338   sys_sem_wait_timeout(delaysem, ms);
339
340   sys_sem_free(delaysem);
341 }
342
343
344 #endif /* NO_SYS */