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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
lwip_timeouts.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/timeouts.h" 00045 #include "lwip/priv/tcp_priv.h" 00046 00047 #include "lwip/def.h" 00048 #include "lwip/memp.h" 00049 #include "lwip/priv/tcpip_priv.h" 00050 00051 #include "lwip/ip4_frag.h" 00052 #include "lwip/etharp.h" 00053 #include "lwip/dhcp.h" 00054 #include "lwip/autoip.h" 00055 #include "lwip/igmp.h" 00056 #include "lwip/dns.h" 00057 #include "lwip/nd6.h" 00058 #include "lwip/ip6_frag.h" 00059 #include "lwip/mld6.h" 00060 #include "lwip/dhcp6.h" 00061 #include "lwip/sys.h" 00062 #include "lwip/pbuf.h" 00063 00064 #if LWIP_DEBUG_TIMERNAMES 00065 #define HANDLER(x) x, #x 00066 #else /* LWIP_DEBUG_TIMERNAMES */ 00067 #define HANDLER(x) x 00068 #endif /* LWIP_DEBUG_TIMERNAMES */ 00069 00070 #define LWIP_MAX_TIMEOUT 0x7fffffff 00071 00072 /* Check if timer's expiry time is greater than time and care about u32_t wraparounds */ 00073 #define TIME_LESS_THAN(t, compare_to) ( (((u32_t)((t)-(compare_to))) > LWIP_MAX_TIMEOUT) ? 1 : 0 ) 00074 00075 /** This array contains all stack-internal cyclic timers. To get the number of 00076 * timers, use LWIP_ARRAYSIZE() */ 00077 const struct lwip_cyclic_timer lwip_cyclic_timers[] = { 00078 #if LWIP_TCP 00079 /* The TCP timer is a special case: it does not have to run always and 00080 is triggered to start from TCP using tcp_timer_needed() */ 00081 {TCP_TMR_INTERVAL, HANDLER(tcp_tmr)}, 00082 #endif /* LWIP_TCP */ 00083 #if LWIP_IPV4 00084 #if IP_REASSEMBLY 00085 {IP_TMR_INTERVAL, HANDLER(ip_reass_tmr)}, 00086 #endif /* IP_REASSEMBLY */ 00087 #if LWIP_ARP 00088 {ARP_TMR_INTERVAL, HANDLER(etharp_tmr)}, 00089 #endif /* LWIP_ARP */ 00090 #if LWIP_DHCP 00091 {DHCP_COARSE_TIMER_MSECS, HANDLER(dhcp_coarse_tmr)}, 00092 {DHCP_FINE_TIMER_MSECS, HANDLER(dhcp_fine_tmr)}, 00093 #endif /* LWIP_DHCP */ 00094 #if LWIP_AUTOIP 00095 {AUTOIP_TMR_INTERVAL, HANDLER(autoip_tmr)}, 00096 #endif /* LWIP_AUTOIP */ 00097 #if LWIP_IGMP 00098 {IGMP_TMR_INTERVAL, HANDLER(igmp_tmr)}, 00099 #endif /* LWIP_IGMP */ 00100 #endif /* LWIP_IPV4 */ 00101 #if LWIP_DNS 00102 {DNS_TMR_INTERVAL, HANDLER(dns_tmr)}, 00103 #endif /* LWIP_DNS */ 00104 #if LWIP_IPV6 00105 {ND6_TMR_INTERVAL, HANDLER(nd6_tmr)}, 00106 #if LWIP_IPV6_REASS 00107 {IP6_REASS_TMR_INTERVAL, HANDLER(ip6_reass_tmr)}, 00108 #endif /* LWIP_IPV6_REASS */ 00109 #if LWIP_IPV6_MLD 00110 {MLD6_TMR_INTERVAL, HANDLER(mld6_tmr)}, 00111 #endif /* LWIP_IPV6_MLD */ 00112 #if LWIP_IPV6_DHCP6 00113 {DHCP6_TIMER_MSECS, HANDLER(dhcp6_tmr)}, 00114 #endif /* LWIP_IPV6_DHCP6 */ 00115 #endif /* LWIP_IPV6 */ 00116 }; 00117 const int lwip_num_cyclic_timers = LWIP_ARRAYSIZE(lwip_cyclic_timers); 00118 00119 #if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM 00120 00121 /** The one and only timeout list */ 00122 static struct sys_timeo *next_timeout; 00123 00124 static u32_t current_timeout_due_time; 00125 00126 #if LWIP_TESTMODE 00127 struct sys_timeo** 00128 sys_timeouts_get_next_timeout(void) 00129 { 00130 return &next_timeout; 00131 } 00132 #endif 00133 00134 #if LWIP_TCP 00135 /** global variable that shows if the tcp timer is currently scheduled or not */ 00136 static int tcpip_tcp_timer_active; 00137 00138 /** 00139 * Timer callback function that calls tcp_tmr() and reschedules itself. 00140 * 00141 * @param arg unused argument 00142 */ 00143 static void 00144 tcpip_tcp_timer(void *arg) 00145 { 00146 LWIP_UNUSED_ARG(arg); 00147 00148 /* call TCP timer handler */ 00149 tcp_tmr(); 00150 /* timer still needed? */ 00151 if (tcp_active_pcbs || tcp_tw_pcbs) { 00152 /* restart timer */ 00153 sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); 00154 } else { 00155 /* disable timer */ 00156 tcpip_tcp_timer_active = 0; 00157 } 00158 } 00159 00160 /** 00161 * Called from TCP_REG when registering a new PCB: 00162 * the reason is to have the TCP timer only running when 00163 * there are active (or time-wait) PCBs. 00164 */ 00165 void 00166 tcp_timer_needed(void) 00167 { 00168 LWIP_ASSERT_CORE_LOCKED(); 00169 00170 /* timer is off but needed again? */ 00171 if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { 00172 /* enable and start timer */ 00173 tcpip_tcp_timer_active = 1; 00174 sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); 00175 } 00176 } 00177 #endif /* LWIP_TCP */ 00178 00179 static void 00180 #if LWIP_DEBUG_TIMERNAMES 00181 sys_timeout_abs(u32_t abs_time, sys_timeout_handler handler, void *arg, const char *handler_name) 00182 #else /* LWIP_DEBUG_TIMERNAMES */ 00183 sys_timeout_abs(u32_t abs_time, sys_timeout_handler handler, void *arg) 00184 #endif 00185 { 00186 struct sys_timeo *timeout, *t; 00187 00188 timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT); 00189 if (timeout == NULL) { 00190 LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL); 00191 return; 00192 } 00193 00194 timeout->next = NULL; 00195 timeout->h = handler; 00196 timeout->arg = arg; 00197 timeout->time = abs_time; 00198 00199 #if LWIP_DEBUG_TIMERNAMES 00200 timeout->handler_name = handler_name; 00201 LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p abs_time=%"U32_F" handler=%s arg=%p\n", 00202 (void *)timeout, abs_time, handler_name, (void *)arg)); 00203 #endif /* LWIP_DEBUG_TIMERNAMES */ 00204 00205 if (next_timeout == NULL) { 00206 next_timeout = timeout; 00207 return; 00208 } 00209 if (TIME_LESS_THAN(timeout->time, next_timeout->time)) { 00210 timeout->next = next_timeout; 00211 next_timeout = timeout; 00212 } else { 00213 for (t = next_timeout; t != NULL; t = t->next) { 00214 if ((t->next == NULL) || TIME_LESS_THAN(timeout->time, t->next->time)) { 00215 timeout->next = t->next; 00216 t->next = timeout; 00217 break; 00218 } 00219 } 00220 } 00221 } 00222 00223 /** 00224 * Timer callback function that calls cyclic->handler() and reschedules itself. 00225 * 00226 * @param arg unused argument 00227 */ 00228 #if !LWIP_TESTMODE 00229 static 00230 #endif 00231 void 00232 lwip_cyclic_timer(void *arg) 00233 { 00234 u32_t now; 00235 u32_t next_timeout_time; 00236 const struct lwip_cyclic_timer *cyclic = (const struct lwip_cyclic_timer *)arg; 00237 00238 #if LWIP_DEBUG_TIMERNAMES 00239 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: %s()\n", cyclic->handler_name)); 00240 #endif 00241 cyclic->handler(); 00242 00243 now = sys_now(); 00244 next_timeout_time = (u32_t)(current_timeout_due_time + cyclic->interval_ms); /* overflow handled by TIME_LESS_THAN macro */ 00245 if (TIME_LESS_THAN(next_timeout_time, now)) { 00246 /* timer would immediately expire again -> "overload" -> restart without any correction */ 00247 #if LWIP_DEBUG_TIMERNAMES 00248 sys_timeout_abs((u32_t)(now + cyclic->interval_ms), lwip_cyclic_timer, arg, cyclic->handler_name); 00249 #else 00250 sys_timeout_abs((u32_t)(now + cyclic->interval_ms), lwip_cyclic_timer, arg); 00251 #endif 00252 00253 } else { 00254 /* correct cyclic interval with handler execution delay and sys_check_timeouts jitter */ 00255 #if LWIP_DEBUG_TIMERNAMES 00256 sys_timeout_abs(next_timeout_time, lwip_cyclic_timer, arg, cyclic->handler_name); 00257 #else 00258 sys_timeout_abs(next_timeout_time, lwip_cyclic_timer, arg); 00259 #endif 00260 } 00261 } 00262 00263 /** Initialize this module */ 00264 void sys_timeouts_init(void) 00265 { 00266 size_t i; 00267 /* tcp_tmr() at index 0 is started on demand */ 00268 for (i = (LWIP_TCP ? 1 : 0); i < LWIP_ARRAYSIZE(lwip_cyclic_timers); i++) { 00269 /* we have to cast via size_t to get rid of const warning 00270 (this is OK as cyclic_timer() casts back to const* */ 00271 sys_timeout(lwip_cyclic_timers[i].interval_ms, lwip_cyclic_timer, LWIP_CONST_CAST(void *, &lwip_cyclic_timers[i])); 00272 } 00273 } 00274 00275 /** 00276 * Create a one-shot timer (aka timeout). Timeouts are processed in the 00277 * following cases: 00278 * - while waiting for a message using sys_timeouts_mbox_fetch() 00279 * - by calling sys_check_timeouts() (NO_SYS==1 only) 00280 * 00281 * @param msecs time in milliseconds after that the timer should expire 00282 * @param handler callback function to call when msecs have elapsed 00283 * @param arg argument to pass to the callback function 00284 */ 00285 #if LWIP_DEBUG_TIMERNAMES 00286 void 00287 sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char *handler_name) 00288 #else /* LWIP_DEBUG_TIMERNAMES */ 00289 void 00290 sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) 00291 #endif /* LWIP_DEBUG_TIMERNAMES */ 00292 { 00293 u32_t next_timeout_time; 00294 00295 LWIP_ASSERT_CORE_LOCKED(); 00296 00297 LWIP_ASSERT("Timeout time too long, max is LWIP_UINT32_MAX/4 msecs", msecs <= (LWIP_UINT32_MAX / 4)); 00298 00299 next_timeout_time = (u32_t)(sys_now() + msecs); /* overflow handled by TIME_LESS_THAN macro */ 00300 00301 #if LWIP_DEBUG_TIMERNAMES 00302 sys_timeout_abs(next_timeout_time, handler, arg, handler_name); 00303 #else 00304 sys_timeout_abs(next_timeout_time, handler, arg); 00305 #endif 00306 } 00307 00308 /** 00309 * Go through timeout list (for this task only) and remove the first matching 00310 * entry (subsequent entries remain untouched), even though the timeout has not 00311 * triggered yet. 00312 * 00313 * @param handler callback function that would be called by the timeout 00314 * @param arg callback argument that would be passed to handler 00315 */ 00316 void 00317 sys_untimeout(sys_timeout_handler handler, void *arg) 00318 { 00319 struct sys_timeo *prev_t, *t; 00320 00321 LWIP_ASSERT_CORE_LOCKED(); 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 memp_free(MEMP_SYS_TIMEOUT, t); 00337 return; 00338 } 00339 } 00340 return; 00341 } 00342 00343 /** 00344 * @ingroup lwip_nosys 00345 * Handle timeouts for NO_SYS==1 (i.e. without using 00346 * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout 00347 * handler functions when timeouts expire. 00348 * 00349 * Must be called periodically from your main loop. 00350 */ 00351 void 00352 sys_check_timeouts(void) 00353 { 00354 u32_t now; 00355 00356 LWIP_ASSERT_CORE_LOCKED(); 00357 00358 /* Process only timers expired at the start of the function. */ 00359 now = sys_now(); 00360 00361 do { 00362 struct sys_timeo *tmptimeout; 00363 sys_timeout_handler handler; 00364 void *arg; 00365 00366 PBUF_CHECK_FREE_OOSEQ(); 00367 00368 tmptimeout = next_timeout; 00369 if (tmptimeout == NULL) { 00370 return; 00371 } 00372 00373 if (TIME_LESS_THAN(now, tmptimeout->time)) { 00374 return; 00375 } 00376 00377 /* Timeout has expired */ 00378 next_timeout = tmptimeout->next; 00379 handler = tmptimeout->h; 00380 arg = tmptimeout->arg; 00381 current_timeout_due_time = tmptimeout->time; 00382 #if LWIP_DEBUG_TIMERNAMES 00383 if (handler != NULL) { 00384 LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s t=%"U32_F" arg=%p\n", 00385 tmptimeout->handler_name, sys_now() - tmptimeout->time, arg)); 00386 } 00387 #endif /* LWIP_DEBUG_TIMERNAMES */ 00388 memp_free(MEMP_SYS_TIMEOUT, tmptimeout); 00389 if (handler != NULL) { 00390 handler(arg); 00391 } 00392 LWIP_TCPIP_THREAD_ALIVE(); 00393 00394 /* Repeat until all expired timers have been called */ 00395 } while (1); 00396 } 00397 00398 /** Rebase the timeout times to the current time. 00399 * This is necessary if sys_check_timeouts() hasn't been called for a long 00400 * time (e.g. while saving energy) to prevent all timer functions of that 00401 * period being called. 00402 */ 00403 void 00404 sys_restart_timeouts(void) 00405 { 00406 u32_t now; 00407 u32_t base; 00408 struct sys_timeo *t; 00409 00410 if (next_timeout == NULL) { 00411 return; 00412 } 00413 00414 now = sys_now(); 00415 base = next_timeout->time; 00416 00417 for (t = next_timeout; t != NULL; t = t->next) { 00418 t->time = (t->time - base) + now; 00419 } 00420 } 00421 00422 /** Return the time left before the next timeout is due. If no timeouts are 00423 * enqueued, returns 0xffffffff 00424 */ 00425 u32_t 00426 sys_timeouts_sleeptime(void) 00427 { 00428 u32_t now; 00429 00430 LWIP_ASSERT_CORE_LOCKED(); 00431 00432 if (next_timeout == NULL) { 00433 return SYS_TIMEOUTS_SLEEPTIME_INFINITE; 00434 } 00435 now = sys_now(); 00436 if (TIME_LESS_THAN(next_timeout->time, now)) { 00437 return 0; 00438 } else { 00439 u32_t ret = (u32_t)(next_timeout->time - now); 00440 LWIP_ASSERT("invalid sleeptime", ret <= LWIP_MAX_TIMEOUT); 00441 return ret; 00442 } 00443 } 00444 00445 #else /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ 00446 /* Satisfy the TCP code which calls this function */ 00447 void 00448 tcp_timer_needed(void) 00449 { 00450 } 00451 #endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */
Generated on Tue Jul 12 2022 13:54:30 by
