mirror of https://github.com/dzavalishin/oskit/
160 lines
5.2 KiB
C
Executable File
160 lines
5.2 KiB
C
Executable File
/*
|
|
* Copyright (c) 2000 University of Utah and the Flux Group.
|
|
* All rights reserved.
|
|
*
|
|
* This file is part of the Flux OSKit. The OSKit is free software, also known
|
|
* as "open source;" you can redistribute it and/or modify it under the terms
|
|
* of the GNU General Public License (GPL), version 2, as published by the Free
|
|
* Software Foundation (FSF). To explore alternate licensing terms, contact
|
|
* the University of Utah at csl-dist@cs.utah.edu or +1-801-585-3271.
|
|
*
|
|
* The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have
|
|
* received a copy of the GPL along with the OSKit; see the file COPYING. If
|
|
* not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#ifdef PTHREAD_REALTIME
|
|
/*
|
|
* Support for realtime schedulers.
|
|
*/
|
|
|
|
#include <threads/pthread_internal.h>
|
|
#include <threads/pthread_realtime.h>
|
|
|
|
/* Clock IRQ handlers */
|
|
static void realtime_clock_handler(void *data);
|
|
static void standard_clock_handler(void *data);
|
|
|
|
/*
|
|
* Clock counts. This allows us to keep track of missed clock
|
|
* interrupts. For every realtime interrupt, there should be a
|
|
* corresponding callback on the standard handler. When interrupts are
|
|
* software disabled, we get callback on the realtime handler, but not
|
|
* on the standard handler. In most cases this one miss will get
|
|
* called later when interrupts are software enabled. However, it is
|
|
* possible to miss more than one if interrupts are disabled a long
|
|
* time. By keeping track of the difference in count, we can schedule
|
|
* enough clock ticks to keep the rest of the oskit time keeping
|
|
* mechanism happy. This essentially operates as an up/down counter.
|
|
*/
|
|
static unsigned int realtime_clock_ticks;
|
|
|
|
/*
|
|
* Just what the name sez.
|
|
*/
|
|
void
|
|
realtime_clock_init(void)
|
|
{
|
|
int err, enabled;
|
|
|
|
enabled = machine_intr_enabled();
|
|
machine_intr_disable();
|
|
|
|
/*
|
|
* Add a realtime handler for IRQ 0 (Clock).
|
|
*/
|
|
err = osenv_irq_alloc(0, realtime_clock_handler,
|
|
0, OSENV_IRQ_REALTIME);
|
|
if (err)
|
|
panic("realtime_clock_init: Could not add realtime IRQ\n");
|
|
|
|
/*
|
|
* Add a normal handler for the clock. The override flag allows
|
|
* a non-shared IRQ to become shared. I prefer this to changing
|
|
* existing uses of IRQ 0 in other parts of the oskit.
|
|
*/
|
|
err = osenv_irq_alloc(0, standard_clock_handler,
|
|
0, OSENV_IRQ_OVERRIDE);
|
|
if (err)
|
|
panic("realtime_clock_init: Could not add standard IRQ\n");
|
|
|
|
|
|
if (enabled)
|
|
machine_intr_enable();
|
|
}
|
|
|
|
/*
|
|
* Realtime clock handler.
|
|
*/
|
|
static void
|
|
realtime_clock_handler(void *data)
|
|
{
|
|
#if defined(RTSCHED_STATS) && defined(OSKIT_X86_PC)
|
|
/*
|
|
* Count latency cycles. Depends on some code in the low level
|
|
* IRQ handler. Not portable.
|
|
*/
|
|
extern stat_time_t interrupt_start_high, interrupt_start_low;
|
|
stat_stamp_t then, now;
|
|
stat_accum_t diff;
|
|
|
|
now = STAT_STAMPGET();
|
|
then = ((stat_stamp_t) interrupt_start_high << 32) |
|
|
interrupt_start_low;
|
|
diff = (stat_accum_t) (now - then);
|
|
|
|
pthread_counts.handler_latency_total += diff;
|
|
|
|
if (diff < pthread_counts.handler_latency_min)
|
|
pthread_counts.handler_latency_min = diff;
|
|
if (diff > pthread_counts.handler_latency_max)
|
|
pthread_counts.handler_latency_max = diff;
|
|
#endif
|
|
PCOUNT(pthread_counts.realtime_clockticks++);
|
|
realtime_clock_ticks++;
|
|
|
|
/*
|
|
* Always pend a corresponding standard clock IRQ so that the
|
|
* rest of the oskit stays happy and in time. This will result
|
|
* in a call to the pthread timer callback.
|
|
*/
|
|
osenv_irq_schedule(0);
|
|
|
|
/*
|
|
* In the RTAI/RTL systems, a realtime thread preempts whatever is
|
|
* running immediately. Thats because there is a very clear line
|
|
* between what is Linux and what is the RT system. In other words,
|
|
* linux and RT threads will not overlap in their behaviour, so its
|
|
* okay to preempt the linux kernel no matter what it is doing,
|
|
* cause an RT thread will never do anything that overlaps it.
|
|
* Well, thats how it appears to me.
|
|
*
|
|
* In the oskit, we do not have such a clear line (yet?). Preempting
|
|
* a thread when interrupts or preemption is disabled could really
|
|
* mess up things. This aspect needs more thought/work. Additionally,
|
|
* the scheduler code proper will need to hardware disable interrupts
|
|
* when taking the scheduler lock since it would be bad to context
|
|
* switch when in the context switch path!
|
|
*
|
|
* For now, use the existing thread preemption mechanism, which is
|
|
* a software interrupt. The existing pthread timer callback
|
|
* will enable the software interrupt flag. A preemption will
|
|
* happen as soon as interrupts are enabled and the preemption
|
|
* disable flag is cleared.
|
|
*/
|
|
}
|
|
|
|
/*
|
|
* All this does is keep the oskit time in sync by making sure that we
|
|
* get as many standard interrupts handler calls as there are realtime
|
|
* handler calls.
|
|
*/
|
|
static void
|
|
standard_clock_handler(void *data)
|
|
{
|
|
PCOUNT(pthread_counts.standard_clockticks++);
|
|
|
|
osenv_assert(realtime_clock_ticks > 0);
|
|
|
|
/*
|
|
* If multiple missed ticks, schedule another IRQ to be delivered.
|
|
*/
|
|
if (--realtime_clock_ticks > 0) {
|
|
PCOUNT(pthread_counts.missed_clockticks++);
|
|
osenv_irq_schedule(0);
|
|
}
|
|
}
|
|
#endif
|