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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since da1bafb was da1bafb, checked in by Martin Decky <martin@…>, 15 years ago

major code revision

  • replace spinlocks taken with interrupts disabled with irq_spinlocks
  • change spacing (not indendation) to be tab-size independent
  • use unsigned integer types where appropriate (especially bit flags)
  • visual separation
  • remove argument names in function prototypes
  • string changes
  • correct some formating directives
  • replace various cryptic single-character variables (t, a, m, c, b, etc.) with proper identifiers (thread, task, timeout, as, itm, itc, etc.)
  • unify some assembler constructs
  • unused page table levels are now optimized out in compile time
  • replace several ints (with boolean semantics) with bools
  • use specifically sized types instead of generic types where appropriate (size_t, uint32_t, btree_key_t)
  • improve comments
  • split asserts with conjuction into multiple independent asserts
  • Property mode set to 100644
File size: 5.7 KB
Line 
1/*
2 * Copyright (c) 2001-2004 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup time
30 * @{
31 */
32
33/**
34 * @file
35 * @brief High-level clock interrupt handler.
36 *
37 * This file contains the clock() function which is the source
38 * of preemption. It is also responsible for executing expired
39 * timeouts.
40 *
41 */
42
43#include <time/clock.h>
44#include <time/timeout.h>
45#include <config.h>
46#include <synch/spinlock.h>
47#include <synch/waitq.h>
48#include <func.h>
49#include <proc/scheduler.h>
50#include <cpu.h>
51#include <arch.h>
52#include <adt/list.h>
53#include <atomic.h>
54#include <proc/thread.h>
55#include <sysinfo/sysinfo.h>
56#include <arch/barrier.h>
57#include <mm/frame.h>
58#include <ddi/ddi.h>
59
60/* Pointer to variable with uptime */
61uptime_t *uptime;
62
63/** Physical memory area of the real time clock */
64static parea_t clock_parea;
65
66/** Fragment of second
67 *
68 * For updating seconds correctly.
69 *
70 */
71static unative_t secfrag = 0;
72
73/** Initialize realtime clock counter
74 *
75 * The applications (and sometimes kernel) need to access accurate
76 * information about realtime data. We allocate 1 page with these
77 * data and update it periodically.
78 *
79 */
80void clock_counter_init(void)
81{
82 void *faddr = frame_alloc(ONE_FRAME, FRAME_ATOMIC);
83 if (!faddr)
84 panic("Cannot allocate page for clock.");
85
86 uptime = (uptime_t *) PA2KA(faddr);
87
88 uptime->seconds1 = 0;
89 uptime->seconds2 = 0;
90 uptime->useconds = 0;
91
92 clock_parea.pbase = (uintptr_t) faddr;
93 clock_parea.frames = 1;
94 ddi_parea_register(&clock_parea);
95
96 /*
97 * Prepare information for the userspace so that it can successfully
98 * physmem_map() the clock_parea.
99 *
100 */
101 sysinfo_set_item_val("clock.cacheable", NULL, (unative_t) true);
102 sysinfo_set_item_val("clock.faddr", NULL, (unative_t) faddr);
103}
104
105/** Update public counters
106 *
107 * Update it only on first processor
108 * TODO: Do we really need so many write barriers?
109 *
110 */
111static void clock_update_counters(void)
112{
113 if (CPU->id == 0) {
114 secfrag += 1000000 / HZ;
115 if (secfrag >= 1000000) {
116 secfrag -= 1000000;
117 uptime->seconds1++;
118 write_barrier();
119 uptime->useconds = secfrag;
120 write_barrier();
121 uptime->seconds2 = uptime->seconds1;
122 } else
123 uptime->useconds += 1000000 / HZ;
124 }
125}
126
127/** Clock routine
128 *
129 * Clock routine executed from clock interrupt handler
130 * (assuming interrupts_disable()'d). Runs expired timeouts
131 * and preemptive scheduling.
132 *
133 */
134void clock(void)
135{
136 size_t missed_clock_ticks = CPU->missed_clock_ticks;
137
138 /* Account lost ticks to CPU usage */
139 if (CPU->idle)
140 CPU->idle_ticks += missed_clock_ticks + 1;
141 else
142 CPU->busy_ticks += missed_clock_ticks + 1;
143
144 CPU->idle = false;
145
146 /*
147 * To avoid lock ordering problems,
148 * run all expired timeouts as you visit them.
149 *
150 */
151 size_t i;
152 for (i = 0; i <= missed_clock_ticks; i++) {
153 clock_update_counters();
154 irq_spinlock_lock(&CPU->timeoutlock, false);
155
156 link_t *cur;
157 while ((cur = CPU->timeout_active_head.next) != &CPU->timeout_active_head) {
158 timeout_t *timeout = list_get_instance(cur, timeout_t, link);
159
160 irq_spinlock_lock(&timeout->lock, false);
161 if (timeout->ticks-- != 0) {
162 irq_spinlock_unlock(&timeout->lock, false);
163 break;
164 }
165
166 list_remove(cur);
167 timeout_handler_t handler = timeout->handler;
168 void *arg = timeout->arg;
169 timeout_reinitialize(timeout);
170
171 irq_spinlock_unlock(&timeout->lock, false);
172 irq_spinlock_unlock(&CPU->timeoutlock, false);
173
174 handler(arg);
175
176 irq_spinlock_lock(&CPU->timeoutlock, false);
177 }
178
179 irq_spinlock_unlock(&CPU->timeoutlock, false);
180 }
181 CPU->missed_clock_ticks = 0;
182
183 /*
184 * Do CPU usage accounting and find out whether to preempt THREAD.
185 *
186 */
187
188 if (THREAD) {
189 uint64_t ticks;
190
191 irq_spinlock_lock(&CPU->lock, false);
192 CPU->needs_relink += 1 + missed_clock_ticks;
193 irq_spinlock_unlock(&CPU->lock, false);
194
195 irq_spinlock_lock(&THREAD->lock, false);
196 if ((ticks = THREAD->ticks)) {
197 if (ticks >= 1 + missed_clock_ticks)
198 THREAD->ticks -= 1 + missed_clock_ticks;
199 else
200 THREAD->ticks = 0;
201 }
202 irq_spinlock_unlock(&THREAD->lock, false);
203
204 if ((!ticks) && (!PREEMPTION_DISABLED)) {
205 scheduler();
206#ifdef CONFIG_UDEBUG
207 /*
208 * Give udebug chance to stop the thread
209 * before it begins executing userspace code.
210 */
211 istate_t *istate = THREAD->udebug.uspace_state;
212 if ((istate) && (istate_from_uspace(istate)))
213 udebug_before_thread_runs();
214#endif
215 }
216 }
217}
218
219/** @}
220 */
Note: See TracBrowser for help on using the repository browser.