source: mainline/kernel/generic/src/time/clock.c@ b2ec5cf

ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b2ec5cf was b2ec5cf, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 2 years ago

Implement atomic_time_stat_t for lockless timekeeping

We keep monotonically increasing temporal statistics in several places.
They are frequently written from the thread that owns them, and rarely
read from other threads in certain syscalls. This new code serves the
purpose of avoiding the need for synchronization on the writer side.
On 64b system, we can simply assume that 64b writes are indivisible,
and relaxed atomic read/writes simply serve to formally prevent C
undefined behavior from data races (they translate to regular memory
reads/writes in assembly).

On 32b systems, we use the same algorithm that's been used for userspace
clock access, using three fields and some memory barriers to maintain
consistency of reads when the upper half changes. Only readers always
synchronize though. For writers, barriers are avoided in the common case
when the upper half remains unchanged.

  • Property mode set to 100644
File size: 5.4 KB
RevLine 
[f761f1eb]1/*
[df4ed85]2 * Copyright (c) 2001-2004 Jakub Jermar
[eda43238]3 * Copyright (c) 2022 Jiří Zárevúcky
[f761f1eb]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
[e88eb48]30/** @addtogroup kernel_time
[b45c443]31 * @{
32 */
33
[cf26ba9]34/**
[b45c443]35 * @file
[da1bafb]36 * @brief High-level clock interrupt handler.
[cf26ba9]37 *
38 * This file contains the clock() function which is the source
39 * of preemption. It is also responsible for executing expired
40 * timeouts.
[da1bafb]41 *
[cf26ba9]42 */
[da1bafb]43
[f761f1eb]44#include <time/clock.h>
45#include <time/timeout.h>
46#include <config.h>
47#include <synch/spinlock.h>
48#include <synch/waitq.h>
[b2e121a]49#include <halt.h>
[f761f1eb]50#include <proc/scheduler.h>
51#include <cpu.h>
52#include <arch.h>
[5c9a08b]53#include <adt/list.h>
[23684b7]54#include <atomic.h>
[1084a784]55#include <proc/thread.h>
[d6e5cbc]56#include <sysinfo/sysinfo.h>
[05882233]57#include <barrier.h>
[f8ddd17]58#include <mm/frame.h>
59#include <ddi/ddi.h>
[d0c82c5]60#include <arch/cycle.h>
[f43d8ce]61#include <preemption.h>
[f8ddd17]62
[4b662f8c]63/* Pointer to variable with uptime */
64uptime_t *uptime;
65
66/** Physical memory area of the real time clock */
[f8ddd17]67static parea_t clock_parea;
[d6e5cbc]68
69/** Initialize realtime clock counter
70 *
71 * The applications (and sometimes kernel) need to access accurate
[1b20da0]72 * information about realtime data. We allocate 1 page with these
[d6e5cbc]73 * data and update it periodically.
[da1bafb]74 *
[d6e5cbc]75 */
76void clock_counter_init(void)
77{
[482f968]78 uintptr_t faddr = frame_alloc(1, FRAME_LOWMEM | FRAME_ATOMIC, 0);
[8cbf1c3]79 if (faddr == 0)
[f651e80]80 panic("Cannot allocate page for clock.");
[a35b458]81
[4b662f8c]82 uptime = (uptime_t *) PA2KA(faddr);
[a35b458]83
[4b662f8c]84 uptime->seconds1 = 0;
85 uptime->seconds2 = 0;
[9dae191e]86 uptime->useconds = 0;
[a35b458]87
[6f7071b]88 ddi_parea_init(&clock_parea);
[8cbf1c3]89 clock_parea.pbase = faddr;
[f8ddd17]90 clock_parea.frames = 1;
[d7533c7]91 clock_parea.unpriv = true;
[b366a6f4]92 clock_parea.mapped = false;
[f8ddd17]93 ddi_parea_register(&clock_parea);
[a35b458]94
[f8ddd17]95 /*
96 * Prepare information for the userspace so that it can successfully
97 * physmem_map() the clock_parea.
[da1bafb]98 *
[f8ddd17]99 */
[96b02eb9]100 sysinfo_set_item_val("clock.faddr", NULL, (sysarg_t) faddr);
[d6e5cbc]101}
102
103/** Update public counters
104 *
105 * Update it only on first processor
106 */
[d9dda26]107static void clock_update_counters(uint64_t current_tick)
[d6e5cbc]108{
109 if (CPU->id == 0) {
[d9dda26]110 uint64_t usec = (1000000 / HZ) * current_tick;
111
112 sysarg_t secs = usec / 1000000;
113 sysarg_t usecs = usec % 1000000;
114
115 uptime->seconds1 = secs;
116 write_barrier();
117 uptime->useconds = usecs;
118 write_barrier();
119 uptime->seconds2 = secs;
[d6e5cbc]120 }
121}
[f761f1eb]122
[d0c82c5]123static void cpu_update_accounting(void)
124{
125 irq_spinlock_lock(&CPU->lock, false);
126 uint64_t now = get_cycle();
[b2ec5cf]127 atomic_time_increment(&CPU->busy_cycles, now - CPU->last_cycle);
[d0c82c5]128 CPU->last_cycle = now;
129 irq_spinlock_unlock(&CPU->lock, false);
130}
131
[70527f1]132/** Clock routine
133 *
134 * Clock routine executed from clock interrupt handler
[22f7769]135 * (assuming interrupts_disable()'d). Runs expired timeouts
[70527f1]136 * and preemptive scheduling.
137 *
[f761f1eb]138 */
139void clock(void)
140{
[98000fb]141 size_t missed_clock_ticks = CPU->missed_clock_ticks;
[ab855cd]142 CPU->missed_clock_ticks = 0;
143
[d9dda26]144 CPU->current_clock_tick += missed_clock_ticks + 1;
145 uint64_t current_clock_tick = CPU->current_clock_tick;
146 clock_update_counters(current_clock_tick);
[a35b458]147
[d0c82c5]148 /* Account CPU usage */
149 cpu_update_accounting();
[a35b458]150
[f761f1eb]151 /*
152 * To avoid lock ordering problems,
153 * run all expired timeouts as you visit them.
[da1bafb]154 *
[f761f1eb]155 */
[a35b458]156
[ab855cd]157 irq_spinlock_lock(&CPU->timeoutlock, false);
[a35b458]158
[ab855cd]159 link_t *cur;
160 while ((cur = list_first(&CPU->timeout_active_list)) != NULL) {
161 timeout_t *timeout = list_get_instance(cur, timeout_t, link);
[a35b458]162
[ab855cd]163 if (current_clock_tick <= timeout->deadline) {
164 break;
165 }
[a35b458]166
[ab855cd]167 list_remove(cur);
168 timeout_handler_t handler = timeout->handler;
169 void *arg = timeout->arg;
[ba25c4b]170 atomic_bool *finished = &timeout->finished;
[a35b458]171
[ab855cd]172 irq_spinlock_unlock(&CPU->timeoutlock, false);
[a35b458]173
[ab855cd]174 handler(arg);
[a35b458]175
[ba25c4b]176 /* Signal that the handler is finished. */
177 atomic_store_explicit(finished, true, memory_order_release);
178
[ab855cd]179 irq_spinlock_lock(&CPU->timeoutlock, false);
[f761f1eb]180 }
[ab855cd]181
182 irq_spinlock_unlock(&CPU->timeoutlock, false);
[a35b458]183
[f761f1eb]184 /*
[43114c5]185 * Do CPU usage accounting and find out whether to preempt THREAD.
[da1bafb]186 *
[f761f1eb]187 */
[a35b458]188
[43114c5]189 if (THREAD) {
[aae2869]190 if (current_clock_tick >= CPU->preempt_deadline && PREEMPTION_ENABLED) {
[f761f1eb]191 scheduler();
[3ff2b54]192#ifdef CONFIG_UDEBUG
193 /*
194 * Give udebug chance to stop the thread
[5d9430d7]195 * before it begins executing userspace code.
[3ff2b54]196 */
[da1bafb]197 istate_t *istate = THREAD->udebug.uspace_state;
198 if ((istate) && (istate_from_uspace(istate)))
[3ff2b54]199 udebug_before_thread_runs();
200#endif
[f761f1eb]201 }
202 }
203}
[b45c443]204
[1bb2e7a]205/** @}
[b45c443]206 */
Note: See TracBrowser for help on using the repository browser.