深入理解任务堆栈以及堆栈溢出

前言:
在多任务操作系统中创建任务时,都需要指定该任务的堆栈大小,那么这个堆栈的作用时什么呢?什么情况下需要用到堆栈,以及大小不够时会产生什么异常呢?

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功能的操作系统中,可能会导致系统奔溃。
所以,需要根据任务的情况设置合适的堆栈大小。同时,应避免使用递归调用函数,函数中局部变量的分配空间不能太大。

  • 7
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值