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.
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 00046 #if LWIP_TIMERS 00047 00048 #include "lwip/def.h" 00049 #include "lwip/memp.h" 00050 #include "lwip/tcpip.h" 00051 00052 #include "lwip/tcp_impl.h" 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 next_timeout = NULL; 00224 #if IP_REASSEMBLY 00225 sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); 00226 #endif /* IP_REASSEMBLY */ 00227 #if LWIP_ARP 00228 sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); 00229 #endif /* LWIP_ARP */ 00230 #if LWIP_DHCP 00231 sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); 00232 sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); 00233 #endif /* LWIP_DHCP */ 00234 #if LWIP_AUTOIP 00235 sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); 00236 #endif /* LWIP_AUTOIP */ 00237 #if LWIP_IGMP 00238 sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); 00239 #endif /* LWIP_IGMP */ 00240 #if LWIP_DNS 00241 sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); 00242 #endif /* LWIP_DNS */ 00243 00244 #if NO_SYS 00245 /* Initialise timestamp for sys_check_timeouts */ 00246 timeouts_last_time = sys_now(); 00247 #endif 00248 } 00249 00250 /** 00251 * Create a one-shot timer (aka timeout). Timeouts are processed in the 00252 * following cases: 00253 * - while waiting for a message using sys_timeouts_mbox_fetch() 00254 * - by calling sys_check_timeouts() (NO_SYS==1 only) 00255 * 00256 * @param msecs time in milliseconds after that the timer should expire 00257 * @param handler callback function to call when msecs have elapsed 00258 * @param arg argument to pass to the callback function 00259 */ 00260 #if LWIP_DEBUG_TIMERNAMES 00261 void 00262 sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name) 00263 #else /* LWIP_DEBUG_TIMERNAMES */ 00264 void 00265 sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) 00266 #endif /* LWIP_DEBUG_TIMERNAMES */ 00267 { 00268 struct sys_timeo *timeout, *t; 00269 00270 timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT); 00271 if (timeout == NULL) { 00272 LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL); 00273 return; 00274 } 00275 timeout->next = NULL; 00276 timeout->h = handler; 00277 timeout->arg = arg; 00278 timeout->time = msecs; 00279 #if LWIP_DEBUG_TIMERNAMES 00280 timeout->handler_name = handler_name; 00281 LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n", 00282 (void *)timeout, msecs, handler_name, (void *)arg)); 00283 #endif /* LWIP_DEBUG_TIMERNAMES */ 00284 00285 if (next_timeout == NULL) { 00286 next_timeout = timeout; 00287 return; 00288 } 00289 00290 if (next_timeout->time > msecs) { 00291 next_timeout->time -= msecs; 00292 timeout->next = next_timeout; 00293 next_timeout = timeout; 00294 } else { 00295 for(t = next_timeout; t != NULL; t = t->next) { 00296 timeout->time -= t->time; 00297 if (t->next == NULL || t->next->time > timeout->time) { 00298 if (t->next != NULL) { 00299 t->next->time -= timeout->time; 00300 } 00301 timeout->next = t->next; 00302 t->next = timeout; 00303 break; 00304 } 00305 } 00306 } 00307 } 00308 00309 /** 00310 * Go through timeout list (for this task only) and remove the first matching 00311 * entry, even though the timeout has not triggered yet. 00312 * 00313 * @note This function only works as expected if there is only one timeout 00314 * calling 'handler' in the list of timeouts. 00315 * 00316 * @param handler callback function that would be called by the timeout 00317 * @param arg callback argument that would be passed to handler 00318 */ 00319 void 00320 sys_untimeout(sys_timeout_handler handler, void *arg) 00321 { 00322 struct sys_timeo *prev_t, *t; 00323 00324 if (next_timeout == NULL) { 00325 return; 00326 } 00327 00328 for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { 00329 if ((t->h == handler) && (t->arg == arg)) { 00330 /* We have a match */ 00331 /* Unlink from previous in list */ 00332 if (prev_t == NULL) { 00333 next_timeout = t->next; 00334 } else { 00335 prev_t->next = t->next; 00336 } 00337 /* If not the last one, add time of this one back to next */ 00338 if (t->next != NULL) { 00339 t->next->time += t->time; 00340 } 00341 memp_free(MEMP_SYS_TIMEOUT, t); 00342 return; 00343 } 00344 } 00345 return; 00346 } 00347 00348 #if NO_SYS 00349 00350 /** Handle timeouts for NO_SYS==1 (i.e. without using 00351 * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout 00352 * handler functions when timeouts expire. 00353 * 00354 * Must be called periodically from your main loop. 00355 */ 00356 void 00357 sys_check_timeouts(void) 00358 { 00359 struct sys_timeo *tmptimeout; 00360 u32_t diff; 00361 sys_timeout_handler handler; 00362 void *arg; 00363 int had_one; 00364 u32_t now; 00365 00366 now = sys_now(); 00367 if (next_timeout) { 00368 /* this cares for wraparounds */ 00369 diff = LWIP_U32_DIFF(now, timeouts_last_time); 00370 do 00371 { 00372 had_one = 0; 00373 tmptimeout = next_timeout; 00374 if (tmptimeout->time <= diff) { 00375 /* timeout has expired */ 00376 had_one = 1; 00377 timeouts_last_time = now; 00378 diff -= tmptimeout->time; 00379 next_timeout = tmptimeout->next; 00380 handler = tmptimeout->h; 00381 arg = tmptimeout->arg; 00382 #if LWIP_DEBUG_TIMERNAMES 00383 if (handler != NULL) { 00384 LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n", 00385 tmptimeout->handler_name, arg)); 00386 } 00387 #endif /* LWIP_DEBUG_TIMERNAMES */ 00388 memp_free(MEMP_SYS_TIMEOUT, tmptimeout); 00389 if (handler != NULL) { 00390 handler(arg); 00391 } 00392 } 00393 /* repeat until all expired timers have been called */ 00394 }while(had_one); 00395 } 00396 } 00397 00398 /** Set back the timestamp of the last call to sys_check_timeouts() 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 timeouts_last_time = sys_now(); 00407 } 00408 00409 #else /* NO_SYS */ 00410 00411 /** 00412 * Wait (forever) for a message to arrive in an mbox. 00413 * While waiting, timeouts are processed. 00414 * 00415 * @param mbox the mbox to fetch the message from 00416 * @param msg the place to store the message 00417 */ 00418 void 00419 sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) 00420 { 00421 u32_t time_needed; 00422 struct sys_timeo *tmptimeout; 00423 sys_timeout_handler handler; 00424 void *arg; 00425 00426 again: 00427 if (!next_timeout) { 00428 time_needed = sys_arch_mbox_fetch(mbox, msg, 0); 00429 } else { 00430 if (next_timeout->time > 0) { 00431 time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time); 00432 } else { 00433 time_needed = SYS_ARCH_TIMEOUT; 00434 } 00435 00436 if (time_needed == SYS_ARCH_TIMEOUT) { 00437 /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message 00438 could be fetched. We should now call the timeout handler and 00439 deallocate the memory allocated for the timeout. */ 00440 tmptimeout = next_timeout; 00441 next_timeout = tmptimeout->next; 00442 handler = tmptimeout->h; 00443 arg = tmptimeout->arg; 00444 #if LWIP_DEBUG_TIMERNAMES 00445 if (handler != NULL) { 00446 LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n", 00447 tmptimeout->handler_name, arg)); 00448 } 00449 #endif /* LWIP_DEBUG_TIMERNAMES */ 00450 memp_free(MEMP_SYS_TIMEOUT, tmptimeout); 00451 if (handler != NULL) { 00452 /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the 00453 timeout handler function. */ 00454 LOCK_TCPIP_CORE(); 00455 handler(arg); 00456 UNLOCK_TCPIP_CORE(); 00457 } 00458 LWIP_TCPIP_THREAD_ALIVE(); 00459 00460 /* We try again to fetch a message from the mbox. */ 00461 goto again; 00462 } else { 00463 /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout 00464 occured. The time variable is set to the number of 00465 milliseconds we waited for the message. */ 00466 if (time_needed < next_timeout->time) { 00467 next_timeout->time -= time_needed; 00468 } else { 00469 next_timeout->time = 0; 00470 } 00471 } 00472 } 00473 } 00474 00475 #endif /* NO_SYS */ 00476 00477 #else /* LWIP_TIMERS */ 00478 /* Satisfy the TCP code which calls this function */ 00479 void 00480 tcp_timer_needed(void) 00481 { 00482 } 00483 #endif /* LWIP_TIMERS */
Generated on Tue Jul 12 2022 15:41:50 by
1.7.2