Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | /*
* Copyright (c) 1997-2010, 2012-2015 Wind River Systems, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* @brief Microkernel tick event handler
*
* This module implements the microkernel's tick event handler.
*/
#include <nanokernel.h>
#include <arch/cpu.h>
#include <micro_private.h>
#include <drivers/system_timer.h>
#include <microkernel.h>
#include <microkernel/ticks.h>
#include <toolchain.h>
#include <sections.h>
#include <init.h>
#ifdef CONFIG_TIMESLICING
static int32_t slice_count = (int32_t)0;
static int32_t slice_time = (int32_t)CONFIG_TIMESLICE_SIZE;
static kpriority_t slice_prio =
(kpriority_t)CONFIG_TIMESLICE_PRIORITY;
#endif /* CONFIG_TIMESLICING */
#ifdef CONFIG_TICKLESS_IDLE
/* Number of ticks elapsed that have not been announced to the microkernel */
int32_t _sys_idle_elapsed_ticks; /* Initial value must be 0 */
#endif
/**
* @internal
* @brief Task level debugging tick handler
*
* If task level debugging is configured this routine updates the low resolution
* debugging timer and determines if task level processing should be suspended.
*
* @return 0 if task level processing should be halted or 1 if not
*
*/
#ifdef CONFIG_TASK_DEBUG
uint32_t __noinit _k_debug_sys_clock_tick_count;
static inline int _TlDebugUpdate(int32_t ticks)
{
_k_debug_sys_clock_tick_count += ticks;
return !_k_debug_halt;
}
#else
#define _TlDebugUpdate(ticks) 1
#endif
/**
* @internal
* @brief Tick handler time slice logic
*
* This routine checks to see if it is time for the current task
* to relinquish control, and yields CPU if so.
*
* @return N/A
*
*/
static inline void _TimeSliceUpdate(void)
{
#ifdef CONFIG_TIMESLICING
int yield = slice_time && (_k_current_task->priority >= slice_prio) &&
(++slice_count >= slice_time);
if (yield) {
slice_count = 0;
_k_task_yield(NULL);
}
#else
/* do nothing */
#endif /* CONFIG_TIMESLICING */
}
/**
* @internal
* @brief Get elapsed ticks
*
* If tickless idle support is configured this routine returns the number
* of ticks since going idle and then resets the global elapsed tick counter back
* to zero indicating all elapsed ticks have been consumed. This is done with
* interrupts locked to prevent the timer ISR from modifying the global elapsed
* tick counter.
* If tickless idle support is not configured in it simply returns 1.
*
* @return number of ticks to process
*/
static inline int32_t _SysIdleElapsedTicksGet(void)
{
#ifdef CONFIG_TICKLESS_IDLE
int32_t ticks;
int key;
key = irq_lock();
ticks = _sys_idle_elapsed_ticks;
_sys_idle_elapsed_ticks = 0;
irq_unlock(key);
return ticks;
#else
/* A single tick always elapses when not in tickless mode */
return 1;
#endif
}
/**
*
* @brief Microkernel tick handler
*
* This routine informs other microkernel subsystems that a tick event has
* occurred.
* @param even Event
* @return 1
*/
int _k_ticker(int event)
{
(void)event; /* prevent "unused argument" compiler warning */
int32_t ticks;
ticks = _SysIdleElapsedTicksGet();
_k_workload_monitor_update();
if (_TlDebugUpdate(ticks)) {
_TimeSliceUpdate();
_k_timer_list_update(ticks);
_nano_sys_clock_tick_announce(ticks);
}
return 1;
}
#ifdef CONFIG_SYS_CLOCK_EXISTS
static void _sys_clock_tick_announce_pre_micro(kevent_t e)
{
ARG_UNUSED(e);
/* before k_server starts use nanokernel tick announce function */
_nano_sys_clock_tick_announce(_SysIdleElapsedTicksGet());
}
void (*_do_sys_clock_tick_announce)(kevent_t) =
_sys_clock_tick_announce_pre_micro;
static int _sys_clock_microkernel_handler_install(struct device *dev)
{
ARG_UNUSED(dev);
extern void (*_do_task_sleep)(int32_t ticks);
extern void _micro_task_sleep(int32_t ticks);
_do_sys_clock_tick_announce = isr_event_send;
_do_task_sleep = _micro_task_sleep;
return 0;
}
SYS_INIT(_sys_clock_microkernel_handler_install, MICROKERNEL, 0);
#endif /* CONFIG_SYS_CLOCK_EXISTS */
#ifdef CONFIG_TIMESLICING
void sys_scheduler_time_slice_set(int32_t t, kpriority_t p)
{
slice_time = t;
slice_prio = p;
}
#endif /* CONFIG_TIMESLICING */
|