3 * lwIP Operating System abstraction
8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
11 * Redistribution and use in source and binary forms, with or without modification,
12 * are permitted provided that the following conditions are met:
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.
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
33 * This file is part of the lwIP TCP/IP stack.
35 * Author: Adam Dunkels <adam@sics.se>
41 #if (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */
45 #include "lwip/memp.h"
46 #include "lwip/tcpip.h"
49 * Struct used for sys_sem_wait_timeout() to tell wether the time
50 * has run out or the semaphore has really become available.
59 * Wait (forever) for a message to arrive in an mbox.
60 * While waiting, timeouts (for this thread) are processed.
62 * @param mbox the mbox to fetch the message from
63 * @param msg the place to store the message
66 sys_mbox_fetch(sys_mbox_t mbox
, void **msg
)
69 struct sys_timeouts
*timeouts
;
70 struct sys_timeo
*tmptimeout
;
71 sys_timeout_handler h
;
75 timeouts
= sys_arch_timeouts();
77 if (!timeouts
|| !timeouts
->next
) {
79 time
= sys_arch_mbox_fetch(mbox
, msg
, 0);
82 if (timeouts
->next
->time
> 0) {
84 time
= sys_arch_mbox_fetch(mbox
, msg
, timeouts
->next
->time
);
87 time
= SYS_ARCH_TIMEOUT
;
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
;
97 arg
= tmptimeout
->arg
;
98 memp_free(MEMP_SYS_TIMEOUT
, tmptimeout
);
100 LWIP_DEBUGF(SYS_DEBUG
, ("smf calling h=%p(%p)\n", (void*)&h
, arg
));
104 /* We try again to fetch a message from the mbox. */
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
;
113 timeouts
->next
->time
= 0;
120 * Wait (forever) for a semaphore to become available.
121 * While waiting, timeouts (for this thread) are processed.
123 * @param sem semaphore to wait for
126 sys_sem_wait(sys_sem_t sem
)
129 struct sys_timeouts
*timeouts
;
130 struct sys_timeo
*tmptimeout
;
131 sys_timeout_handler h
;
136 timeouts
= sys_arch_timeouts();
138 if (!timeouts
|| !timeouts
->next
) {
139 sys_arch_sem_wait(sem
, 0);
141 if (timeouts
->next
->time
> 0) {
142 time
= sys_arch_sem_wait(sem
, timeouts
->next
->time
);
144 time
= SYS_ARCH_TIMEOUT
;
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
;
154 arg
= tmptimeout
->arg
;
155 memp_free(MEMP_SYS_TIMEOUT
, tmptimeout
);
157 LWIP_DEBUGF(SYS_DEBUG
, ("ssw h=%p(%p)\n", (void*)&h
, (void *)arg
));
161 /* We try again to fetch a message from the mbox. */
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
;
170 timeouts
->next
->time
= 0;
177 * Create a one-shot timer (aka timeout). Timeouts are processed in the
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()
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
188 sys_timeout(u32_t msecs
, sys_timeout_handler h
, void *arg
)
190 struct sys_timeouts
*timeouts
;
191 struct sys_timeo
*timeout
, *t
;
193 timeout
= memp_malloc(MEMP_SYS_TIMEOUT
);
194 if (timeout
== NULL
) {
195 LWIP_ASSERT("sys_timeout: timeout != NULL", timeout
!= NULL
);
198 timeout
->next
= NULL
;
201 timeout
->time
= msecs
;
203 timeouts
= sys_arch_timeouts();
205 LWIP_DEBUGF(SYS_DEBUG
, ("sys_timeout: %p msecs=%"U32_F
" h=%p arg=%p\n",
206 (void *)timeout
, msecs
, (void*)&h
, (void *)arg
));
208 if (timeouts
== NULL
) {
209 LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts
!= NULL
);
213 if (timeouts
->next
== NULL
) {
214 timeouts
->next
= timeout
;
218 if (timeouts
->next
->time
> msecs
) {
219 timeouts
->next
->time
-= msecs
;
220 timeout
->next
= timeouts
->next
;
221 timeouts
->next
= timeout
;
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
;
229 timeout
->next
= t
->next
;
238 * Go through timeout list (for this task only) and remove the first matching
239 * entry, even though the timeout has not triggered yet.
241 * @note This function only works as expected if there is only one timeout
242 * calling 'h' in the list of timeouts.
244 * @param h callback function that would be called by the timeout
245 * @param arg callback argument that would be passed to h
248 sys_untimeout(sys_timeout_handler h
, void *arg
)
250 struct sys_timeouts
*timeouts
;
251 struct sys_timeo
*prev_t
, *t
;
253 timeouts
= sys_arch_timeouts();
255 if (timeouts
== NULL
) {
256 LWIP_ASSERT("sys_untimeout: timeouts != NULL", timeouts
!= NULL
);
259 if (timeouts
->next
== NULL
) {
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 */
268 timeouts
->next
= t
->next
;
270 prev_t
->next
= t
->next
;
271 /* If not the last one, add time of this one back to next */
273 t
->next
->time
+= t
->time
;
274 memp_free(MEMP_SYS_TIMEOUT
, t
);
282 * Timeout handler function for sys_sem_wait_timeout()
284 * @param arg struct sswt_cb* used to signal a semaphore and end waiting.
287 sswt_handler(void *arg
)
289 struct sswt_cb
*sswt_cb
= (struct sswt_cb
*) arg
;
291 /* Timeout. Set flag to TRUE and signal semaphore */
292 sswt_cb
->timeflag
= 1;
293 sys_sem_signal(*(sswt_cb
->psem
));
297 * Wait for a semaphore with timeout (specified in ms)
299 * @param sem semaphore to wait
300 * @param timeout timeout in ms (0: wait forever)
301 * @return 0 on timeout, 1 otherwise
304 sys_sem_wait_timeout(sys_sem_t sem
, u32_t timeout
)
306 struct sswt_cb sswt_cb
;
309 sswt_cb
.timeflag
= 0;
311 /* If timeout is zero, then just wait forever */
313 /* Create a timer and pass it the address of our flag */
314 sys_timeout(timeout
, sswt_handler
, &sswt_cb
);
317 /* Was it a timeout? */
318 if (sswt_cb
.timeflag
) {
322 /* Not a timeout. Remove timeout entry */
323 sys_untimeout(sswt_handler
, &sswt_cb
);
329 * Sleep for some ms. Timeouts are processed while sleeping.
331 * @param ms number of milliseconds to sleep
336 sys_sem_t delaysem
= sys_sem_new(0);
338 sys_sem_wait_timeout(delaysem
, ms
);
340 sys_sem_free(delaysem
);