⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtos_services.c

📁 嵌入式操作系统EOS(Embedded OperatingSystem)是一种用途广泛的系统软件
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
** Copyright (C) 2006 Tamir Michael
**  
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
** 
** This program 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
** GNU General Public License for more details.
** 
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software 
** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

/* TODO: 

* fix performance measurement
* measure interrupt execution time (optional, MACRO?)
* optional stack status checks (MACRO ?). cound be interesting for ISRs
* allow tasks to be signalled (unblocked) when waiting
* write a "blocking" post thread message
*/

#include <XC167.h>
#include <stdio.h>

#include "system_messages.h"
#include "rtos_services.h"
#include "synchronization.h"
#include "general_definitions.h"
#include "trace_buffer.h"

// used to map a priority (the index of the array) to a time slice (the contents of the array)
static int16s s_task_time_slices[] = {TIME_SLICE_0, TIME_SLICE_1, TIME_SLICE_2, TIME_SLICE_3, TIME_SLICE_4, TIME_SLICE_5, TIME_SLICE_6, TIME_SLICE_7} ;

// this table returns the index of the task group with the highest priority.
// each task administration has a 'priority_bitmap' member of type int8u (8 bit). fr example, if the administration's
// 'priority_bitmap' value is 0x34 = 00110100 (meaning: there are tasks with priorities 2, 4 and 5 ready to run)
// this table returns 2, because the lower the value of the priority, the higher it is considered.
static int8u s_priority_resolution_table[] = 
{
    0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x00 to 0x0F                             */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x10 to 0x1F                             */
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x20 to 0x2F                             */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x30 to 0x3F                             */
    6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x40 to 0x4F                             */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x50 to 0x5F                             */
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x60 to 0x6F                             */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x70 to 0x7F                             */
    7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x80 to 0x8F                             */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0x90 to 0x9F                             */
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xA0 to 0xAF                             */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xB0 to 0xBF                             */
    6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xC0 to 0xCF                             */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xD0 to 0xDF                             */
    5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0,       /* 0xE0 to 0xEF                             */
    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0        /* 0xF0 to 0xFF                             */
} ;

task_info 					g_tcb[MAX_TASKS] ; // TCB - task control block. this is a global.
int16s 						g_running_task = 0 ;
static int16s 				s_number_of_tasks = 0 ;
static int16s				s_number_of_timers = 0 ;
static schedule_policy 		s_schedule_policy = ePriorityBased ;
static timer_info			s_timers[MAX_TIMERS] ; // system timers (of all types)
int32u volatile 	        g_tick_count = 0;
static stacktype 			s_idle_stack[DEFUALT_STACK_SIZE] ;
static int32u				s_schedule_session = 0 ; // used to efficPSW_IENtly reload the time-slices of tasks

static queue_info			s_suspended_tasks_queue ; // tasks that are explicitly suspended
static queue_info			s_waiting_tasks_queue ; // tasks blocked on a synchronization primitive
static queue_info			s_waiting_for_messages_tasks_queue ; // tasks waiting for incoming messages

// performance measurements
static int32u 				s_max_performance_task_counter = 0 ;
static int32u 				s_last_performance_task_counter = 0 ;
static int16s				s_performance_mutex ;
static int8u				s_cpu_load = 0 ;
static stacktype 			s_performance_task_stack[DEFUALT_STACK_SIZE] ; // note: user stack + processor stack (as system stack defined in A66 file * 2)

static bit					s_scheduler_started = 0 ;

// the scheduler shall switch to this task id if an interrupt occurs and a task is waiting for it.
// this variable is set in the respective ISR.
int16s 						g_force_switch_to_task_interrupt_occurred = -1 ;

// if the scheduler is suspended, the system repeatedly switches from the task that suspended the scheduler to 
// the idle task and back. the id of the task that suspended the scheduler is save in
// "s_scheduler_disabled_idle_task_forced_context_switch_to_task".
static int16s				s_scheduler_disabled_idle_task_forced_context_switch_to_task = -1 ;

// user defined callback in case of system failure
callback_ptr 		        g_system_failure_hook = 0 ;

int16s g_vector_to_task_index[NUM_INTERRUPTS] ;

// primary and secondary task administrations. switched once the active task is empty. tasks that consume their 
// time slice are transfered to the secondary administration pending the switch. the usage of pointers here is 
// intended to speed up administration switch by reducing it to a simple pointer address assigmnet operation (see
// 'scheduler_select_next_stack').
static prio_array  s_main_priority_array ;
static prio_array  s_secondary_priority_array ;
prio_array        *s_primary_ready_to_run_tasks  	= &s_main_priority_array ;
static prio_array *s_secondary_ready_to_run_tasks 	= &s_secondary_priority_array ;

// idle task hook
static callback_ptr	s_idle_task_hook ;
static int32s		s_idle_task_hook_parameter ;

// task stack snapshot
static stacktype s_task_snapshot_image[DEFUALT_STACK_SIZE] ; // the snapshot buffer
static stacktype *s_task_snapshot_sp = (stacktype *)SYSTEM_STACK_TOP ; // offset in the snapshot buffer - actually stack top
static int16s	 s_snapshot_task_id ;

