1195972f6Sopenharmony_ci/** 2195972f6Sopenharmony_ci * @file 3195972f6Sopenharmony_ci * Stack-internal timers implementation. 4195972f6Sopenharmony_ci * This file includes timer callbacks for stack-internal timers as well as 5195972f6Sopenharmony_ci * functions to set up or stop timers and check for expired timers. 6195972f6Sopenharmony_ci * 7195972f6Sopenharmony_ci */ 8195972f6Sopenharmony_ci 9195972f6Sopenharmony_ci/* 10195972f6Sopenharmony_ci * Copyright (c) 2001-2004 Swedish Institute of Computer Science. 11195972f6Sopenharmony_ci * All rights reserved. 12195972f6Sopenharmony_ci * 13195972f6Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 14195972f6Sopenharmony_ci * are permitted provided that the following conditions are met: 15195972f6Sopenharmony_ci * 16195972f6Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, 17195972f6Sopenharmony_ci * this list of conditions and the following disclaimer. 18195972f6Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, 19195972f6Sopenharmony_ci * this list of conditions and the following disclaimer in the documentation 20195972f6Sopenharmony_ci * and/or other materials provided with the distribution. 21195972f6Sopenharmony_ci * 3. The name of the author may not be used to endorse or promote products 22195972f6Sopenharmony_ci * derived from this software without specific prior written permission. 23195972f6Sopenharmony_ci * 24195972f6Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 25195972f6Sopenharmony_ci * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 26195972f6Sopenharmony_ci * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 27195972f6Sopenharmony_ci * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 28195972f6Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 29195972f6Sopenharmony_ci * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 30195972f6Sopenharmony_ci * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 31195972f6Sopenharmony_ci * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 32195972f6Sopenharmony_ci * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 33195972f6Sopenharmony_ci * OF SUCH DAMAGE. 34195972f6Sopenharmony_ci * 35195972f6Sopenharmony_ci * This file is part of the lwIP TCP/IP stack. 36195972f6Sopenharmony_ci * 37195972f6Sopenharmony_ci * Author: Adam Dunkels <adam@sics.se> 38195972f6Sopenharmony_ci * Simon Goldschmidt 39195972f6Sopenharmony_ci * 40195972f6Sopenharmony_ci */ 41195972f6Sopenharmony_ci 42195972f6Sopenharmony_ci#include "lwip/opt.h" 43195972f6Sopenharmony_ci 44195972f6Sopenharmony_ci#include "lwip/timeouts.h" 45195972f6Sopenharmony_ci#include "lwip/priv/tcp_priv.h" 46195972f6Sopenharmony_ci 47195972f6Sopenharmony_ci#include "lwip/def.h" 48195972f6Sopenharmony_ci#include "lwip/memp.h" 49195972f6Sopenharmony_ci#include "lwip/priv/tcpip_priv.h" 50195972f6Sopenharmony_ci 51195972f6Sopenharmony_ci#include "lwip/ip4_frag.h" 52195972f6Sopenharmony_ci#include "lwip/etharp.h" 53195972f6Sopenharmony_ci#include "lwip/dhcp.h" 54195972f6Sopenharmony_ci#include "lwip/autoip.h" 55195972f6Sopenharmony_ci#include "lwip/igmp.h" 56195972f6Sopenharmony_ci#include "lwip/dns.h" 57195972f6Sopenharmony_ci#include "lwip/nd6.h" 58195972f6Sopenharmony_ci#include "lwip/ip6_frag.h" 59195972f6Sopenharmony_ci#include "lwip/mld6.h" 60195972f6Sopenharmony_ci#include "lwip/dhcp6.h" 61195972f6Sopenharmony_ci#include "lwip/sys.h" 62195972f6Sopenharmony_ci#include "lwip/pbuf.h" 63195972f6Sopenharmony_ci 64195972f6Sopenharmony_ci#if !LWIP_LOWPOWER 65195972f6Sopenharmony_ci 66195972f6Sopenharmony_ci#if LWIP_DEBUG_TIMERNAMES 67195972f6Sopenharmony_ci#define HANDLER(x) x, #x 68195972f6Sopenharmony_ci#else /* LWIP_DEBUG_TIMERNAMES */ 69195972f6Sopenharmony_ci#define HANDLER(x) x 70195972f6Sopenharmony_ci#endif /* LWIP_DEBUG_TIMERNAMES */ 71195972f6Sopenharmony_ci 72195972f6Sopenharmony_ci#define LWIP_MAX_TIMEOUT 0x7fffffff 73195972f6Sopenharmony_ci 74195972f6Sopenharmony_ci/* Check if timer's expiry time is greater than time and care about u32_t wraparounds */ 75195972f6Sopenharmony_ci#define TIME_LESS_THAN(t, compare_to) ( (((u32_t)((t)-(compare_to))) > LWIP_MAX_TIMEOUT) ? 1 : 0 ) 76195972f6Sopenharmony_ci 77195972f6Sopenharmony_ci/** This array contains all stack-internal cyclic timers. To get the number of 78195972f6Sopenharmony_ci * timers, use LWIP_ARRAYSIZE() */ 79195972f6Sopenharmony_ciconst struct lwip_cyclic_timer lwip_cyclic_timers[] = { 80195972f6Sopenharmony_ci#if LWIP_TCP 81195972f6Sopenharmony_ci /* The TCP timer is a special case: it does not have to run always and 82195972f6Sopenharmony_ci is triggered to start from TCP using tcp_timer_needed() */ 83195972f6Sopenharmony_ci {TCP_TMR_INTERVAL, HANDLER(tcp_tmr)}, 84195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 85195972f6Sopenharmony_ci#if LWIP_IPV4 86195972f6Sopenharmony_ci#if IP_REASSEMBLY 87195972f6Sopenharmony_ci {IP_TMR_INTERVAL, HANDLER(ip_reass_tmr)}, 88195972f6Sopenharmony_ci#endif /* IP_REASSEMBLY */ 89195972f6Sopenharmony_ci#if LWIP_ARP 90195972f6Sopenharmony_ci {ARP_TMR_INTERVAL, HANDLER(etharp_tmr)}, 91195972f6Sopenharmony_ci#endif /* LWIP_ARP */ 92195972f6Sopenharmony_ci#if LWIP_DHCP 93195972f6Sopenharmony_ci {DHCP_COARSE_TIMER_MSECS, HANDLER(dhcp_coarse_tmr)}, 94195972f6Sopenharmony_ci {DHCP_FINE_TIMER_MSECS, HANDLER(dhcp_fine_tmr)}, 95195972f6Sopenharmony_ci#endif /* LWIP_DHCP */ 96195972f6Sopenharmony_ci#if LWIP_AUTOIP 97195972f6Sopenharmony_ci {AUTOIP_TMR_INTERVAL, HANDLER(autoip_tmr)}, 98195972f6Sopenharmony_ci#endif /* LWIP_AUTOIP */ 99195972f6Sopenharmony_ci#if LWIP_IGMP 100195972f6Sopenharmony_ci {IGMP_TMR_INTERVAL, HANDLER(igmp_tmr)}, 101195972f6Sopenharmony_ci#endif /* LWIP_IGMP */ 102195972f6Sopenharmony_ci#endif /* LWIP_IPV4 */ 103195972f6Sopenharmony_ci#if LWIP_DNS 104195972f6Sopenharmony_ci {DNS_TMR_INTERVAL, HANDLER(dns_tmr)}, 105195972f6Sopenharmony_ci#endif /* LWIP_DNS */ 106195972f6Sopenharmony_ci#if LWIP_IPV6 107195972f6Sopenharmony_ci {ND6_TMR_INTERVAL, HANDLER(nd6_tmr)}, 108195972f6Sopenharmony_ci#if LWIP_IPV6_REASS 109195972f6Sopenharmony_ci {IP6_REASS_TMR_INTERVAL, HANDLER(ip6_reass_tmr)}, 110195972f6Sopenharmony_ci#endif /* LWIP_IPV6_REASS */ 111195972f6Sopenharmony_ci#if LWIP_IPV6_MLD 112195972f6Sopenharmony_ci {MLD6_TMR_INTERVAL, HANDLER(mld6_tmr)}, 113195972f6Sopenharmony_ci#endif /* LWIP_IPV6_MLD */ 114195972f6Sopenharmony_ci#if LWIP_IPV6_DHCP6 115195972f6Sopenharmony_ci {DHCP6_TIMER_MSECS, HANDLER(dhcp6_tmr)}, 116195972f6Sopenharmony_ci#endif /* LWIP_IPV6_DHCP6 */ 117195972f6Sopenharmony_ci#endif /* LWIP_IPV6 */ 118195972f6Sopenharmony_ci}; 119195972f6Sopenharmony_ciconst int lwip_num_cyclic_timers = LWIP_ARRAYSIZE(lwip_cyclic_timers); 120195972f6Sopenharmony_ci 121195972f6Sopenharmony_ci#if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM 122195972f6Sopenharmony_ci 123195972f6Sopenharmony_ci/** The one and only timeout list */ 124195972f6Sopenharmony_cistatic struct sys_timeo *next_timeout; 125195972f6Sopenharmony_ci 126195972f6Sopenharmony_cistatic u32_t current_timeout_due_time; 127195972f6Sopenharmony_ci 128195972f6Sopenharmony_ci#if LWIP_TESTMODE 129195972f6Sopenharmony_cistruct sys_timeo** 130195972f6Sopenharmony_cisys_timeouts_get_next_timeout(void) 131195972f6Sopenharmony_ci{ 132195972f6Sopenharmony_ci return &next_timeout; 133195972f6Sopenharmony_ci} 134195972f6Sopenharmony_ci#endif 135195972f6Sopenharmony_ci 136195972f6Sopenharmony_ci#if LWIP_TCP 137195972f6Sopenharmony_ci/** global variable that shows if the tcp timer is currently scheduled or not */ 138195972f6Sopenharmony_cistatic int tcpip_tcp_timer_active; 139195972f6Sopenharmony_ci 140195972f6Sopenharmony_ci/** 141195972f6Sopenharmony_ci * Timer callback function that calls tcp_tmr() and reschedules itself. 142195972f6Sopenharmony_ci * 143195972f6Sopenharmony_ci * @param arg unused argument 144195972f6Sopenharmony_ci */ 145195972f6Sopenharmony_cistatic void 146195972f6Sopenharmony_citcpip_tcp_timer(void *arg) 147195972f6Sopenharmony_ci{ 148195972f6Sopenharmony_ci LWIP_UNUSED_ARG(arg); 149195972f6Sopenharmony_ci 150195972f6Sopenharmony_ci /* call TCP timer handler */ 151195972f6Sopenharmony_ci tcp_tmr(); 152195972f6Sopenharmony_ci /* timer still needed? */ 153195972f6Sopenharmony_ci if (tcp_active_pcbs || tcp_tw_pcbs) { 154195972f6Sopenharmony_ci /* restart timer */ 155195972f6Sopenharmony_ci sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); 156195972f6Sopenharmony_ci } else { 157195972f6Sopenharmony_ci /* disable timer */ 158195972f6Sopenharmony_ci tcpip_tcp_timer_active = 0; 159195972f6Sopenharmony_ci } 160195972f6Sopenharmony_ci} 161195972f6Sopenharmony_ci 162195972f6Sopenharmony_ci/** 163195972f6Sopenharmony_ci * Called from TCP_REG when registering a new PCB: 164195972f6Sopenharmony_ci * the reason is to have the TCP timer only running when 165195972f6Sopenharmony_ci * there are active (or time-wait) PCBs. 166195972f6Sopenharmony_ci */ 167195972f6Sopenharmony_civoid 168195972f6Sopenharmony_citcp_timer_needed(void) 169195972f6Sopenharmony_ci{ 170195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 171195972f6Sopenharmony_ci 172195972f6Sopenharmony_ci /* timer is off but needed again? */ 173195972f6Sopenharmony_ci if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { 174195972f6Sopenharmony_ci /* enable and start timer */ 175195972f6Sopenharmony_ci tcpip_tcp_timer_active = 1; 176195972f6Sopenharmony_ci sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); 177195972f6Sopenharmony_ci } 178195972f6Sopenharmony_ci} 179195972f6Sopenharmony_ci#endif /* LWIP_TCP */ 180195972f6Sopenharmony_ci 181195972f6Sopenharmony_cistatic void 182195972f6Sopenharmony_ci#if LWIP_DEBUG_TIMERNAMES 183195972f6Sopenharmony_cisys_timeout_abs(u32_t abs_time, sys_timeout_handler handler, void *arg, const char *handler_name) 184195972f6Sopenharmony_ci#else /* LWIP_DEBUG_TIMERNAMES */ 185195972f6Sopenharmony_cisys_timeout_abs(u32_t abs_time, sys_timeout_handler handler, void *arg) 186195972f6Sopenharmony_ci#endif 187195972f6Sopenharmony_ci{ 188195972f6Sopenharmony_ci struct sys_timeo *timeout, *t; 189195972f6Sopenharmony_ci 190195972f6Sopenharmony_ci timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT); 191195972f6Sopenharmony_ci if (timeout == NULL) { 192195972f6Sopenharmony_ci LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL); 193195972f6Sopenharmony_ci return; 194195972f6Sopenharmony_ci } 195195972f6Sopenharmony_ci 196195972f6Sopenharmony_ci timeout->next = NULL; 197195972f6Sopenharmony_ci timeout->h = handler; 198195972f6Sopenharmony_ci timeout->arg = arg; 199195972f6Sopenharmony_ci timeout->time = abs_time; 200195972f6Sopenharmony_ci 201195972f6Sopenharmony_ci#if LWIP_DEBUG_TIMERNAMES 202195972f6Sopenharmony_ci timeout->handler_name = handler_name; 203195972f6Sopenharmony_ci LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p abs_time=%"U32_F" handler=%s arg=%p\n", 204195972f6Sopenharmony_ci (void *)timeout, abs_time, handler_name, (void *)arg)); 205195972f6Sopenharmony_ci#endif /* LWIP_DEBUG_TIMERNAMES */ 206195972f6Sopenharmony_ci 207195972f6Sopenharmony_ci if (next_timeout == NULL) { 208195972f6Sopenharmony_ci next_timeout = timeout; 209195972f6Sopenharmony_ci return; 210195972f6Sopenharmony_ci } 211195972f6Sopenharmony_ci if (TIME_LESS_THAN(timeout->time, next_timeout->time)) { 212195972f6Sopenharmony_ci timeout->next = next_timeout; 213195972f6Sopenharmony_ci next_timeout = timeout; 214195972f6Sopenharmony_ci } else { 215195972f6Sopenharmony_ci for (t = next_timeout; t != NULL; t = t->next) { 216195972f6Sopenharmony_ci if ((t->next == NULL) || TIME_LESS_THAN(timeout->time, t->next->time)) { 217195972f6Sopenharmony_ci timeout->next = t->next; 218195972f6Sopenharmony_ci t->next = timeout; 219195972f6Sopenharmony_ci break; 220195972f6Sopenharmony_ci } 221195972f6Sopenharmony_ci } 222195972f6Sopenharmony_ci } 223195972f6Sopenharmony_ci} 224195972f6Sopenharmony_ci 225195972f6Sopenharmony_ci/** 226195972f6Sopenharmony_ci * Timer callback function that calls cyclic->handler() and reschedules itself. 227195972f6Sopenharmony_ci * 228195972f6Sopenharmony_ci * @param arg unused argument 229195972f6Sopenharmony_ci */ 230195972f6Sopenharmony_ci#if !LWIP_TESTMODE 231195972f6Sopenharmony_cistatic 232195972f6Sopenharmony_ci#endif 233195972f6Sopenharmony_civoid 234195972f6Sopenharmony_cilwip_cyclic_timer(void *arg) 235195972f6Sopenharmony_ci{ 236195972f6Sopenharmony_ci u32_t now; 237195972f6Sopenharmony_ci u32_t next_timeout_time; 238195972f6Sopenharmony_ci const struct lwip_cyclic_timer *cyclic = (const struct lwip_cyclic_timer *)arg; 239195972f6Sopenharmony_ci 240195972f6Sopenharmony_ci#if LWIP_DEBUG_TIMERNAMES 241195972f6Sopenharmony_ci LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: %s()\n", cyclic->handler_name)); 242195972f6Sopenharmony_ci#endif 243195972f6Sopenharmony_ci cyclic->handler(); 244195972f6Sopenharmony_ci 245195972f6Sopenharmony_ci now = sys_now(); 246195972f6Sopenharmony_ci next_timeout_time = (u32_t)(current_timeout_due_time + cyclic->interval_ms); /* overflow handled by TIME_LESS_THAN macro */ 247195972f6Sopenharmony_ci if (TIME_LESS_THAN(next_timeout_time, now)) { 248195972f6Sopenharmony_ci /* timer would immediately expire again -> "overload" -> restart without any correction */ 249195972f6Sopenharmony_ci#if LWIP_DEBUG_TIMERNAMES 250195972f6Sopenharmony_ci sys_timeout_abs((u32_t)(now + cyclic->interval_ms), lwip_cyclic_timer, arg, cyclic->handler_name); 251195972f6Sopenharmony_ci#else 252195972f6Sopenharmony_ci sys_timeout_abs((u32_t)(now + cyclic->interval_ms), lwip_cyclic_timer, arg); 253195972f6Sopenharmony_ci#endif 254195972f6Sopenharmony_ci 255195972f6Sopenharmony_ci } else { 256195972f6Sopenharmony_ci /* correct cyclic interval with handler execution delay and sys_check_timeouts jitter */ 257195972f6Sopenharmony_ci#if LWIP_DEBUG_TIMERNAMES 258195972f6Sopenharmony_ci sys_timeout_abs(next_timeout_time, lwip_cyclic_timer, arg, cyclic->handler_name); 259195972f6Sopenharmony_ci#else 260195972f6Sopenharmony_ci sys_timeout_abs(next_timeout_time, lwip_cyclic_timer, arg); 261195972f6Sopenharmony_ci#endif 262195972f6Sopenharmony_ci } 263195972f6Sopenharmony_ci} 264195972f6Sopenharmony_ci 265195972f6Sopenharmony_ci/** Initialize this module */ 266195972f6Sopenharmony_civoid sys_timeouts_init(void) 267195972f6Sopenharmony_ci{ 268195972f6Sopenharmony_ci size_t i; 269195972f6Sopenharmony_ci /* tcp_tmr() at index 0 is started on demand */ 270195972f6Sopenharmony_ci for (i = (LWIP_TCP ? 1 : 0); i < LWIP_ARRAYSIZE(lwip_cyclic_timers); i++) { 271195972f6Sopenharmony_ci /* we have to cast via size_t to get rid of const warning 272195972f6Sopenharmony_ci (this is OK as cyclic_timer() casts back to const* */ 273195972f6Sopenharmony_ci sys_timeout(lwip_cyclic_timers[i].interval_ms, lwip_cyclic_timer, LWIP_CONST_CAST(void *, &lwip_cyclic_timers[i])); 274195972f6Sopenharmony_ci } 275195972f6Sopenharmony_ci} 276195972f6Sopenharmony_ci 277195972f6Sopenharmony_ci/** 278195972f6Sopenharmony_ci * Create a one-shot timer (aka timeout). Timeouts are processed in the 279195972f6Sopenharmony_ci * following cases: 280195972f6Sopenharmony_ci * - while waiting for a message using sys_timeouts_mbox_fetch() 281195972f6Sopenharmony_ci * - by calling sys_check_timeouts() (NO_SYS==1 only) 282195972f6Sopenharmony_ci * 283195972f6Sopenharmony_ci * @param msecs time in milliseconds after that the timer should expire 284195972f6Sopenharmony_ci * @param handler callback function to call when msecs have elapsed 285195972f6Sopenharmony_ci * @param arg argument to pass to the callback function 286195972f6Sopenharmony_ci */ 287195972f6Sopenharmony_ci#if LWIP_DEBUG_TIMERNAMES 288195972f6Sopenharmony_civoid 289195972f6Sopenharmony_cisys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char *handler_name) 290195972f6Sopenharmony_ci#else /* LWIP_DEBUG_TIMERNAMES */ 291195972f6Sopenharmony_civoid 292195972f6Sopenharmony_cisys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) 293195972f6Sopenharmony_ci#endif /* LWIP_DEBUG_TIMERNAMES */ 294195972f6Sopenharmony_ci{ 295195972f6Sopenharmony_ci u32_t next_timeout_time; 296195972f6Sopenharmony_ci 297195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 298195972f6Sopenharmony_ci 299195972f6Sopenharmony_ci LWIP_ASSERT("Timeout time too long, max is LWIP_UINT32_MAX/4 msecs", msecs <= (LWIP_UINT32_MAX / 4)); 300195972f6Sopenharmony_ci 301195972f6Sopenharmony_ci next_timeout_time = (u32_t)(sys_now() + msecs); /* overflow handled by TIME_LESS_THAN macro */ 302195972f6Sopenharmony_ci 303195972f6Sopenharmony_ci#if LWIP_DEBUG_TIMERNAMES 304195972f6Sopenharmony_ci sys_timeout_abs(next_timeout_time, handler, arg, handler_name); 305195972f6Sopenharmony_ci#else 306195972f6Sopenharmony_ci sys_timeout_abs(next_timeout_time, handler, arg); 307195972f6Sopenharmony_ci#endif 308195972f6Sopenharmony_ci} 309195972f6Sopenharmony_ci 310195972f6Sopenharmony_ci/** 311195972f6Sopenharmony_ci * Go through timeout list (for this task only) and remove the first matching 312195972f6Sopenharmony_ci * entry (subsequent entries remain untouched), even though the timeout has not 313195972f6Sopenharmony_ci * triggered yet. 314195972f6Sopenharmony_ci * 315195972f6Sopenharmony_ci * @param handler callback function that would be called by the timeout 316195972f6Sopenharmony_ci * @param arg callback argument that would be passed to handler 317195972f6Sopenharmony_ci*/ 318195972f6Sopenharmony_civoid 319195972f6Sopenharmony_cisys_untimeout(sys_timeout_handler handler, void *arg) 320195972f6Sopenharmony_ci{ 321195972f6Sopenharmony_ci struct sys_timeo *prev_t, *t; 322195972f6Sopenharmony_ci 323195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 324195972f6Sopenharmony_ci 325195972f6Sopenharmony_ci if (next_timeout == NULL) { 326195972f6Sopenharmony_ci return; 327195972f6Sopenharmony_ci } 328195972f6Sopenharmony_ci 329195972f6Sopenharmony_ci for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { 330195972f6Sopenharmony_ci if ((t->h == handler) && (t->arg == arg)) { 331195972f6Sopenharmony_ci /* We have a match */ 332195972f6Sopenharmony_ci /* Unlink from previous in list */ 333195972f6Sopenharmony_ci if (prev_t == NULL) { 334195972f6Sopenharmony_ci next_timeout = t->next; 335195972f6Sopenharmony_ci } else { 336195972f6Sopenharmony_ci prev_t->next = t->next; 337195972f6Sopenharmony_ci } 338195972f6Sopenharmony_ci memp_free(MEMP_SYS_TIMEOUT, t); 339195972f6Sopenharmony_ci return; 340195972f6Sopenharmony_ci } 341195972f6Sopenharmony_ci } 342195972f6Sopenharmony_ci return; 343195972f6Sopenharmony_ci} 344195972f6Sopenharmony_ci 345195972f6Sopenharmony_ci/** 346195972f6Sopenharmony_ci * @ingroup lwip_nosys 347195972f6Sopenharmony_ci * Handle timeouts for NO_SYS==1 (i.e. without using 348195972f6Sopenharmony_ci * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout 349195972f6Sopenharmony_ci * handler functions when timeouts expire. 350195972f6Sopenharmony_ci * 351195972f6Sopenharmony_ci * Must be called periodically from your main loop. 352195972f6Sopenharmony_ci */ 353195972f6Sopenharmony_civoid 354195972f6Sopenharmony_cisys_check_timeouts(void) 355195972f6Sopenharmony_ci{ 356195972f6Sopenharmony_ci u32_t now; 357195972f6Sopenharmony_ci 358195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 359195972f6Sopenharmony_ci 360195972f6Sopenharmony_ci /* Process only timers expired at the start of the function. */ 361195972f6Sopenharmony_ci now = sys_now(); 362195972f6Sopenharmony_ci 363195972f6Sopenharmony_ci do { 364195972f6Sopenharmony_ci struct sys_timeo *tmptimeout; 365195972f6Sopenharmony_ci sys_timeout_handler handler; 366195972f6Sopenharmony_ci void *arg; 367195972f6Sopenharmony_ci 368195972f6Sopenharmony_ci PBUF_CHECK_FREE_OOSEQ(); 369195972f6Sopenharmony_ci 370195972f6Sopenharmony_ci tmptimeout = next_timeout; 371195972f6Sopenharmony_ci if (tmptimeout == NULL) { 372195972f6Sopenharmony_ci return; 373195972f6Sopenharmony_ci } 374195972f6Sopenharmony_ci 375195972f6Sopenharmony_ci if (TIME_LESS_THAN(now, tmptimeout->time)) { 376195972f6Sopenharmony_ci return; 377195972f6Sopenharmony_ci } 378195972f6Sopenharmony_ci 379195972f6Sopenharmony_ci /* Timeout has expired */ 380195972f6Sopenharmony_ci next_timeout = tmptimeout->next; 381195972f6Sopenharmony_ci handler = tmptimeout->h; 382195972f6Sopenharmony_ci arg = tmptimeout->arg; 383195972f6Sopenharmony_ci current_timeout_due_time = tmptimeout->time; 384195972f6Sopenharmony_ci#if LWIP_DEBUG_TIMERNAMES 385195972f6Sopenharmony_ci if (handler != NULL) { 386195972f6Sopenharmony_ci LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s t=%"U32_F" arg=%p\n", 387195972f6Sopenharmony_ci tmptimeout->handler_name, sys_now() - tmptimeout->time, arg)); 388195972f6Sopenharmony_ci } 389195972f6Sopenharmony_ci#endif /* LWIP_DEBUG_TIMERNAMES */ 390195972f6Sopenharmony_ci memp_free(MEMP_SYS_TIMEOUT, tmptimeout); 391195972f6Sopenharmony_ci if (handler != NULL) { 392195972f6Sopenharmony_ci handler(arg); 393195972f6Sopenharmony_ci } 394195972f6Sopenharmony_ci LWIP_TCPIP_THREAD_ALIVE(); 395195972f6Sopenharmony_ci 396195972f6Sopenharmony_ci /* Repeat until all expired timers have been called */ 397195972f6Sopenharmony_ci } while (1); 398195972f6Sopenharmony_ci} 399195972f6Sopenharmony_ci 400195972f6Sopenharmony_ci/** Rebase the timeout times to the current time. 401195972f6Sopenharmony_ci * This is necessary if sys_check_timeouts() hasn't been called for a long 402195972f6Sopenharmony_ci * time (e.g. while saving energy) to prevent all timer functions of that 403195972f6Sopenharmony_ci * period being called. 404195972f6Sopenharmony_ci */ 405195972f6Sopenharmony_civoid 406195972f6Sopenharmony_cisys_restart_timeouts(void) 407195972f6Sopenharmony_ci{ 408195972f6Sopenharmony_ci u32_t now; 409195972f6Sopenharmony_ci u32_t base; 410195972f6Sopenharmony_ci struct sys_timeo *t; 411195972f6Sopenharmony_ci 412195972f6Sopenharmony_ci if (next_timeout == NULL) { 413195972f6Sopenharmony_ci return; 414195972f6Sopenharmony_ci } 415195972f6Sopenharmony_ci 416195972f6Sopenharmony_ci now = sys_now(); 417195972f6Sopenharmony_ci base = next_timeout->time; 418195972f6Sopenharmony_ci 419195972f6Sopenharmony_ci for (t = next_timeout; t != NULL; t = t->next) { 420195972f6Sopenharmony_ci t->time = (t->time - base) + now; 421195972f6Sopenharmony_ci } 422195972f6Sopenharmony_ci} 423195972f6Sopenharmony_ci 424195972f6Sopenharmony_ci/** Return the time left before the next timeout is due. If no timeouts are 425195972f6Sopenharmony_ci * enqueued, returns 0xffffffff 426195972f6Sopenharmony_ci */ 427195972f6Sopenharmony_ciu32_t 428195972f6Sopenharmony_cisys_timeouts_sleeptime(void) 429195972f6Sopenharmony_ci{ 430195972f6Sopenharmony_ci u32_t now; 431195972f6Sopenharmony_ci 432195972f6Sopenharmony_ci LWIP_ASSERT_CORE_LOCKED(); 433195972f6Sopenharmony_ci 434195972f6Sopenharmony_ci if (next_timeout == NULL) { 435195972f6Sopenharmony_ci return SYS_TIMEOUTS_SLEEPTIME_INFINITE; 436195972f6Sopenharmony_ci } 437195972f6Sopenharmony_ci now = sys_now(); 438195972f6Sopenharmony_ci if (TIME_LESS_THAN(next_timeout->time, now)) { 439195972f6Sopenharmony_ci return 0; 440195972f6Sopenharmony_ci } else { 441195972f6Sopenharmony_ci u32_t ret = (u32_t)(next_timeout->time - now); 442195972f6Sopenharmony_ci LWIP_ASSERT("invalid sleeptime", ret <= LWIP_MAX_TIMEOUT); 443195972f6Sopenharmony_ci return ret; 444195972f6Sopenharmony_ci } 445195972f6Sopenharmony_ci} 446195972f6Sopenharmony_ci 447195972f6Sopenharmony_ci#else /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ 448195972f6Sopenharmony_ci/* Satisfy the TCP code which calls this function */ 449195972f6Sopenharmony_civoid 450195972f6Sopenharmony_citcp_timer_needed(void) 451195972f6Sopenharmony_ci{ 452195972f6Sopenharmony_ci} 453195972f6Sopenharmony_ci#endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */ 454195972f6Sopenharmony_ci#endif /* !LWIP_LOWPOWER */ 455