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 F7_Ethernet 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 #include "lwip/sys.h" 00060 #include "lwip/pbuf.h" 00061 00062 00063 /** The one and only timeout list */ 00064 static struct sys_timeo *next_timeout; 00065 #if NO_SYS 00066 static u32_t timeouts_last_time; 00067 #endif /* NO_SYS */ 00068 00069 #if LWIP_TCP 00070 /** global variable that shows if the tcp timer is currently scheduled or not */ 00071 static int tcpip_tcp_timer_active; 00072 00073 /** 00074 * Timer callback function that calls tcp_tmr() and reschedules itself. 00075 * 00076 * @param arg unused argument 00077 */ 00078 static void 00079 tcpip_tcp_timer(void *arg) 00080 { 00081 LWIP_UNUSED_ARG(arg); 00082 00083 /* call TCP timer handler */ 00084 tcp_tmr(); 00085 /* timer still needed? */ 00086 if (tcp_active_pcbs || tcp_tw_pcbs) { 00087 /* restart timer */ 00088 sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); 00089 } else { 00090 /* disable timer */ 00091 tcpip_tcp_timer_active = 0; 00092 } 00093 } 00094 00095 /** 00096 * Called from TCP_REG when registering a new PCB: 00097 * the reason is to have the TCP timer only running when 00098 * there are active (or time-wait) PCBs. 00099 */ 00100 void 00101 tcp_timer_needed(void) 00102 { 00103 /* timer is off but needed again? */ 00104 if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { 00105 /* enable and start timer */ 00106 tcpip_tcp_timer_active = 1; 00107 sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); 00108 } 00109 } 00110 #endif /* LWIP_TCP */ 00111 00112 #if IP_REASSEMBLY 00113 /** 00114 * Timer callback function that calls ip_reass_tmr() and reschedules itself. 00115 * 00116 * @param arg unused argument 00117 */ 00118 static void 00119 ip_reass_timer(void *arg) 00120 { 00121 LWIP_UNUSED_ARG(arg); 00122 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n")); 00123 ip_reass_tmr(); 00124 sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); 00125 } 00126 #endif /* IP_REASSEMBLY */ 00127 00128 #if LWIP_ARP 00129 /** 00130 * Timer callback function that calls etharp_tmr() and reschedules itself. 00131 * 00132 * @param arg unused argument 00133 */ 00134 static void 00135 arp_timer(void *arg) 00136 { 00137 LWIP_UNUSED_ARG(arg); 00138 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n")); 00139 etharp_tmr(); 00140 sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); 00141 } 00142 #endif /* LWIP_ARP */ 00143 00144 #if LWIP_DHCP 00145 /** 00146 * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself. 00147 * 00148 * @param arg unused argument 00149 */ 00150 static void 00151 dhcp_timer_coarse(void *arg) 00152 { 00153 LWIP_UNUSED_ARG(arg); 00154 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n")); 00155 dhcp_coarse_tmr(); 00156 sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); 00157 } 00158 00159 /** 00160 * Timer callback function that calls dhcp_fine_tmr() and reschedules itself. 00161 * 00162 * @param arg unused argument 00163 */ 00164 static void 00165 dhcp_timer_fine(void *arg) 00166 { 00167 LWIP_UNUSED_ARG(arg); 00168 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n")); 00169 dhcp_fine_tmr(); 00170 sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); 00171 } 00172 #endif /* LWIP_DHCP */ 00173 00174 #if LWIP_AUTOIP 00175 /** 00176 * Timer callback function that calls autoip_tmr() and reschedules itself. 00177 * 00178 * @param arg unused argument 00179 */ 00180 static void 00181 autoip_timer(void *arg) 00182 { 00183 LWIP_UNUSED_ARG(arg); 00184 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n")); 00185 autoip_tmr(); 00186 sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); 00187 } 00188 #endif /* LWIP_AUTOIP */ 00189 00190 #if LWIP_IGMP 00191 /** 00192 * Timer callback function that calls igmp_tmr() and reschedules itself. 00193 * 00194 * @param arg unused argument 00195 */ 00196 static void 00197 igmp_timer(void *arg) 00198 { 00199 LWIP_UNUSED_ARG(arg); 00200 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n")); 00201 igmp_tmr(); 00202 sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); 00203 } 00204 #endif /* LWIP_IGMP */ 00205 00206 #if LWIP_DNS 00207 /** 00208 * Timer callback function that calls dns_tmr() and reschedules itself. 00209 * 00210 * @param arg unused argument 00211 */ 00212 static void 00213 dns_timer(void *arg) 00214 { 00215 LWIP_UNUSED_ARG(arg); 00216 LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n")); 00217 dns_tmr(); 00218 sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); 00219 } 00220 #endif /* LWIP_DNS */ 00221 00222 /** Initialize this module */ 00223 void sys_timeouts_init(void) 00224 { 00225 #if IP_REASSEMBLY 00226 sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); 00227 #endif /* IP_REASSEMBLY */ 00228 #if LWIP_ARP 00229 sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); 00230 #endif /* LWIP_ARP */ 00231 #if LWIP_DHCP 00232 sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); 00233 sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); 00234 #endif /* LWIP_DHCP */ 00235 #if LWIP_AUTOIP 00236 sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); 00237 #endif /* LWIP_AUTOIP */ 00238 #if LWIP_IGMP 00239 sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); 00240 #endif /* LWIP_IGMP */ 00241 #if LWIP_DNS 00242 sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); 00243 #endif /* LWIP_DNS */ 00244 00245 #if NO_SYS 00246 /* Initialise timestamp for sys_check_timeouts */ 00247 timeouts_last_time = sys_now(); 00248 #endif 00249 } 00250 00251 /** 00252 * Create a one-shot timer (aka timeout). Timeouts are processed in the 00253 * following cases: 00254 * - while waiting for a message using sys_timeouts_mbox_fetch() 00255 * - by calling sys_check_timeouts() (NO_SYS==1 only) 00256 * 00257 * @param msecs time in milliseconds after that the timer should expire 00258 * @param handler callback function to call when msecs have elapsed 00259 * @param arg argument to pass to the callback function 00260 */ 00261 #if LWIP_DEBUG_TIMERNAMES 00262 void 00263 sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name) 00264 #else /* LWIP_DEBUG_TIMERNAMES */ 00265 void 00266 sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) 00267 #endif /* LWIP_DEBUG_TIMERNAMES */ 00268 { 00269 struct sys_timeo *timeout, *t; 00270 00271 timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT); 00272 if (timeout == NULL) { 00273 LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL); 00274 return; 00275 } 00276 timeout->next = NULL; 00277 timeout->h = handler; 00278 timeout->arg = arg; 00279 timeout->time = msecs; 00280 #if LWIP_DEBUG_TIMERNAMES 00281 timeout->handler_name = handler_name; 00282 LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n", 00283 (void *)timeout, msecs, handler_name, (void *)arg)); 00284 #endif /* LWIP_DEBUG_TIMERNAMES */ 00285 00286 if (next_timeout == NULL) { 00287 next_timeout = timeout; 00288 return; 00289 } 00290 00291 if (next_timeout->time > msecs) { 00292 next_timeout->time -= msecs; 00293 timeout->next = next_timeout; 00294 next_timeout = timeout; 00295 } else { 00296 for(t = next_timeout; t != NULL; t = t->next) { 00297 timeout->time -= t->time; 00298 if (t->next == NULL || t->next->time > timeout->time) { 00299 if (t->next != NULL) { 00300 t->next->time -= timeout->time; 00301 } 00302 timeout->next = t->next; 00303 t->next = timeout; 00304 break; 00305 } 00306 } 00307 } 00308 } 00309 00310 /** 00311 * Go through timeout list (for this task only) and remove the first matching 00312 * entry, even though the timeout has not triggered yet. 00313 * 00314 * @note This function only works as expected if there is only one timeout 00315 * calling 'handler' in the list of timeouts. 00316 * 00317 * @param handler callback function that would be called by the timeout 00318 * @param arg callback argument that would be passed to handler 00319 */ 00320 void 00321 sys_untimeout(sys_timeout_handler handler, void *arg) 00322 { 00323 struct sys_timeo *prev_t, *t; 00324 00325 if (next_timeout == NULL) { 00326 return; 00327 } 00328 00329 for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { 00330 if ((t->h == handler) && (t->arg == arg)) { 00331 /* We have a match */ 00332 /* Unlink from previous in list */ 00333 if (prev_t == NULL) { 00334 next_timeout = t->next; 00335 } else { 00336 prev_t->next = t->next; 00337 } 00338 /* If not the last one, add time of this one back to next */ 00339 if (t->next != NULL) { 00340 t->next->time += t->time; 00341 } 00342 memp_free(MEMP_SYS_TIMEOUT, t); 00343 return; 00344 } 00345 } 00346 return; 00347 } 00348 00349 #if NO_SYS 00350 00351 /** Handle timeouts for NO_SYS==1 (i.e. without using 00352 * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout 00353 * handler functions when timeouts expire. 00354 * 00355 * Must be called periodically from your main loop. 00356 */ 00357 void 00358 sys_check_timeouts(void) 00359 { 00360 if (next_timeout) { 00361 struct sys_timeo *tmptimeout; 00362 u32_t diff; 00363 sys_timeout_handler handler; 00364 void *arg; 00365 u8_t had_one; 00366 u32_t now; 00367 00368 now = sys_now(); 00369 /* this cares for wraparounds */ 00370 diff = now - timeouts_last_time; 00371 do 00372 { 00373 #if PBUF_POOL_FREE_OOSEQ 00374 PBUF_CHECK_FREE_OOSEQ(); 00375 #endif /* PBUF_POOL_FREE_OOSEQ */ 00376 had_one = 0; 00377 tmptimeout = next_timeout; 00378 if (tmptimeout && (tmptimeout->time <= diff)) { 00379 /* timeout has expired */ 00380 had_one = 1; 00381 timeouts_last_time = now; 00382 diff -= tmptimeout->time; 00383 next_timeout = tmptimeout->next; 00384 handler = tmptimeout->h; 00385 arg = tmptimeout->arg; 00386 #if LWIP_DEBUG_TIMERNAMES 00387 if (handler != NULL) { 00388 LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n", 00389 tmptimeout->handler_name, arg)); 00390 } 00391 #endif /* LWIP_DEBUG_TIMERNAMES */ 00392 memp_free(MEMP_SYS_TIMEOUT, tmptimeout); 00393 if (handler != NULL) { 00394 handler(arg); 00395 } 00396 } 00397 /* repeat until all expired timers have been called */ 00398 }while(had_one); 00399 } 00400 } 00401 00402 /** Set back the timestamp of the last call to sys_check_timeouts() 00403 * This is necessary if sys_check_timeouts() hasn't been called for a long 00404 * time (e.g. while saving energy) to prevent all timer functions of that 00405 * period being called. 00406 */ 00407 void 00408 sys_restart_timeouts(void) 00409 { 00410 timeouts_last_time = sys_now(); 00411 } 00412 00413 #else /* NO_SYS */ 00414 00415 /** 00416 * Wait (forever) for a message to arrive in an mbox. 00417 * While waiting, timeouts are processed. 00418 * 00419 * @param mbox the mbox to fetch the message from 00420 * @param msg the place to store the message 00421 */ 00422 void 00423 sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) 00424 { 00425 u32_t time_needed; 00426 struct sys_timeo *tmptimeout; 00427 sys_timeout_handler handler; 00428 void *arg; 00429 00430 again: 00431 if (!next_timeout) { 00432 time_needed = sys_arch_mbox_fetch(mbox, msg, 0); 00433 } else { 00434 if (next_timeout->time > 0) { 00435 time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time); 00436 } else { 00437 time_needed = SYS_ARCH_TIMEOUT; 00438 } 00439 00440 if (time_needed == SYS_ARCH_TIMEOUT) { 00441 /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message 00442 could be fetched. We should now call the timeout handler and 00443 deallocate the memory allocated for the timeout. */ 00444 tmptimeout = next_timeout; 00445 next_timeout = tmptimeout->next; 00446 handler = tmptimeout->h; 00447 arg = tmptimeout->arg; 00448 #if LWIP_DEBUG_TIMERNAMES 00449 if (handler != NULL) { 00450 LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n", 00451 tmptimeout->handler_name, arg)); 00452 } 00453 #endif /* LWIP_DEBUG_TIMERNAMES */ 00454 memp_free(MEMP_SYS_TIMEOUT, tmptimeout); 00455 if (handler != NULL) { 00456 /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the 00457 timeout handler function. */ 00458 LOCK_TCPIP_CORE(); 00459 handler(arg); 00460 UNLOCK_TCPIP_CORE(); 00461 } 00462 LWIP_TCPIP_THREAD_ALIVE(); 00463 00464 /* We try again to fetch a message from the mbox. */ 00465 goto again; 00466 } else { 00467 /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout 00468 occured. The time variable is set to the number of 00469 milliseconds we waited for the message. */ 00470 if (time_needed < next_timeout->time) { 00471 next_timeout->time -= time_needed; 00472 } else { 00473 next_timeout->time = 0; 00474 } 00475 } 00476 } 00477 } 00478 00479 #endif /* NO_SYS */ 00480 00481 #else /* LWIP_TIMERS */ 00482 /* Satisfy the TCP code which calls this function */ 00483 void 00484 tcp_timer_needed(void) 00485 { 00486 } 00487 #endif /* LWIP_TIMERS */
Generated on Tue Jul 12 2022 21:19:02 by
1.7.2
