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.
Fork of lwip by
timers.c
00001 /** 00002 * @file 00003 * Stack-internal timers implementation. 00004 * This file includes timer callbacks for stack-internal timers as well as 00005 * functions to set up or stop timers and check for expired timers. 00006 * 00007 */ 00008 00009 /* 00010 * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 00011 * All rights reserved. 00012 * 00013 * Redistribution and use in source and binary forms, with or without modification, 00014 * are permitted provided that the following conditions are met: 00015 * 00016 * 1. Redistributions of source code must retain the above copyright notice, 00017 * this list of conditions and the following disclaimer. 00018 * 2. Redistributions in binary form must reproduce the above copyright notice, 00019 * this list of conditions and the following disclaimer in the documentation 00020 * and/or other materials provided with the distribution. 00021 * 3. The name of the author may not be used to endorse or promote products 00022 * derived from this software without specific prior written permission. 00023 * 00024 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00025 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00026 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00027 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00028 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00029 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00030 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00031 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00032 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00033 * OF SUCH DAMAGE. 00034 * 00035 * This file is part of the lwIP TCP/IP stack. 00036 * 00037 * Author: Adam Dunkels <adam@sics.se> 00038 * Simon Goldschmidt 00039 * 00040 */ 00041 00042 #include "lwip/opt.h" 00043 00044 #include "lwip/timers.h" 00045 #include "lwip/tcp_impl.h" 00046 00047 #if LWIP_TIMERS 00048 00049 #include "lwip/def.h" 00050 #include "lwip/memp.h" 00051 #include "lwip/tcpip.h" 00052 00053 #include "lwip/ip_frag.h" 00054 #include "netif/etharp.h" 00055 #include "lwip/dhcp.h " 00056 #include "lwip/autoip.h" 00057 #include "lwip/igmp.h" 00058 #include "lwip/dns.h" 00059 00060 00061 /** The one and only timeout list */ 00062 static struct sys_timeo *next_timeout; 00063 #if NO_SYS 00064 static u32_t timeouts_last_time; 00065 #endif /* NO_SYS */ 00066 00067 #if LWIP_TCP 00068 /** global variable that shows if the tcp timer is currently scheduled or not */ 00069 static int tcpip_tcp_timer_active; 00070 00071 /** 00072 * Timer callback function that calls tcp_tmr() and reschedules itself. 00073 * 00074 * @param arg unused argument 00075 */ 00076 static void 00077 tcpip_tcp_timer(void *arg) 00078 { 00079 LWIP_UNUSED_ARG(arg); 00080 00081 /* call TCP timer handler */ 00082 tcp_tmr(); 00083 /* timer still needed? */ 00084 if (tcp_active_pcbs || tcp_tw_pcbs) { 00085 /* restart timer */ 00086 sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); 00087 } else { 00088 /* disable timer */ 00089 tcpip_tcp_timer_active = 0; 00090 } 00091 } 00092 00093 /** 00094 * Called from TCP_REG when registering a new PCB: 00095 * the reason is to have the TCP timer only running when 00096 * there are active (or time-wait) PCBs. 00097 */ 00098 void 00099 tcp_timer_needed(void) 00100 { 00101 /* timer is off but needed again? */ 00102 if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { 00103 /* enable and start timer */ 00104 tcpip_tcp_timer_active = 1; 00105 sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); 00106 } 00107 } 00108 #endif /* LWIP_TCP */ 00109 00110 #if IP_REASSEMBLY 00111 /** 00112 * Timer callback function that calls ip_reass_tmr() and reschedules itself. 00113 * 00114 * @param arg unused argument 00115 */ 00116 static void 00117 ip_reass_timer(void *arg) 00118 { 00119 LWIP_UNUSED_ARG(arg); 00120 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n")); 00121 ip_reass_tmr(); 00122 sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); 00123 } 00124 #endif /* IP_REASSEMBLY */ 00125 00126 #if LWIP_ARP 00127 /** 00128 * Timer callback function that calls etharp_tmr() and reschedules itself. 00129 * 00130 * @param arg unused argument 00131 */ 00132 static void 00133 arp_timer(void *arg) 00134 { 00135 LWIP_UNUSED_ARG(arg); 00136 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n")); 00137 etharp_tmr(); 00138 sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); 00139 } 00140 #endif /* LWIP_ARP */ 00141 00142 #if LWIP_DHCP 00143 /** 00144 * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself. 00145 * 00146 * @param arg unused argument 00147 */ 00148 static void 00149 dhcp_timer_coarse(void *arg) 00150 { 00151 LWIP_UNUSED_ARG(arg); 00152 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n")); 00153 dhcp_coarse_tmr(); 00154 sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); 00155 } 00156 00157 /** 00158 * Timer callback function that calls dhcp_fine_tmr() and reschedules itself. 00159 * 00160 * @param arg unused argument 00161 */ 00162 static void 00163 dhcp_timer_fine(void *arg) 00164 { 00165 LWIP_UNUSED_ARG(arg); 00166 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n")); 00167 dhcp_fine_tmr(); 00168 sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); 00169 } 00170 #endif /* LWIP_DHCP */ 00171 00172 #if LWIP_AUTOIP 00173 /** 00174 * Timer callback function that calls autoip_tmr() and reschedules itself. 00175 * 00176 * @param arg unused argument 00177 */ 00178 static void 00179 autoip_timer(void *arg) 00180 { 00181 LWIP_UNUSED_ARG(arg); 00182 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n")); 00183 autoip_tmr(); 00184 sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); 00185 } 00186 #endif /* LWIP_AUTOIP */ 00187 00188 #if LWIP_IGMP 00189 /** 00190 * Timer callback function that calls igmp_tmr() and reschedules itself. 00191 * 00192 * @param arg unused argument 00193 */ 00194 static void 00195 igmp_timer(void *arg) 00196 { 00197 LWIP_UNUSED_ARG(arg); 00198 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n")); 00199 igmp_tmr(); 00200 sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); 00201 } 00202 #endif /* LWIP_IGMP */ 00203 00204 #if LWIP_DNS 00205 /** 00206 * Timer callback function that calls dns_tmr() and reschedules itself. 00207 * 00208 * @param arg unused argument 00209 */ 00210 static void 00211 dns_timer(void *arg) 00212 { 00213 LWIP_UNUSED_ARG(arg); 00214 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n")); 00215 dns_tmr(); 00216 sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); 00217 } 00218 #endif /* LWIP_DNS */ 00219 00220 /** Initialize this module */ 00221 void sys_timeouts_init(void) 00222 { 00223 #if IP_REASSEMBLY 00224 sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); 00225 #endif /* IP_REASSEMBLY */ 00226 #if LWIP_ARP 00227 sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); 00228 #endif /* LWIP_ARP */ 00229 #if LWIP_DHCP 00230 sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); 00231 sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); 00232 #endif /* LWIP_DHCP */ 00233 #if LWIP_AUTOIP 00234 sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); 00235 #endif /* LWIP_AUTOIP */ 00236 #if LWIP_IGMP 00237 sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); 00238 #endif /* LWIP_IGMP */ 00239 #if LWIP_DNS 00240 sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); 00241 #endif /* LWIP_DNS */ 00242 00243 #if NO_SYS 00244 /* Initialise timestamp for sys_check_timeouts */ 00245 timeouts_last_time = sys_now(); 00246 #endif 00247 } 00248 00249 /** 00250 * Create a one-shot timer (aka timeout). Timeouts are processed in the 00251 * following cases: 00252 * - while waiting for a message using sys_timeouts_mbox_fetch() 00253 * - by calling sys_check_timeouts() (NO_SYS==1 only) 00254 * 00255 * @param msecs time in milliseconds after that the timer should expire 00256 * @param handler callback function to call when msecs have elapsed 00257 * @param arg argument to pass to the callback function 00258 */ 00259 #if LWIP_DEBUG_TIMERNAMES 00260 void 00261 sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name) 00262 #else /* LWIP_DEBUG_TIMERNAMES */ 00263 void 00264 sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) 00265 #endif /* LWIP_DEBUG_TIMERNAMES */ 00266 { 00267 struct sys_timeo *timeout, *t; 00268 00269 timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT); 00270 if (timeout == NULL) { 00271 LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL); 00272 return; 00273 } 00274 timeout->next = NULL; 00275 timeout->h = handler; 00276 timeout->arg = arg; 00277 timeout->time = msecs; 00278 #if LWIP_DEBUG_TIMERNAMES 00279 timeout->handler_name = handler_name; 00280 LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n", 00281 (void *)timeout, msecs, handler_name, (void *)arg)); 00282 #endif /* LWIP_DEBUG_TIMERNAMES */ 00283 00284 if (next_timeout == NULL) { 00285 next_timeout = timeout; 00286 return; 00287 } 00288 00289 if (next_timeout->time > msecs) { 00290 next_timeout->time -= msecs; 00291 timeout->next = next_timeout; 00292 next_timeout = timeout; 00293 } else { 00294 for(t = next_timeout; t != NULL; t = t->next) { 00295 timeout->time -= t->time; 00296 if (t->next == NULL || t->next->time > timeout->time) { 00297 if (t->next != NULL) { 00298 t->next->time -= timeout->time; 00299 } 00300 timeout->next = t->next; 00301 t->next = timeout; 00302 break; 00303 } 00304 } 00305 } 00306 } 00307 00308 /** 00309 * Go through timeout list (for this task only) and remove the first matching 00310 * entry, even though the timeout has not triggered yet. 00311 * 00312 * @note This function only works as expected if there is only one timeout 00313 * calling 'handler' in the list of timeouts. 00314 * 00315 * @param handler callback function that would be called by the timeout 00316 * @param arg callback argument that would be passed to handler 00317 */ 00318 void 00319 sys_untimeout(sys_timeout_handler handler, void *arg) 00320 { 00321 struct sys_timeo *prev_t, *t; 00322 00323 if (next_timeout == NULL) { 00324 return; 00325 } 00326 00327 for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { 00328 if ((t->h == handler) && (t->arg == arg)) { 00329 /* We have a match */ 00330 /* Unlink from previous in list */ 00331 if (prev_t == NULL) { 00332 next_timeout = t->next; 00333 } else { 00334 prev_t->next = t->next; 00335 } 00336 /* If not the last one, add time of this one back to next */ 00337 if (t->next != NULL) { 00338 t->next->time += t->time; 00339 } 00340 memp_free(MEMP_SYS_TIMEOUT, t); 00341 return; 00342 } 00343 } 00344 return; 00345 } 00346 00347 #if NO_SYS 00348 00349 /** Handle timeouts for NO_SYS==1 (i.e. without using 00350 * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout 00351 * handler functions when timeouts expire. 00352 * 00353 * Must be called periodically from your main loop. 00354 */ 00355 void 00356 sys_check_timeouts(void) 00357 { 00358 struct sys_timeo *tmptimeout; 00359 u32_t diff; 00360 sys_timeout_handler handler; 00361 void *arg; 00362 int had_one; 00363 u32_t now; 00364 00365 now = sys_now(); 00366 if (next_timeout) { 00367 /* this cares for wraparounds */ 00368 diff = LWIP_U32_DIFF(now, timeouts_last_time); 00369 do 00370 { 00371 had_one = 0; 00372 tmptimeout = next_timeout; 00373 if (tmptimeout->time <= diff) { 00374 /* timeout has expired */ 00375 had_one = 1; 00376 timeouts_last_time = now; 00377 diff -= tmptimeout->time; 00378 next_timeout = tmptimeout->next; 00379 handler = tmptimeout->h; 00380 arg = tmptimeout->arg; 00381 #if LWIP_DEBUG_TIMERNAMES 00382 if (handler != NULL) { 00383 LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n", 00384 tmptimeout->handler_name, arg)); 00385 } 00386 #endif /* LWIP_DEBUG_TIMERNAMES */ 00387 memp_free(MEMP_SYS_TIMEOUT, tmptimeout); 00388 if (handler != NULL) { 00389 handler(arg); 00390 } 00391 } 00392 /* repeat until all expired timers have been called */ 00393 }while(had_one); 00394 } 00395 } 00396 00397 /** Set back the timestamp of the last call to sys_check_timeouts() 00398 * This is necessary if sys_check_timeouts() hasn't been called for a long 00399 * time (e.g. while saving energy) to prevent all timer functions of that 00400 * period being called. 00401 */ 00402 void 00403 sys_restart_timeouts(void) 00404 { 00405 timeouts_last_time = sys_now(); 00406 } 00407 00408 #else /* NO_SYS */ 00409 00410 /** 00411 * Wait (forever) for a message to arrive in an mbox. 00412 * While waiting, timeouts are processed. 00413 * 00414 * @param mbox the mbox to fetch the message from 00415 * @param msg the place to store the message 00416 */ 00417 void 00418 sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) 00419 { 00420 u32_t time_needed; 00421 struct sys_timeo *tmptimeout; 00422 sys_timeout_handler handler; 00423 void *arg; 00424 00425 again: 00426 if (!next_timeout) { 00427 time_needed = sys_arch_mbox_fetch(mbox, msg, 0); 00428 } else { 00429 if (next_timeout->time > 0) { 00430 time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time); 00431 } else { 00432 time_needed = SYS_ARCH_TIMEOUT; 00433 } 00434 00435 if (time_needed == SYS_ARCH_TIMEOUT) { 00436 /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message 00437 could be fetched. We should now call the timeout handler and 00438 deallocate the memory allocated for the timeout. */ 00439 tmptimeout = next_timeout; 00440 next_timeout = tmptimeout->next; 00441 handler = tmptimeout->h; 00442 arg = tmptimeout->arg; 00443 #if LWIP_DEBUG_TIMERNAMES 00444 if (handler != NULL) { 00445 LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n", 00446 tmptimeout->handler_name, arg)); 00447 } 00448 #endif /* LWIP_DEBUG_TIMERNAMES */ 00449 memp_free(MEMP_SYS_TIMEOUT, tmptimeout); 00450 if (handler != NULL) { 00451 /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the 00452 timeout handler function. */ 00453 LOCK_TCPIP_CORE(); 00454 handler(arg); 00455 UNLOCK_TCPIP_CORE(); 00456 } 00457 LWIP_TCPIP_THREAD_ALIVE(); 00458 00459 /* We try again to fetch a message from the mbox. */ 00460 goto again; 00461 } else { 00462 /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout 00463 occured. The time variable is set to the number of 00464 milliseconds we waited for the message. */ 00465 if (time_needed < next_timeout->time) { 00466 next_timeout->time -= time_needed; 00467 } else { 00468 next_timeout->time = 0; 00469 } 00470 } 00471 } 00472 } 00473 00474 #endif /* NO_SYS */ 00475 00476 #else /* LWIP_TIMERS */ 00477 /* Satisfy the TCP code which calls this function */ 00478 void 00479 tcp_timer_needed(void) 00480 { 00481 } 00482 #endif /* LWIP_TIMERS */
Generated on Tue Jul 12 2022 11:29:38 by
