179 lines
4.2 KiB
C
179 lines
4.2 KiB
C
/*
|
|
* 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_nop(kevent_t e)
|
|
{
|
|
ARG_UNUSED(e);
|
|
/* do nothing */
|
|
}
|
|
|
|
void (*_do_sys_clock_tick_announce)(kevent_t) =
|
|
_sys_clock_tick_announce_pre_micro_nop;
|
|
|
|
static int _sys_clock_tick_announce_install(struct device *dev)
|
|
{
|
|
ARG_UNUSED(dev);
|
|
_do_sys_clock_tick_announce = isr_event_send;
|
|
return 0;
|
|
}
|
|
|
|
SYS_INIT(_sys_clock_tick_announce_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 */
|