// WAR STORY
// these variables are only used in 'task_switch', but it is not desirable to allocate them on the processor stack (that
// contains the state of the task that is left) because they will be copied into the stack-copy of the task.
// so they are allocated at compile time instead.
static stacktype *s_lp_source, *s_lp_target, *s_lp_sourceSP, *s_lp_next_stack ;
static stacktype **s_lp_R0 ; // todo: static here is used to prevent the compiler from optimizing s_lp_R0 assignment after #pragma and other measures failed. find a way to solve this.
static int16u s_active_task ;
					
// allowed from interrupt context; does not change anything
int8u rtos_get_cpu_load()
{
	int8u	l_load ;

	rtos_mutex_lock(s_performance_mutex) ;
	l_load = s_cpu_load ;	
	rtos_mutex_unlock(s_performance_mutex) ;
	
	return l_load ;
}

// returns the index of the next free timer
static int16s s_find_next_available_timer()
{
	int16s l_index ;
	timer_info *lp_timer ;

	for (l_index = 0; l_index < MAX_TIMERS; l_index++)
	{
		lp_timer = s_timers + l_index ;

		if (lp_timer->state == eTimerNotAllocated)
		{
			return l_index ;
		}
	}

	return ERR_TIMER_NOT_FOUND ;
}

// allows invocation of this functionality without meddling with interrupts (from 'scheduler_task_wait'). 
// calling 'rtos_save_and_disable_interrupts' twice in a row with interrupts disabled will not allow them to 
// be enabled again without calling 'rtos_enable_interrupts' which is less desired than restoring 
// the previous state with 'rtos_restore_interrupts'.
static int16s s_internal_allocate_timer()
{
	int16s 		l_index ;
	timer_info *lp_timer ;

	if ( (l_index = s_find_next_available_timer() ) != ERR_TIMER_NOT_FOUND)
	{
		lp_timer = s_timers + l_index ;
		lp_timer->owner = ERR_TIMER_NOT_FOUND ; // an owner will be set once this Mutex is locked
		lp_timer->state = eTimerAllocated ;
		lp_timer->parameter = 0 ;
		lp_timer->id = l_index ;
		s_number_of_timers++ ;
	}

	return l_index ;
}

// invoked once a second, to calculate CPU load. 'init_performance_meter' ran for one second
// to measure how many CPU cycles elapse at 100% CPU time. depending on how well 'performance_task' does
// (how often is it being scheduled?) this interrupt handler will calculate CPU load
/*void s_performanceTask()
{
	// allow the idle task count one second before determining how far it managed to get; that is a reflection of "0%" CPU usage (only the idle task runs).
	scheduler_task_wait(SECONDS(1)) ;

	// save the results
	rtos_mutex_lock(s_performance_mutex) ;
	s_max_performance_task_counter = s_last_performance_task_counter ;
	s_last_performance_task_counter = 0 ;
	rtos_mutex_unlock(s_performance_mutex) ;

	// continue measuring periodically
	while (1)
	{
		scheduler_task_wait(SECONDS(1)) ;

		rtos_mutex_lock(s_performance_mutex) ;
		s_cpu_load = 100 - ( (float32)s_last_performance_task_counter / (float32)s_max_performance_task_counter * 100) ;
		s_last_performance_task_counter = 0 ;
		rtos_mutex_unlock(s_performance_mutex) ;
	}
} */

// idle system task. always executed.
static void s_idle_task()
{
	while (1)
	{
		if (s_idle_task_hook)
		{
			int8u  l_interrupts_status ;
	
			// the kernel is not reentrant; protect static/global data from ISRs
			rtos_save_and_disable_interrupts(&l_interrupts_status) ;
			
			s_idle_task_hook(s_idle_task_hook_parameter) ;
			
			rtos_restore_interrupts(l_interrupts_status) ;

			scheduler_reschedule() ;
		}
	}
}

int32s rtos_system_time(int16u *hours, int16u *minutes, int32u *seconds, int32u *milliseconds)
{
	int32u l_tick_count_copy ;

	if ( (!hours) || (!minutes) || (!seconds) || (!milliseconds) )
	{
		software_warning("%s %s %d", resolve_system_message(ERR_INVALID_PARAMETER), __FILE__, __LINE__ ) ;
		return ERR_INVALID_PARAMETER ;
	}

	_atomic_(0) ;
	l_tick_count_copy = g_tick_count ;
	_endatomic_() ;
	
	*milliseconds = l_tick_count_copy / 10L ;
	*seconds = *milliseconds / 1000L ;
	*minutes = (int16u)(*seconds / 60L) ;
	*hours = (int16u)(*minutes / 60L) ;

	return 0 ;
}

static int8u s_updatable_timer(int16s timer)
{
	switch (s_timers[timer].state)
	{
		case eTimerTicking:
			return 1 ;

		case eTimerNotAllocated:
		case eTimerAllocated:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -