新闻  |   论坛  |   博客  |   在线研讨会
Main组件分析(二)--TinyOS 1.x(ZT)
moran | 2008-08-06 15:00:49    阅读:1282   发布文章

  第二组:TOSH_sched_init();for(;;){TOSH_run_task();}

      这两个函数的实现在
tinyos-1.x\tos\system目录下的sched.c源文件中。这个文件就实现了tinyos 1.x的调度策略,很简单吧?闲话少说,下面分析它的数据结构。
typedef struct {
  void (*tp) ();
} TOSH_sched_entry_T;
       这个结构体就是tinyos任务队列里的东东,里面是个函数指针。
enum {
#ifdef TOSH_MAX_TASKS_LOG2
#if TOSH_MAX_TASKS_LOG2 > 8
#error "Maximum of 256 tasks, TOSH_MAX_TASKS_LOG2 must be <= 8"
#endif
  TOSH_MAX_TASKS = 1 << TOSH_MAX_TASKS_LOG2,
#else
  TOSH_MAX_TASKS = 8,
#endif
  TOSH_TASK_BITMASK = (TOSH_MAX_TASKS - 1)
};
      上面定义了tinyos任务队列里的最大任务数TOSH_MAX_TASKS,和一个掩码。

//定义tinyos任务队列,这个队列是个循环队列!
volatile TOSH_sched_entry_T TOSH_queue[TOSH_MAX_TASKS];
//“头指针”tinyos任务队列里的第一个不为空的任务的下标
uint8_t TOSH_sched_full;
//“尾指针”如果tinyos任务队列没有满,则是最后一个不为空的任务
//的下一个元素的下标;如果任务队列满则是最后一个任务的下标。
volatile uint8_t TOSH_sched_free;

       好了,数据结构分析完了,咱们看看tinyos是怎样实现这个队列的吧,实现一个队列,无非就是初始化,增加队列元素,删除队列元素,判断队列是否为空……,数据结构里最基本的东东,想必大家比我清楚了!(如果这个不清楚,赶紧回去看看数据结构^_^ )。


   一初始化
  
      初始化函数很简单,大家肯定都会写了。
void TOSH_sched_init(void)
{
int i;
  TOSH_sched_free = 0;
  TOSH_sched_full = 0;
  for (i = 0; i < TOSH_MAX_TASKS; i++)
    TOSH_queue[i].tp = NULL;
}
      上面这个就是了,首先是初始化两个“指针”,将它们指向第一个元素。接着是一个for循环将队列里的元素逐个“清零”。

二增加队列元素

bool TOS_post(void (*tp) ()) __attribute__((spontaneous)) {
  __nesc_atomic_t fInterruptFlags;
  uint8_t tmp;

  //  dbg(DBG_SCHED, ("TOSH_post: %d 0x%x\n", TOSH_sched_free, (int)tp));
 fInterruptFlags = __nesc_atomic_start();

  tmp = TOSH_sched_free;
  
  if (TOSH_queue[tmp].tp == NULL) {
    TOSH_sched_free = (tmp + 1) & TOSH_TASK_BITMASK;
    TOSH_queue[tmp].tp = tp;
    __nesc_atomic_end(fInterruptFlags);

    return TRUE;
  }
  else {    
    __nesc_atomic_end(fInterruptFlags);

    return FALSE; 
 }
}
       该函数的参数是个函数指针,大家不要怕它,如果不明白就当它是个整数好了(有点误人子弟的嫌疑,不明白的话大家还是回去复习一下c语言^_*)!
    从上面可以看出,该函数核心代码不过三句,
     第一句:if (TOSH_queue[tmp].tp == NULL),判断队列里是否满了;如果满了则返回FALSE,如果没满则队列的“尾指针”向后移,一时不明白的网友可以在纸上画画,很快就明白了;移完“尾指针”后,语句TOSH_queue[tmp].tp = tp;将传入的参数加入到队列尾(这个队列尾是移完“尾指针”前的队尾)。
      就这样,增加队列元素的动作就完了,很简单吧?比我们学过的数据结构还简单吧?
三、取出队列元素并删除该元素


bool TOSH_run_next_task ()
{
  __nesc_atomic_t fInterruptFlags;
  uint8_t old_full;
  void (*func)(void);
  
  fInterruptFlags = __nesc_atomic_start();
  old_full = TOSH_sched_full;
  func = TOSH_queue[old_full].tp;
  if (func == NULL)
    {
      __nesc_atomic_end(fInterruptFlags);
      return 0;
    }
TOSH_queue[old_full].tp = NULL;
  TOSH_sched_full = (old_full + 1) & TOSH_TASK_BITMASK;
  __nesc_atomic_end(fInterruptFlags);
  func();

  return 1;
}

     这个函数稍为比增加元素那个函数复杂一点点,不过也很简单!
    首先是取出队列元素里的值:
void (*func)(void);
old_full = TOSH_sched_full;
func = TOSH_queue[old_full].tp;
      就是这三个语句了!声明一个变量,到最后赋值。
      接着语句if (func == NULL),判断取出的元素的值是否为空,如果不为空则首先将取出值的原来那个位置清零(TOSH_queue[old_full].tp = NULL;),然后将头指针向后移动(TOSH_sched_full = (old_full + 1) & TOSH_TASK_BITMASK;),最后执行这个函数:
fun();

       完了,这个队列简单到极点了吧?但有什么办法了,tinyos 1.x里,这个就是它的任务调度机制:FIFO,并且当队列满时不能够增加新的任务。Tinyos 2.x似乎有所改变。

         for(;;) { TOSH_run_task(); }这个语句就让tinyos(程序)一直跑到世界末日了!
void TOSH_run_task() {
  while (TOSH_run_next_task())
    ;
  TOSH_sleep();
TOSH_wait();
}
      这个函数就不废话了!
       从上面还可以看出,整个过程中并没有哪个语句调用bool TOS_post(void (*tp) ())函数,那么谁来增加任务队列中的任务呢?这里举个例子,大家可以转到tinyos-1.x\apps\BlinkTask\目录下,这个例子跟之前的Blink功能一样,不过是使用任务的,在BlinkTaskM.nc文件中Timer的fired事件中有一句:post processing()就将任务添加到任务队列中。换句话说,是应用程序或其它程序将任务添加到任务队列中。

好了!Main组件分析完了,大家对tinyos(程序)的启动、运行有了个大概了解了吧?

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客