timers.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. /**
  2. * @file
  3. * Stack-internal timers implementation.
  4. * This file includes timer callbacks for stack-internal timers as well as
  5. * functions to set up or stop timers and check for expired timers.
  6. *
  7. */
  8. /*
  9. * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
  10. * All rights reserved.
  11. *
  12. * Redistribution and use in source and binary forms, with or without modification,
  13. * are permitted provided that the following conditions are met:
  14. *
  15. * 1. Redistributions of source code must retain the above copyright notice,
  16. * this list of conditions and the following disclaimer.
  17. * 2. Redistributions in binary form must reproduce the above copyright notice,
  18. * this list of conditions and the following disclaimer in the documentation
  19. * and/or other materials provided with the distribution.
  20. * 3. The name of the author may not be used to endorse or promote products
  21. * derived from this software without specific prior written permission.
  22. *
  23. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  24. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  25. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
  26. * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  27. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  28. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  29. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  30. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  31. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  32. * OF SUCH DAMAGE.
  33. *
  34. * This file is part of the lwIP TCP/IP stack.
  35. *
  36. * Author: Adam Dunkels <adam@sics.se>
  37. * Simon Goldschmidt
  38. *
  39. */
  40. #include "lwip/opt.h"
  41. #include "lwip/timers.h"
  42. #include "lwip/tcp_impl.h"
  43. #if LWIP_TIMERS
  44. #include "lwip/def.h"
  45. #include "lwip/memp.h"
  46. #include "lwip/tcpip.h"
  47. #include "lwip/ip_frag.h"
  48. #include "netif/etharp.h"
  49. #include "lwip/dhcp.h"
  50. #include "lwip/autoip.h"
  51. #include "lwip/igmp.h"
  52. #include "lwip/dns.h"
  53. #ifdef MEMLEAK_DEBUG
  54. static const char mem_debug_file[] ICACHE_RODATA_ATTR = __FILE__;
  55. #endif
  56. /** The one and only timeout list */
  57. static struct sys_timeo *next_timeout = NULL;
  58. #if NO_SYS
  59. static u32_t timeouts_last_time;
  60. #endif /* NO_SYS */
  61. #if LWIP_TCP
  62. /** global variable that shows if the tcp timer is currently scheduled or not */
  63. static int tcpip_tcp_timer_active;
  64. /**
  65. * Timer callback function that calls tcp_tmr() and reschedules itself.
  66. *
  67. * @param arg unused argument
  68. */
  69. static void ICACHE_FLASH_ATTR
  70. tcpip_tcp_timer(void *arg)
  71. {
  72. LWIP_UNUSED_ARG(arg);
  73. /* call TCP timer handler */
  74. tcp_tmr();
  75. /* timer still needed? */
  76. if (tcp_active_pcbs || tcp_tw_pcbs) {
  77. /* restart timer */
  78. sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
  79. } else {
  80. /* disable timer */
  81. tcpip_tcp_timer_active = 0;
  82. }
  83. }
  84. /**
  85. * Called from TCP_REG when registering a new PCB:
  86. * the reason is to have the TCP timer only running when
  87. * there are active (or time-wait) PCBs.
  88. */
  89. void
  90. tcp_timer_needed(void)
  91. {
  92. /* timer is off but needed again? */
  93. if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
  94. /* enable and start timer */
  95. tcpip_tcp_timer_active = 1;
  96. sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
  97. }
  98. }
  99. /**
  100. * Timer callback function that calls tcp_tmr() and reschedules itself.
  101. *
  102. * @param arg unused argument
  103. */
  104. static void ICACHE_FLASH_ATTR
  105. tcp_timer_coarse(void *arg)
  106. {
  107. LWIP_UNUSED_ARG(arg);
  108. LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: tcp_tmr()\n"));
  109. tcp_tmr();
  110. sys_timeout(TCP_TMR_INTERVAL, tcp_timer_coarse, NULL);
  111. }
  112. #endif /* LWIP_TCP */
  113. #if IP_REASSEMBLY
  114. /**
  115. * Timer callback function that calls ip_reass_tmr() and reschedules itself.
  116. *
  117. * @param arg unused argument
  118. */
  119. static void ICACHE_FLASH_ATTR
  120. ip_reass_timer(void *arg)
  121. {
  122. LWIP_UNUSED_ARG(arg);
  123. LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n"));
  124. ip_reass_tmr();
  125. sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
  126. }
  127. #endif /* IP_REASSEMBLY */
  128. #if LWIP_ARP
  129. /**
  130. * Timer callback function that calls etharp_tmr() and reschedules itself.
  131. *
  132. * @param arg unused argument
  133. */
  134. static void ICACHE_FLASH_ATTR
  135. arp_timer(void *arg)
  136. {
  137. LWIP_UNUSED_ARG(arg);
  138. LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n"));
  139. etharp_tmr();
  140. sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
  141. }
  142. #endif /* LWIP_ARP */
  143. #if LWIP_DHCP
  144. /**
  145. * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
  146. *
  147. * @param arg unused argument
  148. */
  149. extern void dhcps_coarse_tmr(void);
  150. static void
  151. dhcp_timer_coarse(void *arg)
  152. {
  153. LWIP_UNUSED_ARG(arg);
  154. LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
  155. dhcp_coarse_tmr();
  156. dhcps_coarse_tmr();
  157. sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
  158. }
  159. /**
  160. * Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
  161. *
  162. * @param arg unused argument
  163. */
  164. static void
  165. dhcp_timer_fine(void *arg)
  166. {
  167. LWIP_UNUSED_ARG(arg);
  168. LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
  169. dhcp_fine_tmr();
  170. sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
  171. }
  172. #endif /* LWIP_DHCP */
  173. #if LWIP_AUTOIP
  174. /**
  175. * Timer callback function that calls autoip_tmr() and reschedules itself.
  176. *
  177. * @param arg unused argument
  178. */
  179. static void
  180. autoip_timer(void *arg)
  181. {
  182. LWIP_UNUSED_ARG(arg);
  183. LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n"));
  184. autoip_tmr();
  185. sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
  186. }
  187. #endif /* LWIP_AUTOIP */
  188. #if LWIP_IGMP
  189. /**
  190. * Timer callback function that calls igmp_tmr() and reschedules itself.
  191. *
  192. * @param arg unused argument
  193. */
  194. static void
  195. igmp_timer(void *arg)
  196. {
  197. LWIP_UNUSED_ARG(arg);
  198. LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n"));
  199. igmp_tmr();
  200. sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
  201. }
  202. #endif /* LWIP_IGMP */
  203. #if LWIP_DNS
  204. /**
  205. * Timer callback function that calls dns_tmr() and reschedules itself.
  206. *
  207. * @param arg unused argument
  208. */
  209. static void
  210. dns_timer(void *arg)
  211. {
  212. LWIP_UNUSED_ARG(arg);
  213. LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n"));
  214. dns_tmr();
  215. sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
  216. }
  217. #endif /* LWIP_DNS */
  218. /** Initialize this module */
  219. void sys_timeouts_init(void)
  220. {
  221. #if IP_REASSEMBLY
  222. sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
  223. #endif /* IP_REASSEMBLY */
  224. #if LWIP_ARP
  225. sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
  226. #endif /* LWIP_ARP */
  227. #if LWIP_DHCP
  228. DHCP_MAXRTX = 0;
  229. sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
  230. sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
  231. #endif /* LWIP_DHCP */
  232. #if LWIP_AUTOIP
  233. sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
  234. #endif /* LWIP_AUTOIP */
  235. #if LWIP_IGMP
  236. sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
  237. #endif /* LWIP_IGMP */
  238. #if LWIP_DNS
  239. sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
  240. #endif /* LWIP_DNS */
  241. #if LWIP_TCP
  242. sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
  243. // sys_timeout(TCP_TMR_INTERVAL, tcp_timer_coarse, NULL);
  244. #endif
  245. #if NO_SYS
  246. /* Initialise timestamp for sys_check_timeouts */
  247. timeouts_last_time = NOW();
  248. #endif
  249. }
  250. /**
  251. * Create a one-shot timer (aka timeout). Timeouts are processed in the
  252. * following cases:
  253. * - while waiting for a message using sys_timeouts_mbox_fetch()
  254. * - by calling sys_check_timeouts() (NO_SYS==1 only)
  255. *
  256. * @param msecs time in milliseconds after that the timer should expire
  257. * @param handler callback function to call when msecs have elapsed
  258. * @param arg argument to pass to the callback function
  259. */
  260. #if LWIP_DEBUG_TIMERNAMES
  261. void
  262. sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)
  263. #else /* LWIP_DEBUG_TIMERNAMES */
  264. void
  265. sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
  266. #endif /* LWIP_DEBUG_TIMERNAMES */
  267. {
  268. struct sys_timeo *timeout, *t;
  269. timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT);
  270. if (timeout == NULL) {
  271. LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL);
  272. return;
  273. }
  274. timeout->next = NULL;
  275. timeout->h = handler;
  276. timeout->arg = arg;
  277. timeout->time = msecs;
  278. #if LWIP_DEBUG_TIMERNAMES
  279. timeout->handler_name = handler_name;
  280. LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n",
  281. (void *)timeout, msecs, handler_name, (void *)arg));
  282. #endif /* LWIP_DEBUG_TIMERNAMES */
  283. if (next_timeout == NULL) {
  284. next_timeout = timeout;
  285. return;
  286. }
  287. if (next_timeout->time > msecs) {
  288. next_timeout->time -= msecs;
  289. timeout->next = next_timeout;
  290. next_timeout = timeout;
  291. } else {
  292. for(t = next_timeout; t != NULL; t = t->next) {
  293. timeout->time -= t->time;
  294. if (t->next == NULL || t->next->time > timeout->time) {
  295. if (t->next != NULL) {
  296. t->next->time -= timeout->time;
  297. }
  298. timeout->next = t->next;
  299. t->next = timeout;
  300. break;
  301. }
  302. }
  303. }
  304. }
  305. /**
  306. * Go through timeout list (for this task only) and remove the first matching
  307. * entry, even though the timeout has not triggered yet.
  308. *
  309. * @note This function only works as expected if there is only one timeout
  310. * calling 'handler' in the list of timeouts.
  311. *
  312. * @param handler callback function that would be called by the timeout
  313. * @param arg callback argument that would be passed to handler
  314. */
  315. void
  316. sys_untimeout(sys_timeout_handler handler, void *arg)
  317. {
  318. struct sys_timeo *prev_t, *t;
  319. if (next_timeout == NULL) {
  320. return;
  321. }
  322. for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
  323. if ((t->h == handler) && (t->arg == arg)) {
  324. /* We have a match */
  325. /* Unlink from previous in list */
  326. if (prev_t == NULL) {
  327. next_timeout = t->next;
  328. } else {
  329. prev_t->next = t->next;
  330. }
  331. /* If not the last one, add time of this one back to next */
  332. if (t->next != NULL) {
  333. t->next->time += t->time;
  334. }
  335. memp_free(MEMP_SYS_TIMEOUT, t);
  336. return;
  337. }
  338. }
  339. return;
  340. }
  341. #if NO_SYS
  342. extern uint8 timer2_ms_flag;
  343. /** Handle timeouts for NO_SYS==1 (i.e. without using
  344. * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout
  345. * handler functions when timeouts expire.
  346. *
  347. * Must be called periodically from your main loop.
  348. */
  349. void
  350. sys_check_timeouts(void)
  351. {
  352. struct sys_timeo *tmptimeout;
  353. u32_t diff;
  354. sys_timeout_handler handler;
  355. void *arg;
  356. int had_one;
  357. u32_t now;
  358. now = NOW();
  359. if (next_timeout) {
  360. /* this cares for wraparounds */
  361. if (timer2_ms_flag == 0) {
  362. diff = LWIP_U32_DIFF(now, timeouts_last_time)/((APB_CLK_FREQ>>4)/1000);
  363. } else {
  364. diff = LWIP_U32_DIFF(now, timeouts_last_time)/((APB_CLK_FREQ>>8)/1000);
  365. }
  366. do
  367. {
  368. had_one = 0;
  369. tmptimeout = next_timeout;
  370. if (tmptimeout->time <= diff) {
  371. /* timeout has expired */
  372. had_one = 1;
  373. timeouts_last_time = now;
  374. diff -= tmptimeout->time;
  375. next_timeout = tmptimeout->next;
  376. handler = tmptimeout->h;
  377. arg = tmptimeout->arg;
  378. #if LWIP_DEBUG_TIMERNAMES
  379. if (handler != NULL) {
  380. LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n",
  381. tmptimeout->handler_name, arg));
  382. }
  383. #endif /* LWIP_DEBUG_TIMERNAMES */
  384. memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
  385. if (handler != NULL) {
  386. handler(arg);
  387. }
  388. }
  389. /* repeat until all expired timers have been called */
  390. }while(had_one);
  391. }
  392. }
  393. /** Set back the timestamp of the last call to sys_check_timeouts()
  394. * This is necessary if sys_check_timeouts() hasn't been called for a long
  395. * time (e.g. while saving energy) to prevent all timer functions of that
  396. * period being called.
  397. */
  398. void
  399. sys_restart_timeouts(void)
  400. {
  401. timeouts_last_time = NOW();
  402. }
  403. #else /* NO_SYS */
  404. /**
  405. * Wait (forever) for a message to arrive in an mbox.
  406. * While waiting, timeouts are processed.
  407. *
  408. * @param mbox the mbox to fetch the message from
  409. * @param msg the place to store the message
  410. */
  411. void
  412. sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
  413. {
  414. u32_t time_needed;
  415. struct sys_timeo *tmptimeout;
  416. sys_timeout_handler handler;
  417. void *arg;
  418. again:
  419. if (!next_timeout) {
  420. time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
  421. } else {
  422. if (next_timeout->time > 0) {
  423. time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time);
  424. } else {
  425. time_needed = SYS_ARCH_TIMEOUT;
  426. }
  427. if (time_needed == SYS_ARCH_TIMEOUT) {
  428. /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
  429. could be fetched. We should now call the timeout handler and
  430. deallocate the memory allocated for the timeout. */
  431. tmptimeout = next_timeout;
  432. next_timeout = tmptimeout->next;
  433. handler = tmptimeout->h;
  434. arg = tmptimeout->arg;
  435. #if LWIP_DEBUG_TIMERNAMES
  436. if (handler != NULL) {
  437. LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n",
  438. tmptimeout->handler_name, arg));
  439. }
  440. #endif /* LWIP_DEBUG_TIMERNAMES */
  441. memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
  442. if (handler != NULL) {
  443. /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
  444. timeout handler function. */
  445. LOCK_TCPIP_CORE();
  446. handler(arg);
  447. UNLOCK_TCPIP_CORE();
  448. }
  449. LWIP_TCPIP_THREAD_ALIVE();
  450. /* We try again to fetch a message from the mbox. */
  451. goto again;
  452. } else {
  453. /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
  454. occured. The time variable is set to the number of
  455. milliseconds we waited for the message. */
  456. if (time_needed < next_timeout->time) {
  457. next_timeout->time -= time_needed;
  458. } else {
  459. next_timeout->time = 0;
  460. }
  461. }
  462. }
  463. }
  464. #endif /* NO_SYS */
  465. #else /* LWIP_TIMERS */
  466. /* Satisfy the TCP code which calls this function */
  467. void
  468. tcp_timer_needed(void)
  469. {
  470. }
  471. #endif /* LWIP_TIMERS */