timeouts.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  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/timeouts.h"
  42. #include "lwip/priv/tcp_priv.h"
  43. #include "lwip/def.h"
  44. #include "lwip/memp.h"
  45. #include "lwip/priv/tcpip_priv.h"
  46. #include "lwip/ip4_frag.h"
  47. #include "lwip/etharp.h"
  48. #include "lwip/dhcp.h"
  49. #include "lwip/autoip.h"
  50. #include "lwip/igmp.h"
  51. #include "lwip/dns.h"
  52. #include "lwip/nd6.h"
  53. #include "lwip/ip6_frag.h"
  54. #include "lwip/mld6.h"
  55. #include "lwip/sys.h"
  56. #include "lwip/pbuf.h"
  57. #if LWIP_DEBUG_TIMERNAMES
  58. #define HANDLER(x) x, #x
  59. #else /* LWIP_DEBUG_TIMERNAMES */
  60. #define HANDLER(x) x
  61. #endif /* LWIP_DEBUG_TIMERNAMES */
  62. /** This array contains all stack-internal cyclic timers. To get the number of
  63. * timers, use LWIP_ARRAYSIZE() */
  64. const struct lwip_cyclic_timer lwip_cyclic_timers[] = {
  65. #if LWIP_TCP
  66. /* The TCP timer is a special case: it does not have to run always and
  67. is triggered to start from TCP using tcp_timer_needed() */
  68. {TCP_TMR_INTERVAL, HANDLER(tcp_tmr)},
  69. #endif /* LWIP_TCP */
  70. #if LWIP_IPV4
  71. #if IP_REASSEMBLY
  72. {IP_TMR_INTERVAL, HANDLER(ip_reass_tmr)},
  73. #endif /* IP_REASSEMBLY */
  74. #if LWIP_ARP
  75. {ARP_TMR_INTERVAL, HANDLER(etharp_tmr)},
  76. #endif /* LWIP_ARP */
  77. #if LWIP_DHCP
  78. {DHCP_COARSE_TIMER_MSECS, HANDLER(dhcp_coarse_tmr)},
  79. {DHCP_FINE_TIMER_MSECS, HANDLER(dhcp_fine_tmr)},
  80. #endif /* LWIP_DHCP */
  81. #if LWIP_AUTOIP
  82. {AUTOIP_TMR_INTERVAL, HANDLER(autoip_tmr)},
  83. #endif /* LWIP_AUTOIP */
  84. #if LWIP_IGMP
  85. {IGMP_TMR_INTERVAL, HANDLER(igmp_tmr)},
  86. #endif /* LWIP_IGMP */
  87. #endif /* LWIP_IPV4 */
  88. #if LWIP_DNS
  89. {DNS_TMR_INTERVAL, HANDLER(dns_tmr)},
  90. #endif /* LWIP_DNS */
  91. #if LWIP_IPV6
  92. {ND6_TMR_INTERVAL, HANDLER(nd6_tmr)},
  93. #if LWIP_IPV6_REASS
  94. {IP6_REASS_TMR_INTERVAL, HANDLER(ip6_reass_tmr)},
  95. #endif /* LWIP_IPV6_REASS */
  96. #if LWIP_IPV6_MLD
  97. {MLD6_TMR_INTERVAL, HANDLER(mld6_tmr)},
  98. #endif /* LWIP_IPV6_MLD */
  99. #endif /* LWIP_IPV6 */
  100. };
  101. #if LWIP_TIMERS && !LWIP_TIMERS_CUSTOM
  102. /** The one and only timeout list */
  103. static struct sys_timeo *next_timeout;
  104. static u32_t timeouts_last_time;
  105. #if LWIP_TCP
  106. /** global variable that shows if the tcp timer is currently scheduled or not */
  107. static int tcpip_tcp_timer_active;
  108. /**
  109. * Timer callback function that calls tcp_tmr() and reschedules itself.
  110. *
  111. * @param arg unused argument
  112. */
  113. static void
  114. tcpip_tcp_timer(void *arg)
  115. {
  116. LWIP_UNUSED_ARG(arg);
  117. /* call TCP timer handler */
  118. tcp_tmr();
  119. /* timer still needed? */
  120. if (tcp_active_pcbs || tcp_tw_pcbs) {
  121. /* restart timer */
  122. sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
  123. } else {
  124. /* disable timer */
  125. tcpip_tcp_timer_active = 0;
  126. }
  127. }
  128. /**
  129. * Called from TCP_REG when registering a new PCB:
  130. * the reason is to have the TCP timer only running when
  131. * there are active (or time-wait) PCBs.
  132. */
  133. void
  134. tcp_timer_needed(void)
  135. {
  136. /* timer is off but needed again? */
  137. if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
  138. /* enable and start timer */
  139. tcpip_tcp_timer_active = 1;
  140. sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
  141. }
  142. }
  143. #endif /* LWIP_TCP */
  144. /**
  145. * Timer callback function that calls mld6_tmr() and reschedules itself.
  146. *
  147. * @param arg unused argument
  148. */
  149. static void
  150. cyclic_timer(void *arg)
  151. {
  152. const struct lwip_cyclic_timer* cyclic = (const struct lwip_cyclic_timer*)arg;
  153. #if LWIP_DEBUG_TIMERNAMES
  154. LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: %s()\n", cyclic->handler_name));
  155. #endif
  156. cyclic->handler();
  157. sys_timeout(cyclic->interval_ms, cyclic_timer, arg);
  158. }
  159. /** Initialize this module */
  160. void sys_timeouts_init(void)
  161. {
  162. size_t i;
  163. /* tcp_tmr() at index 0 is started on demand */
  164. for (i = 1; i < LWIP_ARRAYSIZE(lwip_cyclic_timers); i++) {
  165. /* we have to cast via size_t to get rid of const warning
  166. (this is OK as cyclic_timer() casts back to const* */
  167. sys_timeout(lwip_cyclic_timers[i].interval_ms, cyclic_timer, LWIP_CONST_CAST(void*, &lwip_cyclic_timers[i]));
  168. }
  169. /* Initialise timestamp for sys_check_timeouts */
  170. timeouts_last_time = sys_now();
  171. }
  172. /**
  173. * Create a one-shot timer (aka timeout). Timeouts are processed in the
  174. * following cases:
  175. * - while waiting for a message using sys_timeouts_mbox_fetch()
  176. * - by calling sys_check_timeouts() (NO_SYS==1 only)
  177. *
  178. * @param msecs time in milliseconds after that the timer should expire
  179. * @param handler callback function to call when msecs have elapsed
  180. * @param arg argument to pass to the callback function
  181. */
  182. #if LWIP_DEBUG_TIMERNAMES
  183. void
  184. sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)
  185. #else /* LWIP_DEBUG_TIMERNAMES */
  186. void
  187. sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
  188. #endif /* LWIP_DEBUG_TIMERNAMES */
  189. {
  190. struct sys_timeo *timeout, *t;
  191. u32_t now, diff;
  192. timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT);
  193. if (timeout == NULL) {
  194. LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL);
  195. return;
  196. }
  197. now = sys_now();
  198. if (next_timeout == NULL) {
  199. diff = 0;
  200. timeouts_last_time = now;
  201. } else {
  202. diff = now - timeouts_last_time;
  203. }
  204. timeout->next = NULL;
  205. timeout->h = handler;
  206. timeout->arg = arg;
  207. timeout->time = msecs + diff;
  208. #if LWIP_DEBUG_TIMERNAMES
  209. timeout->handler_name = handler_name;
  210. LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n",
  211. (void *)timeout, msecs, handler_name, (void *)arg));
  212. #endif /* LWIP_DEBUG_TIMERNAMES */
  213. if (next_timeout == NULL) {
  214. next_timeout = timeout;
  215. return;
  216. }
  217. if (next_timeout->time > msecs) {
  218. next_timeout->time -= msecs;
  219. timeout->next = next_timeout;
  220. next_timeout = timeout;
  221. } else {
  222. for (t = next_timeout; t != NULL; t = t->next) {
  223. timeout->time -= t->time;
  224. if (t->next == NULL || t->next->time > timeout->time) {
  225. if (t->next != NULL) {
  226. t->next->time -= timeout->time;
  227. } else if (timeout->time > msecs) {
  228. /* If this is the case, 'timeouts_last_time' and 'now' differs too much.
  229. This can be due to sys_check_timeouts() not being called at the right
  230. times, but also when stopping in a breakpoint. Anyway, let's assume
  231. this is not wanted, so add the first timer's time instead of 'diff' */
  232. timeout->time = msecs + next_timeout->time;
  233. }
  234. timeout->next = t->next;
  235. t->next = timeout;
  236. break;
  237. }
  238. }
  239. }
  240. }
  241. /**
  242. * Go through timeout list (for this task only) and remove the first matching
  243. * entry (subsequent entries remain untouched), even though the timeout has not
  244. * triggered yet.
  245. *
  246. * @param handler callback function that would be called by the timeout
  247. * @param arg callback argument that would be passed to handler
  248. */
  249. void
  250. sys_untimeout(sys_timeout_handler handler, void *arg)
  251. {
  252. struct sys_timeo *prev_t, *t;
  253. if (next_timeout == NULL) {
  254. return;
  255. }
  256. for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
  257. if ((t->h == handler) && (t->arg == arg)) {
  258. /* We have a match */
  259. /* Unlink from previous in list */
  260. if (prev_t == NULL) {
  261. next_timeout = t->next;
  262. } else {
  263. prev_t->next = t->next;
  264. }
  265. /* If not the last one, add time of this one back to next */
  266. if (t->next != NULL) {
  267. t->next->time += t->time;
  268. }
  269. memp_free(MEMP_SYS_TIMEOUT, t);
  270. return;
  271. }
  272. }
  273. return;
  274. }
  275. /**
  276. * @ingroup lwip_nosys
  277. * Handle timeouts for NO_SYS==1 (i.e. without using
  278. * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout
  279. * handler functions when timeouts expire.
  280. *
  281. * Must be called periodically from your main loop.
  282. */
  283. #if !NO_SYS && !defined __DOXYGEN__
  284. static
  285. #endif /* !NO_SYS */
  286. void
  287. sys_check_timeouts(void)
  288. {
  289. if (next_timeout) {
  290. struct sys_timeo *tmptimeout;
  291. u32_t diff;
  292. sys_timeout_handler handler;
  293. void *arg;
  294. u8_t had_one;
  295. u32_t now;
  296. now = sys_now();
  297. /* this cares for wraparounds */
  298. diff = now - timeouts_last_time;
  299. do {
  300. PBUF_CHECK_FREE_OOSEQ();
  301. had_one = 0;
  302. tmptimeout = next_timeout;
  303. if (tmptimeout && (tmptimeout->time <= diff)) {
  304. /* timeout has expired */
  305. had_one = 1;
  306. timeouts_last_time += tmptimeout->time;
  307. diff -= tmptimeout->time;
  308. next_timeout = tmptimeout->next;
  309. handler = tmptimeout->h;
  310. arg = tmptimeout->arg;
  311. #if LWIP_DEBUG_TIMERNAMES
  312. if (handler != NULL) {
  313. LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n",
  314. tmptimeout->handler_name, arg));
  315. }
  316. #endif /* LWIP_DEBUG_TIMERNAMES */
  317. memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
  318. if (handler != NULL) {
  319. #if !NO_SYS
  320. /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
  321. timeout handler function. */
  322. LOCK_TCPIP_CORE();
  323. #endif /* !NO_SYS */
  324. handler(arg);
  325. #if !NO_SYS
  326. UNLOCK_TCPIP_CORE();
  327. #endif /* !NO_SYS */
  328. }
  329. LWIP_TCPIP_THREAD_ALIVE();
  330. }
  331. /* repeat until all expired timers have been called */
  332. } while (had_one);
  333. }
  334. }
  335. /** Set back the timestamp of the last call to sys_check_timeouts()
  336. * This is necessary if sys_check_timeouts() hasn't been called for a long
  337. * time (e.g. while saving energy) to prevent all timer functions of that
  338. * period being called.
  339. */
  340. void
  341. sys_restart_timeouts(void)
  342. {
  343. timeouts_last_time = sys_now();
  344. }
  345. /** Return the time left before the next timeout is due. If no timeouts are
  346. * enqueued, returns 0xffffffff
  347. */
  348. #if !NO_SYS
  349. static
  350. #endif /* !NO_SYS */
  351. u32_t
  352. sys_timeouts_sleeptime(void)
  353. {
  354. u32_t diff;
  355. if (next_timeout == NULL) {
  356. return 0xffffffff;
  357. }
  358. diff = sys_now() - timeouts_last_time;
  359. if (diff > next_timeout->time) {
  360. return 0;
  361. } else {
  362. return next_timeout->time - diff;
  363. }
  364. }
  365. #if !NO_SYS
  366. /**
  367. * Wait (forever) for a message to arrive in an mbox.
  368. * While waiting, timeouts are processed.
  369. *
  370. * @param mbox the mbox to fetch the message from
  371. * @param msg the place to store the message
  372. */
  373. void
  374. sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
  375. {
  376. u32_t sleeptime;
  377. again:
  378. if (!next_timeout) {
  379. sys_arch_mbox_fetch(mbox, msg, 0);
  380. return;
  381. }
  382. sleeptime = sys_timeouts_sleeptime();
  383. if (sleeptime == 0 || sys_arch_mbox_fetch(mbox, msg, sleeptime) == SYS_ARCH_TIMEOUT) {
  384. /* If a SYS_ARCH_TIMEOUT value is returned, a timeout occurred
  385. before a message could be fetched. */
  386. sys_check_timeouts();
  387. /* We try again to fetch a message from the mbox. */
  388. goto again;
  389. }
  390. }
  391. #endif /* NO_SYS */
  392. #else /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */
  393. /* Satisfy the TCP code which calls this function */
  394. void
  395. tcp_timer_needed(void)
  396. {
  397. }
  398. #endif /* LWIP_TIMERS && !LWIP_TIMERS_CUSTOM */