PageRenderTime 54ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/kernel/clock.cpp

https://gitlab.com/PedroFalcato/sortix
C++ | 431 lines | 288 code | 66 blank | 77 comment | 47 complexity | 45d9bc06df7fa1c4ced61efe9a33aedd MD5 | raw file
  1. /*
  2. * Copyright (c) 2013, 2016 Jonas 'Sortie' Termansen.
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. *
  16. * clock.cpp
  17. * Clock and timer facility.
  18. */
  19. #include <assert.h>
  20. #include <timespec.h>
  21. #include <sortix/kernel/clock.h>
  22. #include <sortix/kernel/interrupt.h>
  23. #include <sortix/kernel/kernel.h>
  24. #include <sortix/kernel/kthread.h>
  25. #include <sortix/kernel/signal.h>
  26. #include <sortix/kernel/timer.h>
  27. #include <sortix/kernel/worker.h>
  28. namespace Sortix {
  29. Clock::Clock()
  30. {
  31. delay_timer = NULL;
  32. absolute_timer = NULL;
  33. current_time = timespec_nul();
  34. current_advancement = timespec_nul();
  35. resolution = timespec_nul();
  36. clock_mutex = KTHREAD_MUTEX_INITIALIZER;
  37. clock_callable_from_interrupt = false;
  38. we_disabled_interrupts = false;
  39. }
  40. Clock::~Clock()
  41. {
  42. // TODO: The best solution would probably be to cancel everything that is
  43. // waiting on us, but that is a bit dangerous since things have to be
  44. // notified carefully that they should not use stale pointers to this
  45. // clock. This is a bunch of work and since the clock is being
  46. // destroyed, you could argue that you shouldn't be using a clock
  47. // whose lifetime you don't control. Therefore assume that all users
  48. // of the clock has stopped using it.
  49. assert(!absolute_timer && !delay_timer);
  50. }
  51. // This clock and timer facility is designed to work even from interrupt
  52. // handlers. For instance, this is needed by the uptime clock that is
  53. // incremented every timer interrupt. If we don't need interrupt handler safety,
  54. // we simply fall back on regular mutual exclusion.
  55. void Clock::SetCallableFromInterrupts(bool callable_from_interrupts)
  56. {
  57. clock_callable_from_interrupt = callable_from_interrupts;
  58. }
  59. void Clock::LockClock()
  60. {
  61. if ( clock_callable_from_interrupt )
  62. {
  63. if ( (we_disabled_interrupts = Interrupt::IsEnabled()) )
  64. Interrupt::Disable();
  65. }
  66. else
  67. kthread_mutex_lock(&clock_mutex);
  68. }
  69. void Clock::UnlockClock()
  70. {
  71. if ( clock_callable_from_interrupt )
  72. {
  73. if ( we_disabled_interrupts )
  74. Interrupt::Enable();
  75. }
  76. else
  77. kthread_mutex_unlock(&clock_mutex);
  78. }
  79. void Clock::Set(struct timespec* now, struct timespec* res)
  80. {
  81. LockClock();
  82. if ( now )
  83. current_time = *now;
  84. if ( res )
  85. resolution = *res;
  86. TriggerAbsolute();
  87. UnlockClock();
  88. }
  89. void Clock::Get(struct timespec* now, struct timespec* res)
  90. {
  91. LockClock();
  92. if ( now )
  93. *now = current_time;
  94. if ( res )
  95. *res = resolution;
  96. UnlockClock();
  97. }
  98. // We maintain two queues of timers; one for timers that sleep for a duration
  99. // and one that that sleeps until a certain point in time. This lets us deal
  100. // nicely with non-monotonic clocks and simplifies the code. The absolute timers
  101. // queue is simply sorted after their wake-up time, while the delay timers queue
  102. // is sorted after their delays, where each node stores the delay between it and
  103. // its previous node (if any, otherwise just the actual time left of the timer).
  104. // This data structure allows constant time detection of whether a timer should
  105. // be fired and the double-linked queue allow constant-time cancellation - this
  106. // is at the expense of linear time insertion, but it is kinda okay since timers
  107. // that are soon will always be at the start (and hence quick to insert), while
  108. // timers in the far future will be last and the calling thread probably
  109. // wouldn't mind a little delay.
  110. // TODO: If locking the clock means disabling interrupts, and a large numbers of
  111. // timers are attached to this clock, then inserting a timer becomes
  112. // expensive as the CPU locks up for a moment. Perhaps this is not as bad
  113. // as it theoretically could be?
  114. void Clock::RegisterAbsolute(Timer* timer) // Lock acquired.
  115. {
  116. assert(!(timer->flags & TIMER_ACTIVE));
  117. timer->flags |= TIMER_ACTIVE;
  118. Timer* before = NULL;
  119. for ( Timer* iter = absolute_timer; iter; iter = iter->next_timer )
  120. {
  121. if ( timespec_lt(timer->value.it_value, iter->value.it_value) )
  122. before = iter;
  123. }
  124. timer->prev_timer = before;
  125. timer->next_timer = before ? before->next_timer : absolute_timer;
  126. if ( timer->next_timer ) timer->next_timer->prev_timer = timer;
  127. (before ? before->next_timer : absolute_timer) = timer;
  128. }
  129. void Clock::RegisterDelay(Timer* timer) // Lock acquired.
  130. {
  131. assert(!(timer->flags & TIMER_ACTIVE));
  132. timer->flags |= TIMER_ACTIVE;
  133. Timer* before = NULL;
  134. for ( Timer* iter = delay_timer; iter; iter = iter->next_timer )
  135. {
  136. if ( timespec_lt(timer->value.it_value, iter->value.it_value) )
  137. break;
  138. timer->value.it_value = timespec_sub(timer->value.it_value, iter->value.it_value);
  139. before = iter;
  140. }
  141. timer->prev_timer = before;
  142. timer->next_timer = before ? before->next_timer : delay_timer;
  143. if ( timer->next_timer )
  144. timer->next_timer->prev_timer = timer;
  145. if ( before )
  146. before->next_timer = timer;
  147. else
  148. delay_timer = timer;
  149. if ( timer->next_timer )
  150. timer->next_timer->value.it_value =
  151. timespec_sub(timer->next_timer->value.it_value, timer->value.it_value);
  152. }
  153. void Clock::Register(Timer* timer)
  154. {
  155. if ( timer->flags & TIMER_ABSOLUTE )
  156. RegisterAbsolute(timer);
  157. else
  158. RegisterDelay(timer);
  159. }
  160. void Clock::UnlinkAbsolute(Timer* timer) // Lock acquired.
  161. {
  162. assert(timer->flags & TIMER_ACTIVE);
  163. (timer->prev_timer ? timer->prev_timer->next_timer : absolute_timer) = timer->next_timer;
  164. if ( timer->next_timer ) timer->next_timer->prev_timer = timer->prev_timer;
  165. timer->prev_timer = timer->next_timer = NULL;
  166. timer->flags &= ~TIMER_ACTIVE;
  167. }
  168. void Clock::UnlinkDelay(Timer* timer) // Lock acquired.
  169. {
  170. assert(timer->flags & TIMER_ACTIVE);
  171. (timer->prev_timer ? timer->prev_timer->next_timer : delay_timer) = timer->next_timer;
  172. if ( timer->next_timer ) timer->next_timer->prev_timer = timer->prev_timer;
  173. if ( timer->next_timer ) timer->next_timer->value.it_value = timespec_add(timer->next_timer->value.it_value, timer->value.it_value);
  174. timer->prev_timer = timer->next_timer = NULL;
  175. timer->flags &= ~TIMER_ACTIVE;
  176. }
  177. void Clock::Unlink(Timer* timer) // Lock acquired.
  178. {
  179. if ( timer->flags & TIMER_ACTIVE )
  180. {
  181. if ( timer->flags & TIMER_ABSOLUTE )
  182. UnlinkAbsolute(timer);
  183. else
  184. UnlinkDelay(timer);
  185. }
  186. }
  187. void Clock::Cancel(Timer* timer)
  188. {
  189. LockClock();
  190. Unlink(timer);
  191. while ( timer->flags & TIMER_FIRING )
  192. {
  193. UnlockClock();
  194. // TODO: This busy-loop is rather inefficient. We could set up some
  195. // condition variable and wait on it. However, if the lock is
  196. // turning interrupts off, then there is no mutex we can use.
  197. kthread_yield();
  198. LockClock();
  199. }
  200. UnlockClock();
  201. }
  202. // TODO: We need some method for threads to sleep for real but still be
  203. // interrupted by signals.
  204. struct timespec Clock::SleepDelay(struct timespec duration)
  205. {
  206. struct timespec start_advancement;
  207. struct timespec elapsed = timespec_nul();
  208. bool start_advancement_set = false;
  209. while ( timespec_lt(elapsed, duration) )
  210. {
  211. if ( start_advancement_set )
  212. {
  213. if ( Signal::IsPending() )
  214. return duration;
  215. kthread_yield();
  216. }
  217. LockClock();
  218. if ( !start_advancement_set )
  219. {
  220. start_advancement = current_advancement;
  221. start_advancement_set = true;
  222. }
  223. elapsed = timespec_sub(current_advancement, start_advancement);
  224. UnlockClock();
  225. }
  226. return timespec_nul();
  227. }
  228. // TODO: We need some method for threads to sleep for real but still be
  229. // interrupted by signals.
  230. struct timespec Clock::SleepUntil(struct timespec expiration)
  231. {
  232. while ( true )
  233. {
  234. LockClock();
  235. struct timespec now = current_time;
  236. UnlockClock();
  237. if ( timespec_le(expiration, now) )
  238. break;
  239. if ( Signal::IsPending() )
  240. return timespec_sub(expiration, now);
  241. kthread_yield();
  242. }
  243. return timespec_nul();
  244. }
  245. void Clock::Advance(struct timespec duration)
  246. {
  247. LockClock();
  248. current_time = timespec_add(current_time, duration);
  249. current_advancement = timespec_add(current_advancement, duration);
  250. TriggerDelay(duration);
  251. TriggerAbsolute();
  252. UnlockClock();
  253. }
  254. // Fire timers that wait for a certain amount of time.
  255. void Clock::TriggerDelay(struct timespec unaccounted) // Lock acquired.
  256. {
  257. while ( Timer* timer = delay_timer )
  258. {
  259. if ( timespec_lt(unaccounted, timer->value.it_value) )
  260. {
  261. timer->value.it_value = timespec_sub(timer->value.it_value, unaccounted);
  262. break;
  263. }
  264. unaccounted = timespec_sub(unaccounted, timer->value.it_value);
  265. timer->value.it_value = timespec_nul();
  266. if ( (delay_timer = delay_timer->next_timer) )
  267. delay_timer->prev_timer = NULL;
  268. FireTimer(timer);
  269. }
  270. }
  271. // Fire timers that wait until a certain point in time.
  272. void Clock::TriggerAbsolute() // Lock acquired.
  273. {
  274. while ( Timer* timer = absolute_timer )
  275. {
  276. if ( timespec_lt(current_time, timer->value.it_value) )
  277. break;
  278. if ( (absolute_timer = absolute_timer->next_timer) )
  279. absolute_timer->prev_timer = NULL;
  280. FireTimer(timer);
  281. }
  282. }
  283. static void Clock__DoFireTimer(Timer* timer)
  284. {
  285. timer->callback(timer->clock, timer, timer->user);
  286. }
  287. static void Clock__FireTimer(void* timer_ptr)
  288. {
  289. Timer* timer = (Timer*) timer_ptr;
  290. assert(timer->clock);
  291. // Combine all the additionally pending events into a single one and notify
  292. // the caller of all the events that he missed because we couldn't call him
  293. // fast enough.
  294. timer->clock->LockClock();
  295. timer->num_overrun_events = timer->num_firings_scheduled;
  296. timer->num_firings_scheduled = 0;
  297. timer->clock->UnlockClock();
  298. Clock__DoFireTimer(timer);
  299. // If additional events happened during the time of the event handler, we'll
  300. // have to handle them because the firing bit is set. We'll schedule another
  301. // worker thread job and resume there, so this worker thread can continue to
  302. // do other important stuff.
  303. timer->clock->LockClock();
  304. if ( timer->num_firings_scheduled )
  305. Worker::Schedule(Clock__FireTimer, timer_ptr);
  306. // If this was the last event, we'll clear the firing bit and the advance
  307. // thread now has the responsibility of creating worker thread jobs.
  308. else
  309. timer->flags &= ~TIMER_FIRING;
  310. timer->clock->UnlockClock();
  311. }
  312. static void Clock__FireTimer_InterruptWorker(void* timer_ptr, void*, size_t)
  313. {
  314. Clock__FireTimer(timer_ptr);
  315. }
  316. void Clock::FireTimer(Timer* timer)
  317. {
  318. timer->flags &= ~TIMER_ACTIVE;
  319. // If the CPU is currently interrupted, we call the timer callback directly
  320. // only if it is known to work when the interrupts are disabled on this CPU.
  321. // Otherwise, we forward the timer pointer to a special interrupt-safe
  322. // worker thread that'll run the callback normally.
  323. if ( !Interrupt::IsEnabled() )
  324. {
  325. if ( timer->flags & TIMER_FUNC_INTERRUPT_HANDLER )
  326. Clock__DoFireTimer(timer);
  327. else if ( timer->flags & TIMER_FIRING )
  328. timer->num_firings_scheduled++;
  329. else
  330. {
  331. timer->flags |= TIMER_FIRING;
  332. Interrupt::ScheduleWork(Clock__FireTimer_InterruptWorker, timer, NULL, 0);
  333. }
  334. }
  335. // Normally, we will run the timer callback in a worker thread, but as an
  336. // optimization, if the callback is known to be short and simple and safely
  337. // handles this situation, we'll simply call it from the current thread.
  338. else
  339. {
  340. if ( timer->flags & TIMER_FUNC_ADVANCE_THREAD )
  341. Clock__DoFireTimer(timer);
  342. else if ( timer->flags & TIMER_FIRING )
  343. timer->num_firings_scheduled++;
  344. else
  345. {
  346. timer->flags |= TIMER_FIRING;
  347. Worker::Schedule(Clock__FireTimer, timer);
  348. }
  349. }
  350. // Rearm the timer only if it is periodic.
  351. if ( timespec_le(timer->value.it_interval, timespec_nul()) )
  352. return;
  353. // TODO: If the period is too short (such a single nanosecond) on a delay
  354. // timer, then it will try to spend each nanosecond avanced carefully
  355. // and reliably schedule a shitload of firings. Not only that, but it
  356. // will also loop this function many million timers per tick!
  357. // TODO: Throtte the timer if firing while the callback is still running!
  358. // TODO: Doesn't reload properly for absolute timers!
  359. if ( timer->flags & TIMER_ABSOLUTE )
  360. timer->value.it_value = timespec_add(timer->value.it_value, timer->value.it_interval);
  361. else
  362. timer->value.it_value = timer->value.it_interval;
  363. Register(timer);
  364. }
  365. } // namespace Sortix