timer.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517
  1. /*
  2. * Copyright (c) 2017-2019 Richard Braun.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. *
  18. * This implementation is based on "Hashed and Hierarchical Timing Wheels:
  19. * Efficient Data Structures for Implementing a Timer Facility" by George
  20. * Varghese and Tony Lauck. Specifically, it implements scheme 6.1.2.
  21. *
  22. */
  23. #include <assert.h>
  24. #include <stdalign.h>
  25. #include <stdbool.h>
  26. #include <stddef.h>
  27. #include <stdint.h>
  28. #include <kern/atomic.h>
  29. #include <kern/clock.h>
  30. #include <kern/error.h>
  31. #include <kern/init.h>
  32. #include <kern/hash.h>
  33. #include <kern/hlist.h>
  34. #include <kern/macros.h>
  35. #include <kern/panic.h>
  36. #include <kern/percpu.h>
  37. #include <kern/spinlock.h>
  38. #include <kern/thread.h>
  39. #include <kern/timer.h>
  40. #include <kern/work.h>
  41. #include <machine/boot.h>
  42. #include <machine/cpu.h>
  43. // Timer states.
  44. #define TIMER_TS_READY 1
  45. #define TIMER_TS_SCHEDULED 2
  46. #define TIMER_TS_RUNNING 3
  47. #define TIMER_TS_DONE 4
  48. // Timer flags.
  49. #define TIMER_TF_DETACHED 0x1
  50. #define TIMER_TF_INTR 0x2
  51. #define TIMER_TF_HIGH_PRIO 0x4
  52. #define TIMER_TF_CANCELED 0x8
  53. #define TIMER_INVALID_CPU ((unsigned int)-1)
  54. #define TIMER_HTABLE_SIZE 2048
  55. #if !ISP2(TIMER_HTABLE_SIZE)
  56. #error "hash table size must be a power of two"
  57. #endif
  58. #define TIMER_HTABLE_MASK (TIMER_HTABLE_SIZE - 1)
  59. struct timer_bucket
  60. {
  61. struct hlist timers;
  62. };
  63. /*
  64. * The hash table bucket matching the last time member has already been
  65. * processed, and the next periodic event resumes from the next bucket.
  66. *
  67. * Locking order: interrupts -> timer_cpu_data.
  68. */
  69. struct timer_cpu_data
  70. {
  71. unsigned int cpu;
  72. struct spinlock lock;
  73. uint64_t last_time;
  74. struct timer_bucket htable[TIMER_HTABLE_SIZE];
  75. };
  76. static struct timer_cpu_data timer_cpu_data __percpu;
  77. static struct timer_cpu_data*
  78. timer_cpu_data_acquire (cpu_flags_t *flags)
  79. {
  80. thread_preempt_disable ();
  81. _Auto cpu_data = cpu_local_ptr (timer_cpu_data);
  82. spinlock_lock_intr_save (&cpu_data->lock, flags);
  83. thread_preempt_enable_no_resched ();
  84. return (cpu_data);
  85. }
  86. static struct timer_cpu_data*
  87. timer_lock_cpu_data (struct timer *timer, cpu_flags_t *flags)
  88. {
  89. while (1)
  90. {
  91. uint32_t cpu = atomic_load_rlx (&timer->cpu);
  92. if (cpu == TIMER_INVALID_CPU)
  93. return (NULL);
  94. _Auto cpu_data = percpu_ptr (timer_cpu_data, cpu);
  95. spinlock_lock_intr_save (&cpu_data->lock, flags);
  96. if (cpu == atomic_load_rlx (&timer->cpu))
  97. return (cpu_data);
  98. spinlock_unlock_intr_restore (&cpu_data->lock, *flags);
  99. }
  100. }
  101. static void
  102. timer_unlock_cpu_data (struct timer_cpu_data *cpu_data, cpu_flags_t flags)
  103. {
  104. spinlock_unlock_intr_restore (&cpu_data->lock, flags);
  105. }
  106. // Timer state functions.
  107. static bool
  108. timer_ready (const struct timer *timer)
  109. {
  110. return (timer->state == TIMER_TS_READY);
  111. }
  112. static void
  113. timer_set_ready (struct timer *timer)
  114. {
  115. timer->state = TIMER_TS_READY;
  116. }
  117. static bool
  118. timer_scheduled (const struct timer *timer)
  119. {
  120. return (timer->state == TIMER_TS_SCHEDULED);
  121. }
  122. static void
  123. timer_set_scheduled (struct timer *timer, uint32_t cpu)
  124. {
  125. atomic_store (&timer->cpu, cpu, ATOMIC_RELAXED);
  126. timer->state = TIMER_TS_SCHEDULED;
  127. }
  128. static bool
  129. timer_running (const struct timer *timer)
  130. {
  131. return (timer->state == TIMER_TS_RUNNING);
  132. }
  133. static void
  134. timer_set_running (struct timer *timer)
  135. {
  136. timer->state = TIMER_TS_RUNNING;
  137. }
  138. static bool
  139. timer_done (const struct timer *timer)
  140. {
  141. return (timer->state == TIMER_TS_DONE);
  142. }
  143. static void
  144. timer_set_done (struct timer *timer)
  145. {
  146. timer->state = TIMER_TS_DONE;
  147. }
  148. // Timer flags functions.
  149. static bool
  150. timer_detached (const struct timer *timer)
  151. {
  152. return ((timer->flags & TIMER_TF_DETACHED) != 0);
  153. }
  154. static void
  155. timer_set_detached (struct timer *timer)
  156. {
  157. timer->flags |= TIMER_TF_DETACHED;
  158. }
  159. static bool
  160. timer_is_intr (const struct timer *timer)
  161. {
  162. return ((timer->flags & TIMER_TF_INTR) != 0);
  163. }
  164. static void
  165. timer_set_intr (struct timer *timer)
  166. {
  167. timer->flags |= TIMER_TF_INTR;
  168. }
  169. static bool
  170. timer_is_high_prio (const struct timer *timer)
  171. {
  172. return ((timer->flags & TIMER_TF_HIGH_PRIO) != 0);
  173. }
  174. static void
  175. timer_set_high_prio (struct timer *timer)
  176. {
  177. timer->flags |= TIMER_TF_HIGH_PRIO;
  178. }
  179. static bool
  180. timer_canceled (const struct timer *timer)
  181. {
  182. return ((timer->flags & TIMER_TF_CANCELED) != 0);
  183. }
  184. static void
  185. timer_set_canceled (struct timer *timer)
  186. {
  187. timer->flags |= TIMER_TF_CANCELED;
  188. }
  189. static void
  190. timer_set_time (struct timer *timer, uint64_t ticks)
  191. {
  192. timer->ticks = ticks;
  193. }
  194. static bool
  195. timer_occurred (const struct timer *timer, uint64_t ref)
  196. {
  197. return (clock_time_occurred (timer_get_time (timer), ref));
  198. }
  199. static uint32_t
  200. timer_hash (uint64_t ticks)
  201. {
  202. return (hash_u64 (ticks));
  203. }
  204. static void
  205. timer_run (struct timer *timer)
  206. {
  207. assert (timer_running (timer));
  208. timer->fn (timer);
  209. if (timer_detached (timer))
  210. return;
  211. cpu_flags_t cpu_flags;
  212. _Auto cpu_data = timer_lock_cpu_data (timer, &cpu_flags);
  213. /*
  214. * The timer handler may have :
  215. * - rescheduled itself
  216. * - been canceled
  217. * - none of the above
  218. *
  219. * If the handler didn't call a timer function, or if the timer was
  220. * canceled, set the state to done and wake up the joiner, if any.
  221. *
  222. * If the handler rescheduled the timer, nothing must be done. This
  223. * is also true if the timer was canceled after being rescheduled by
  224. * the handler (in this case, cancellation won't wait for a signal).
  225. * These cases can be identified by checking if the timer state is
  226. * different from running.
  227. */
  228. if (timer_running (timer))
  229. {
  230. timer_set_done (timer);
  231. thread_wakeup (timer->joiner);
  232. }
  233. timer_unlock_cpu_data (cpu_data, cpu_flags);
  234. }
  235. static void
  236. timer_run_work (struct work *work)
  237. {
  238. timer_run (structof (work, struct timer, work));
  239. }
  240. static void
  241. timer_process (struct timer *timer)
  242. {
  243. if (timer_is_intr (timer))
  244. {
  245. timer_run (timer);
  246. return;
  247. }
  248. int work_flags = timer_is_high_prio (timer) ? WORK_HIGHPRIO : 0;
  249. work_init (&timer->work, timer_run_work);
  250. work_schedule (&timer->work, work_flags);
  251. }
  252. static void
  253. timer_bucket_init (struct timer_bucket *bucket)
  254. {
  255. hlist_init (&bucket->timers);
  256. }
  257. static void
  258. timer_bucket_add (struct timer_bucket *bucket, struct timer *timer)
  259. {
  260. hlist_insert_head (&bucket->timers, &timer->node);
  261. }
  262. static void
  263. timer_bucket_remove (struct timer_bucket *bucket __unused, struct timer *timer)
  264. {
  265. hlist_remove (&timer->node);
  266. }
  267. static void
  268. timer_cpu_data_init (struct timer_cpu_data *cpu_data, unsigned int cpu)
  269. {
  270. cpu_data->cpu = cpu;
  271. spinlock_init (&cpu_data->lock);
  272. // See periodic event handling.
  273. cpu_data->last_time = clock_get_time () - 1;
  274. for (size_t i = 0; i < ARRAY_SIZE (cpu_data->htable); i++)
  275. timer_bucket_init (&cpu_data->htable[i]);
  276. }
  277. static struct timer_bucket*
  278. timer_cpu_data_get_bucket (struct timer_cpu_data *cpu_data, uint64_t ticks)
  279. {
  280. uint32_t index = timer_hash (ticks) & TIMER_HTABLE_MASK;
  281. assert (index < ARRAY_SIZE (cpu_data->htable));
  282. return (&cpu_data->htable[index]);
  283. }
  284. static void
  285. timer_cpu_data_add (struct timer_cpu_data *cpu_data, struct timer *timer)
  286. {
  287. assert (timer_ready (timer));
  288. _Auto bucket = timer_cpu_data_get_bucket (cpu_data, timer->ticks);
  289. timer_bucket_add (bucket, timer);
  290. }
  291. static void
  292. timer_cpu_data_remove (struct timer_cpu_data *cpu_data, struct timer *timer)
  293. {
  294. assert (timer_scheduled (timer));
  295. _Auto bucket = timer_cpu_data_get_bucket (cpu_data, timer->ticks);
  296. timer_bucket_remove (bucket, timer);
  297. }
  298. static void
  299. timer_bucket_filter (struct timer_bucket *bucket, uint64_t now,
  300. struct hlist *timers)
  301. {
  302. struct timer *timer, *tmp;
  303. hlist_for_each_entry_safe (&bucket->timers, timer, tmp, node)
  304. {
  305. assert (timer_scheduled (timer));
  306. if (!timer_occurred (timer, now))
  307. continue;
  308. hlist_remove (&timer->node);
  309. timer_set_running (timer);
  310. hlist_insert_head (timers, &timer->node);
  311. }
  312. }
  313. static int __init
  314. timer_bootstrap (void)
  315. {
  316. timer_cpu_data_init (cpu_local_ptr (timer_cpu_data), 0);
  317. return (0);
  318. }
  319. INIT_OP_DEFINE (timer_bootstrap,
  320. INIT_OP_DEP (cpu_setup, true),
  321. INIT_OP_DEP (spinlock_setup, true));
  322. static int __init
  323. timer_setup (void)
  324. {
  325. for (uint32_t cpu = 1; cpu < cpu_count (); cpu++)
  326. timer_cpu_data_init (percpu_ptr (timer_cpu_data, cpu), cpu);
  327. return (0);
  328. }
  329. INIT_OP_DEFINE (timer_setup,
  330. INIT_OP_DEP (cpu_mp_probe, true),
  331. INIT_OP_DEP (spinlock_setup, true));
  332. void
  333. timer_init (struct timer *timer, timer_fn_t fn, int flags)
  334. {
  335. timer->fn = fn;
  336. timer->cpu = TIMER_INVALID_CPU;
  337. timer->state = TIMER_TS_READY;
  338. timer->flags = 0;
  339. timer->joiner = NULL;
  340. if (flags & TIMER_DETACHED)
  341. timer_set_detached (timer);
  342. if (flags & TIMER_INTR)
  343. timer_set_intr (timer);
  344. else if (flags & TIMER_HIGH_PRIO)
  345. timer_set_high_prio (timer);
  346. }
  347. void
  348. timer_schedule (struct timer *timer, uint64_t ticks)
  349. {
  350. cpu_flags_t cpu_flags;
  351. _Auto cpu_data = timer_lock_cpu_data (timer, &cpu_flags);
  352. if (! cpu_data)
  353. cpu_data = timer_cpu_data_acquire (&cpu_flags);
  354. else
  355. {
  356. if (timer_canceled (timer))
  357. goto out;
  358. /*
  359. * If called from the handler, the timer is running. If rescheduled
  360. * after completion, it's done.
  361. */
  362. if (timer_running (timer) || timer_done (timer))
  363. timer_set_ready (timer);
  364. }
  365. timer_set_time (timer, ticks);
  366. if (timer_occurred (timer, cpu_data->last_time))
  367. ticks = cpu_data->last_time + 1;
  368. timer_cpu_data_add (cpu_data, timer);
  369. timer_set_scheduled (timer, cpu_data->cpu);
  370. out:
  371. timer_unlock_cpu_data (cpu_data, cpu_flags);
  372. }
  373. void
  374. timer_cancel (struct timer *timer)
  375. {
  376. assert (!timer_detached (timer));
  377. cpu_flags_t cpu_flags;
  378. _Auto cpu_data = timer_lock_cpu_data (timer, &cpu_flags);
  379. assert (!timer->joiner);
  380. timer_set_canceled (timer);
  381. if (timer_scheduled (timer))
  382. timer_cpu_data_remove (cpu_data, timer);
  383. else
  384. {
  385. timer->joiner = thread_self ();
  386. while (!timer_done (timer))
  387. {
  388. if (timer_is_intr (timer))
  389. {
  390. timer_unlock_cpu_data (cpu_data, cpu_flags);
  391. cpu_pause ();
  392. cpu_data = timer_lock_cpu_data (timer, &cpu_flags);
  393. }
  394. else
  395. thread_sleep (&cpu_data->lock, timer, "tmr_cncl");
  396. }
  397. assert (timer_done (timer));
  398. timer->joiner = NULL;
  399. }
  400. timer_set_ready (timer);
  401. timer_unlock_cpu_data (cpu_data, cpu_flags);
  402. }
  403. void
  404. timer_report_periodic_event (void)
  405. {
  406. assert (thread_check_intr_context ());
  407. uint64_t now = clock_get_time ();
  408. struct hlist timers;
  409. hlist_init (&timers);
  410. _Auto cpu_data = cpu_local_ptr (timer_cpu_data);
  411. spinlock_lock (&cpu_data->lock);
  412. for (uint64_t ticks = cpu_data->last_time + 1;
  413. clock_time_occurred (ticks, now);
  414. ticks++)
  415. {
  416. _Auto bucket = timer_cpu_data_get_bucket (cpu_data, ticks);
  417. timer_bucket_filter (bucket, now, &timers);
  418. }
  419. cpu_data->last_time = now;
  420. spinlock_unlock (&cpu_data->lock);
  421. while (!hlist_empty (&timers))
  422. {
  423. _Auto timer = hlist_first_entry (&timers, struct timer, node);
  424. hlist_remove (&timer->node);
  425. timer_process (timer);
  426. }
  427. }