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