前言: 在多任务操作系统中创建任务时,都需要指定该任务的堆栈大小,那么这个堆栈的作用时什么呢?什么情况下需要用到堆栈,以及大小不够时会产生什么异常呢?
1 任务状态 简单分为运行态,就绪态,阻塞态。 运行态:万事俱备,不欠东风(获得CPU控制权); 就绪态:万事俱备,只欠东风(缺少CPU控制权); 阻塞态:万事不俱备(等事件或信号),还欠东风(缺少CPU控制权); 每个任务基本上都会游离于这三种状态。 运行到阻塞,就绪到运行称为任务切换过程。
2 任务控制块 任务控制块是任务的抽象类型,用于描述其属性和方法。
struct tcb_s { /* Fields used to support list management *************************************/ FAR struct tcb_s *flink; /* Doubly linked list */ FAR struct tcb_s *blink; /* Task Group *****************************************************************/ #ifdef HAVE_TASK_GROUP FAR struct task_group_s *group; /* Pointer to shared task group data */ #endif /* Task Management Fields *****************************************************/ pid_t pid; /* This is the ID of the thread */ start_t start; /* Thread start function */ entry_t entry; /* Entry Point into the thread */ uint8_t sched_priority; /* Current priority of the thread */ uint8_t init_priority; /* Initial priority of the thread */ #ifdef CONFIG_PRIORITY_INHERITANCE #if CONFIG_SEM_NNESTPRIO > 0 uint8_t npend_reprio; /* Number of nested reprioritizations */ uint8_t pend_reprios[CONFIG_SEM_NNESTPRIO]; #endif uint8_t base_priority; /* "Normal" priority of the thread */ #endif uint8_t task_state; /* Current state of the thread */ #ifdef CONFIG_SMP uint8_t cpu; /* CPU index if running or assigned */ cpu_set_t affinity; /* Bit set of permitted CPUs */ #endif uint16_t flags; /* Misc. general status flags */ int16_t lockcount; /* 0=preemptable (not-locked) */ #ifdef CONFIG_SMP int16_t irqcount; /* 0=Not in critical section */ #endif #ifdef CONFIG_CANCELLATION_POINTS int16_t cpcount; /* Nested cancellation point count */ #endif #if CONFIG_RR_INTERVAL > 0 || defined(CONFIG_SCHED_SPORADIC) int32_t timeslice; /* RR timeslice OR Sporadic budget */ /* interval remaining */ #endif #ifdef CONFIG_SCHED_SPORADIC FAR struct sporadic_s *sporadic; /* Sporadic scheduling parameters */ #endif FAR struct wdog_s *waitdog; /* All timed waits use this timer */ /* Stack-Related Fields *******************************************************/ size_t adj_stack_size; /* Stack size after adjustment */ /* for hardware, processor, etc. */ /* (for debug purposes only) */ FAR void *stack_alloc_ptr; /* Pointer to allocated stack */ /* Need to deallocate stack */ FAR void *adj_stack_ptr; /* Adjusted stack_alloc_ptr for HW */ /* The initial stack pointer value */ /* External Module Support ****************************************************/ #ifdef CONFIG_PIC FAR struct dspace_s *dspace; /* Allocated area for .bss and .data */ #endif /* POSIX Semaphore Control Fields *********************************************/ sem_t *waitsem; /* Semaphore ID waiting on */ /* POSIX Signal Control Fields ************************************************/ #ifndef CONFIG_DISABLE_SIGNALS sigset_t sigprocmask; /* Signals that are blocked */ sigset_t sigwaitmask; /* Waiting for pending signals */ sq_queue_t sigpendactionq; /* List of pending signal actions */ sq_queue_t sigpostedq; /* List of posted signals */ siginfo_t sigunbinfo; /* Signal info when task unblocked */ #endif /* POSIX Named Message Queue Fields *******************************************/ #ifndef CONFIG_DISABLE_MQUEUE FAR struct mqueue_inode_s *msgwaitq; /* Waiting for this message queue */ #endif /* POSIX Thread Specific Data *************************************************/ #if CONFIG_NPTHREAD_KEYS > 0 FAR void *pthread_data[CONFIG_NPTHREAD_KEYS]; #endif /* Library related fields *****************************************************/ int pterrno; /* Current per-thread errno */ /* State save areas ***********************************************************/ /* The form and content of these fields are platform-specific. */ struct xcptcontext xcp; /* Interrupt register save area */ #if CONFIG_TASK_NAME_SIZE > 0 char name[CONFIG_TASK_NAME_SIZE+1]; /* Task name (with NUL terminator) */ #endif };3 任务堆栈 任务控制块的stack_alloc_ptr,就是堆栈的栈指针,用于关联任务堆栈:
FAR void *stack_alloc_ptr; /* Pointer to allocated stack任务堆栈使用malloc分配内存空间:
/* Use the user-space allocator if this is a task or pthread */ tcb->stack_alloc_ptr = (uint32_t *)kumm_malloc(stack_size);任务堆栈的作用: 1 任务处于运行状态: 当任务在运行时,一般都会调用各式各样的函数,而函数的局部变量,参数,返回值是存在于函数栈帧里的,每个函数都拥有独立的栈帧,各个栈帧使用的空间就是任务堆栈的空间。所以任务堆栈的作用是用于保存函数在运行/调用过程中的参数/局部变量。
2 任务处于切换 当运行的任务被切换时,需要保护现场(CPU中寄存器的值),以便于下次恢复数据。所以任务堆栈的作用是用于保存CPU中寄存器的值。
任务(低优先级的)在运行过程中,随时可能被切换,所以CPU中寄存器的值入栈的栈位置是不确定的,这取决于当前任务的执行情况。
4 堆栈溢出 若堆栈的空间设置太大,会浪费内存资源。而设置得太小,则会出现堆栈溢出,在没有MMU功能的操作系统中,可能会导致系统奔溃。 所以,需要根据任务的情况设置合适的堆栈大小。同时,应避免使用递归调用函数,函数中局部变量的分配空间不能太大。