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

📄 os_cpu_c.c

📁 GCC下microC/OS-II 开发平台
💻 C
字号:
/* *                                                uC/OS-II *                                          The Real-Time Kernel * *                                               Linux Port * * File        : $Source: /proj/cvs-gfa/Micrium/Software/uCOS-II/Ports/linux-hal/os_cpu_c.c,v $ * By          : (c) George Fankhauser, Sensaco Consulting GmbH,  *               Switzerland, http://www.sensaco.com   * Version     : $Revision: 1.1.1.1 $ * * Changed by  : $Author: gfa $ *               $Date: 2003/11/20 10:19:14 $ * * $Log: os_cpu_c.c,v $ * Revision 1.1.1.1  2003/11/20 10:19:14  gfa * check in ucos II for linux * *//** \file  * User context switching code derived from Topsy 2.0 port to Linux and Solaris * (see http://www.tik.ee.ethz.ch/~topsy). * * \author George Fankhauser */ #define  OS_CPU_GLOBALS#include "includes.h"#include <asm/sigcontext.h> // for context switching#define __USE_GNU#include <ucontext.h>#undef __USE_GNU#include <ucontext.h>   // for context switching#include <string.h>#include <unistd.h>   // used for syscalls:                      // ualarm in Threads/unix/TMClock.c		      // kill   in Topsy/unix/SyscallMsg.c		      // getpid in Topsy/unix/SyscallMsg.c#include <signal.h>   // used in Threads/unix/TMHal.c and                       // Topsy/unix/SyscallMsg.c#include <setjmp.h>   // for contextswitches in Threads/unix/TMHal.c#include <sys/select.h>#include <stdio.h>    // if we want to use printf.../**                                          TASK CREATION HOOK * * This function is called when a task is created. * Arguments  : ptcb   is a pointer to the task control block of the task being created. * Note(s)    : 1) Interrupts are disabled during this call. */#if OS_CPU_HOOKS_EN > 0void OSTaskCreateHook (OS_TCB *ptcb){    ptcb = ptcb;}#endif/**                                          TASK DELETION HOOK * * This function is called when a task is deleted. * \arg ptcb   is a pointer to the task control block of the task being deleted. * Note(s)    : 1) Interrupts are disabled during this call. */#if OS_CPU_HOOKS_EN > 0void OSTaskDelHook (OS_TCB *ptcb){    ptcb = ptcb;       /* Prevent compiler warning */}#endif/**                                           TASK SWITCH HOOK * * This function is called when a task switch is performed.  This allows  * you to perform other operations during a context switch. * * Note(s)    : 1) Interrupts are disabled during this call. *              2) It is assumed that the global pointer 'OSTCBHighRdy' points to the  *              TCB of the task that will be 'switched in' (i.e. the highest priority  *              task) and, 'OSTCBCur' points to the task being switched out (i.e. the  *              preempted task). */#if (OS_CPU_HOOKS_EN > 0) && (OS_TASK_SW_HOOK_EN > 0)void OSTaskSwHook (void){}#endif/**                                           STATISTIC TASK HOOK * * This function is called every second by uC/OS-II's statistics task.   * This allows your application to add functionality to the statistics task. */#if (OS_TASK_STAT_HOOK_EN > 0)void OSTaskStatHook (void){}#endif/**                                               TICK HOOK * * This function is called every tick. * Note(s)    : 1) Interrupts may or may not be ENABLED during this call. */#if (OS_CPU_HOOKS_EN > 0) && (OS_TIME_TICK_HOOK_EN > 0)void OSTimeTickHook (void){}#endif/**                                     OS INITIALIZATION HOOK *                                            (BEGINNING) * * This function is called by OSInit() at the beginning of OSInit(). * Note(s)    : 1) Interrupts should be disabled during this call. */#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203void OSInitHookBegin (void){    linuxInit(); ///< installs the syscall handler}#endif/**                                     OS INITIALIZATION HOOK *                                               (END) * * This function is called by OSInit() at the end of OSInit(). * Note(s)    : 1) Interrupts should be disabled during this call. */#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203void OSInitHookEnd (void){}#endif/**                                          IDLE TASK HOOK * * This function is called by the idle task.  This hook has been added to  * allow you to do such things as STOP the CPU to conserve power. * Note(s)    : 1) Interrupts are enabled during this call. *  * 		On real hardware a power saving function would be selected. * 		On Linux, we sleep a little to lower the load on the system * 		or, we block until next signal is delivered by calling select(). * 		 * 		If either of these methods causes problems just leave the * 		function empty. */#if OS_CPU_HOOKS_EN > 0 && OS_VERSION >= 251void OSTaskIdleHook (void){    // usleep(50); ///< as done in Topsy    select(0, NULL, NULL, NULL, NULL); ///< as done in eCos}#endif/**                                           OSTCBInit() HOOK * * This function is called by OS_TCBInit() after setting up most of the TCB. * \arg ptcb    is a pointer to the TCB of the task being created. * Note(s)    : 1) Interrupts may or may not be ENABLED during this call. */#if OS_CPU_HOOKS_EN > 0 && OS_VERSION > 203void OSTCBInitHook (OS_TCB *ptcb){    ptcb = ptcb;     }#endif/**                                 INITIALIZE A TASK'S STACK * * This function is called by either OSTaskCreate() or OSTaskCreateExt() to  * initialize the stack frame of the task being created. This function is highly  * processor specific. * \arg task    is a pointer to the task code * \arg pdata   is a pointer to a user supplied data area that will be passed to the task *              when the task first executes. * \arg ptos   is a pointer to the top of stack. It is assumed that 'ptos' points to the *              highest valid address on the stack. * \arg opt specifies options that can be used to alter the behavior of OSTaskStkInit(). *               \see uCOS_II.H for OS_TASK_OPT_???. * * \return Always returns the location of the new top-of-stack' once the processor  * registers have been placed on the stack in the proper order. * * Note(s)    : Interrupts are enabled when your task starts executing. You can change  * this by setting this SREG to 0x00 instead. In this case, interrupts would be disabled  * upon task startup. The application code would be responsible for enabling interrupts  * at the beginning of the task code. You will need to modify OSTaskIdle() and  * OSTaskStat() so that they enable interrupts. Failure to do this will make your system  * crash! */OS_STK* OSTaskStkInit (void (*task)(void* pd), void* pdata, OS_STK* ptos, INT16U opt){    INT32U*    stk;    ucontext_t uc;    INT32U     sigsize = 20 + sizeof(uc);    opt = opt;            /* 'opt' is not used, prevent warning  */        getcontext(&uc);        stk = (INT32U*)((int)ptos - sigsize);    uc.uc_link = NULL; ///< no successor    uc.uc_mcontext.gregs[REG_EBP] = (int)stk;    uc.uc_stack.ss_sp = (void*)(((int)stk) - (OS_TASK_DEF_STK_SIZE) + sigsize); ///< base address    uc.uc_stack.ss_size = OS_TASK_DEF_STK_SIZE - sigsize;    makecontext(&uc, (void*)task, 1, pdata);    memcpy(stk, &uc, sizeof(uc));        return ((OS_STK *)stk);}/** A new thread is started */void OSStartHighRdy(void) {	OSTaskSwHook();	OSRunning = TRUE;	// real work goes here...			{	ucontext_t* ucp;	ucp = (struct ucontext*)(OSTCBHighRdy->OSTCBStkPtr);	setcontext(ucp);	// not reached	}}/** called by OSIntExit() * * typically, after signal is handled, a potentially new thread is picked and  * resumed */void OSIntCtxSw(void) {	// on Linux this is the same as OSCtxSw; no special treats for hw/sw ints	OSCtxSw();}/**  * This procedure is called whenever a thread sleeps voluntarily, or, a syscall is made and the * the thread is not the highest priority thread anymore after rescheduling. * * This procedure is called via software interrupt (on Linux synthetic targets: signal and * handler). * * \todo setcontext is a user space implementation of calling sigprocmask and then restoring * registers; should try (ugly) hack using sigreturn which is a real syscall */void OSCtxSw(void) {		struct ucontext* uc = (struct ucontext*)OSTCBHighRdy->OSTCBStkPtr;	// at this point, registers are already saved on stack	OSTaskSwHook();	OSTCBCur = OSTCBHighRdy;	OSPrioCur = OSPrioHighRdy;	//if (uc->uc_mcontext.fpregs == 0) {	  //  fprintf(stderr, "ctx sw: uc->uc_mcontext.fpregs == 0\n");	    //uc->uc_mcontext.fpregs = (fpregset_t)0xbffff6cc;	//}	setcontext(uc);}/** * \arg signo Signal number * \arg info Signal info * \arg uc User context */void OSCtxSwSigHandler(int signo, siginfo_t* info, /*struct ucontext* */ void* uc){	/** Linux specific module variable of current signal context, i.e. interrupted thread 	 */		OSTCBCur->OSTCBStkPtr = uc; //stk;	OSCtxSw();}	/** \todo maybe wrong for linux port? * adjust sp  if nesting == 1 ???? maybe if there is a seperate interrupt stack * linux user space port does not have a special isr stack frame layout	 */void OSTickISR(void) {	///< register context already saved in sig handler	OSIntEnter();	if (OSIntNesting == 1) {		//OSTCBCur->OSTCBStkPtr = $SP;		//asm("mov %%esp, %0" : "=g"(OSTCBCur->OSTCBStkPtr) : );	}	OSTimeTick(); ///< adjusts counters and ready bitmaps	OSIntExit();  ///< reschedules if necessary	OSIntCtxSw(); ///< restore context and jump to highest prio task}/** * Periodic signal handler that adjusts timers * On Linux this is not very precise but for most applications sufficient * * Pick a value between 10 and 1000 Hz for the timer * * \todo this handler maybe executed during a restore (i.e. setcontext()) * call. This is a problem with the setcontext() user space implementation in * Linux i386. Most SysV and Linux RISC systems don't have this. The tests * below are an indication that this situatiuon has occured; the SIGALRM * is then aborted... * * \todo If this is not fixed by adding a Linux syscall for get/setcontext, a user level * implementation with an 'clock interrupt' lock should be used *  * \arg signo Signal number * \arg info Signal info * \arg uc User context */void OSTimeTickSigHandler(int signo, siginfo_t* info, /*struct ucontext* */ void* uc) {	if ((((ucontext_t*)uc)->uc_mcontext.gregs[REG_EIP] >= (unsigned int)setcontext) && 	    (((ucontext_t*)uc)->uc_mcontext.gregs[REG_EIP] < (unsigned int)(setcontext + 110))) {	    	//fprintf(stderr, "sig timer: thread interrupted in setcontext\n");		return;	}	if (((ucontext_t*)uc)->uc_mcontext.fpregs == 0) {	    	//fprintf(stderr, "sig timer: uc->uc_mcontext.fpregs == 0\n");	    	return;	} 	OSTCBCur->OSTCBStkPtr = uc; //stk;	OSTickISR();	// restore context}/** * Kick the periodic clock; this must be done \e after microC/OS-II is initialised,  * typically at the end of main() *  * Either SIGALRM or SIGVTALRM can be used *  * \attention This must be called by the user in the first task */void linuxInitInt(){    ualarm(1000000/OS_TICKS_PER_SEC, 1000000/OS_TICKS_PER_SEC); ///< periodic mode    // alternative    //setitimer(ITIMER_VIRTUAL, 1000000/OS_TICKS_PER_SEC); ///< SIGVTALRM  time spent by the     							  ///< process in User Mode}/** * Setup of Linux specific stuff such as stacks, signals, handlers, mask etc. * * This is called inside the HAL by OSInitHookBegin() */void linuxInit() {       struct sigaction act;    sigset_t mask;                 sigemptyset(&mask);    act.sa_sigaction = OSTimeTickSigHandler;    act.sa_flags = SA_SIGINFO;// | SA_ONSTACK;      act.sa_mask = mask;    sigaction(SIGALRM, &act, NULL);    sigaction(SIGVTALRM, &act, NULL);      sigemptyset(&mask);    act.sa_sigaction = OSCtxSwSigHandler;    act.sa_flags = SA_SIGINFO;// | SA_ONSTACK;      act.sa_mask = mask;    sigaction(SIGUSR1, &act, NULL);}

⌨️ 快捷键说明

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