Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
sys.c
00001 /** 00002 * @file 00003 * lwIP Operating System abstraction 00004 * 00005 */ 00006 00007 /* 00008 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 00009 * All rights reserved. 00010 * 00011 * Redistribution and use in source and binary forms, with or without modification, 00012 * are permitted provided that the following conditions are met: 00013 * 00014 * 1. Redistributions of source code must retain the above copyright notice, 00015 * this list of conditions and the following disclaimer. 00016 * 2. Redistributions in binary form must reproduce the above copyright notice, 00017 * this list of conditions and the following disclaimer in the documentation 00018 * and/or other materials provided with the distribution. 00019 * 3. The name of the author may not be used to endorse or promote products 00020 * derived from this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00023 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00025 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00026 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00027 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00028 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00029 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00030 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00031 * OF SUCH DAMAGE. 00032 * 00033 * This file is part of the lwIP TCP/IP stack. 00034 * 00035 * Author: Adam Dunkels <adam@sics.se> 00036 * 00037 */ 00038 00039 #include "lwip/opt.h" 00040 00041 #if (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */ 00042 00043 #include "lwip/sys.h" 00044 #include "lwip/def.h" 00045 #include "lwip/memp.h" 00046 #include "lwip/tcpip.h" 00047 00048 /** 00049 * Struct used for sys_sem_wait_timeout() to tell wether the time 00050 * has run out or the semaphore has really become available. 00051 */ 00052 struct sswt_cb 00053 { 00054 s16_t timeflag; 00055 sys_sem_t *psem; 00056 }; 00057 00058 /** 00059 * Wait (forever) for a message to arrive in an mbox. 00060 * While waiting, timeouts (for this thread) are processed. 00061 * 00062 * @param mbox the mbox to fetch the message from 00063 * @param msg the place to store the message 00064 */ 00065 void 00066 sys_mbox_fetch(sys_mbox_t mbox, void **msg) 00067 { 00068 u32_t time_needed; 00069 struct sys_timeouts *timeouts; 00070 struct sys_timeo *tmptimeout; 00071 sys_timeout_handler h; 00072 void *arg; 00073 00074 again: 00075 timeouts = sys_arch_timeouts(); 00076 00077 if (!timeouts || !timeouts->next) { 00078 UNLOCK_TCPIP_CORE(); 00079 time_needed = sys_arch_mbox_fetch(mbox, msg, 0); 00080 LOCK_TCPIP_CORE(); 00081 } else { 00082 if (timeouts->next->time > 0) { 00083 UNLOCK_TCPIP_CORE(); 00084 time_needed = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time); 00085 LOCK_TCPIP_CORE(); 00086 } else { 00087 time_needed = SYS_ARCH_TIMEOUT; 00088 } 00089 00090 if (time_needed == SYS_ARCH_TIMEOUT) { 00091 /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message 00092 could be fetched. We should now call the timeout handler and 00093 deallocate the memory allocated for the timeout. */ 00094 tmptimeout = timeouts->next; 00095 timeouts->next = tmptimeout->next; 00096 h = tmptimeout->h; 00097 arg = tmptimeout->arg; 00098 memp_free(MEMP_SYS_TIMEOUT, tmptimeout); 00099 if (h != NULL) { 00100 LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", (void*)&h, arg)); 00101 h(arg); 00102 } 00103 00104 /* We try again to fetch a message from the mbox. */ 00105 goto again; 00106 } else { 00107 /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout 00108 occured. The time variable is set to the number of 00109 milliseconds we waited for the message. */ 00110 if (time_needed < timeouts->next->time) { 00111 timeouts->next->time -= time_needed; 00112 } else { 00113 timeouts->next->time = 0; 00114 } 00115 } 00116 } 00117 } 00118 00119 /** 00120 * Wait (forever) for a semaphore to become available. 00121 * While waiting, timeouts (for this thread) are processed. 00122 * 00123 * @param sem semaphore to wait for 00124 */ 00125 void 00126 sys_sem_wait(sys_sem_t sem) 00127 { 00128 u32_t time_needed; 00129 struct sys_timeouts *timeouts; 00130 struct sys_timeo *tmptimeout; 00131 sys_timeout_handler h; 00132 void *arg; 00133 00134 again: 00135 00136 timeouts = sys_arch_timeouts(); 00137 00138 if (!timeouts || !timeouts->next) { 00139 sys_arch_sem_wait(sem, 0); 00140 } else { 00141 if (timeouts->next->time > 0) { 00142 time_needed = sys_arch_sem_wait(sem, timeouts->next->time); 00143 } else { 00144 time_needed = SYS_ARCH_TIMEOUT; 00145 } 00146 00147 if (time_needed == SYS_ARCH_TIMEOUT) { 00148 /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message 00149 could be fetched. We should now call the timeout handler and 00150 deallocate the memory allocated for the timeout. */ 00151 tmptimeout = timeouts->next; 00152 timeouts->next = tmptimeout->next; 00153 h = tmptimeout->h; 00154 arg = tmptimeout->arg; 00155 memp_free(MEMP_SYS_TIMEOUT, tmptimeout); 00156 if (h != NULL) { 00157 LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", (void*)&h, (void *)arg)); 00158 h(arg); 00159 } 00160 00161 /* We try again to fetch a message from the mbox. */ 00162 goto again; 00163 } else { 00164 /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout 00165 occured. The time variable is set to the number of 00166 milliseconds we waited for the message. */ 00167 if (time_needed < timeouts->next->time) { 00168 timeouts->next->time -= time_needed; 00169 } else { 00170 timeouts->next->time = 0; 00171 } 00172 } 00173 } 00174 } 00175 00176 /** 00177 * Create a one-shot timer (aka timeout). Timeouts are processed in the 00178 * following cases: 00179 * - while waiting for a message using sys_mbox_fetch() 00180 * - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout() 00181 * - while sleeping using the inbuilt sys_msleep() 00182 * 00183 * @param msecs time in milliseconds after that the timer should expire 00184 * @param h callback function to call when msecs have elapsed 00185 * @param arg argument to pass to the callback function 00186 */ 00187 void 00188 sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg) 00189 { 00190 struct sys_timeouts *timeouts; 00191 struct sys_timeo *timeout, *t; 00192 00193 timeout = memp_malloc(MEMP_SYS_TIMEOUT); 00194 if (timeout == NULL) { 00195 LWIP_ASSERT("sys_timeout: timeout != NULL", timeout != NULL); 00196 return; 00197 } 00198 timeout->next = NULL; 00199 timeout->h = h; 00200 timeout->arg = arg; 00201 timeout->time = msecs; 00202 00203 timeouts = sys_arch_timeouts(); 00204 00205 LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n", 00206 (void *)timeout, msecs, (void*)&h, (void *)arg)); 00207 00208 if (timeouts == NULL) { 00209 LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL); 00210 return; 00211 } 00212 00213 if (timeouts->next == NULL) { 00214 timeouts->next = timeout; 00215 return; 00216 } 00217 00218 if (timeouts->next->time > msecs) { 00219 timeouts->next->time -= msecs; 00220 timeout->next = timeouts->next; 00221 timeouts->next = timeout; 00222 } else { 00223 for(t = timeouts->next; t != NULL; t = t->next) { 00224 timeout->time -= t->time; 00225 if (t->next == NULL || t->next->time > timeout->time) { 00226 if (t->next != NULL) { 00227 t->next->time -= timeout->time; 00228 } 00229 timeout->next = t->next; 00230 t->next = timeout; 00231 break; 00232 } 00233 } 00234 } 00235 } 00236 00237 /** 00238 * Go through timeout list (for this task only) and remove the first matching 00239 * entry, even though the timeout has not triggered yet. 00240 * 00241 * @note This function only works as expected if there is only one timeout 00242 * calling 'h' in the list of timeouts. 00243 * 00244 * @param h callback function that would be called by the timeout 00245 * @param arg callback argument that would be passed to h 00246 */ 00247 void 00248 sys_untimeout(sys_timeout_handler h, void *arg) 00249 { 00250 struct sys_timeouts *timeouts; 00251 struct sys_timeo *prev_t, *t; 00252 00253 timeouts = sys_arch_timeouts(); 00254 00255 if (timeouts == NULL) { 00256 LWIP_ASSERT("sys_untimeout: timeouts != NULL", timeouts != NULL); 00257 return; 00258 } 00259 if (timeouts->next == NULL) { 00260 return; 00261 } 00262 00263 for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { 00264 if ((t->h == h) && (t->arg == arg)) { 00265 /* We have a match */ 00266 /* Unlink from previous in list */ 00267 if (prev_t == NULL) 00268 timeouts->next = t->next; 00269 else 00270 prev_t->next = t->next; 00271 /* If not the last one, add time of this one back to next */ 00272 if (t->next != NULL) 00273 t->next->time += t->time; 00274 memp_free(MEMP_SYS_TIMEOUT, t); 00275 return; 00276 } 00277 } 00278 return; 00279 } 00280 00281 /** 00282 * Timeout handler function for sys_sem_wait_timeout() 00283 * 00284 * @param arg struct sswt_cb* used to signal a semaphore and end waiting. 00285 */ 00286 static void 00287 sswt_handler(void *arg) 00288 { 00289 struct sswt_cb *sswt_cb = (struct sswt_cb *) arg; 00290 00291 /* Timeout. Set flag to TRUE and signal semaphore */ 00292 sswt_cb->timeflag = 1; 00293 sys_sem_signal(*(sswt_cb->psem)); 00294 } 00295 00296 /** 00297 * Wait for a semaphore with timeout (specified in ms) 00298 * 00299 * @param sem semaphore to wait 00300 * @param timeout timeout in ms (0: wait forever) 00301 * @return 0 on timeout, 1 otherwise 00302 */ 00303 int 00304 sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout) 00305 { 00306 struct sswt_cb sswt_cb; 00307 00308 sswt_cb.psem = &sem; 00309 sswt_cb.timeflag = 0; 00310 00311 /* If timeout is zero, then just wait forever */ 00312 if (timeout > 0) { 00313 /* Create a timer and pass it the address of our flag */ 00314 sys_timeout(timeout, sswt_handler, &sswt_cb); 00315 } 00316 sys_sem_wait(sem); 00317 /* Was it a timeout? */ 00318 if (sswt_cb.timeflag) { 00319 /* timeout */ 00320 return 0; 00321 } else { 00322 /* Not a timeout. Remove timeout entry */ 00323 sys_untimeout(sswt_handler, &sswt_cb); 00324 return 1; 00325 } 00326 } 00327 00328 /** 00329 * Sleep for some ms. Timeouts are processed while sleeping. 00330 * 00331 * @param ms number of milliseconds to sleep 00332 */ 00333 void 00334 sys_msleep(u32_t ms) 00335 { 00336 sys_sem_t delaysem = sys_sem_new(0); 00337 00338 sys_sem_wait_timeout(delaysem, ms); 00339 00340 sys_sem_free(delaysem); 00341 } 00342 00343 00344 #endif /* NO_SYS */
Generated on Tue Jul 12 2022 20:39:37 by
1.7.2