Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers lwip_timeouts.c Source File

lwip_timeouts.c

Go to the documentation of this file.
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 */