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);