Chinaunix首页 | 论坛 | 博客
  • 博客访问: 432215
  • 博文数量: 103
  • 博客积分: 1455
  • 博客等级: 上尉
  • 技术积分: 1380
  • 用 户 组: 普通用户
  • 注册时间: 2012-09-15 22:17
文章分类

全部博文(103)

文章存档

2013年(4)

2012年(99)

我的朋友

分类: LINUX

2012-11-15 16:34:38

在主函数中,创建完成了需要的task之后,是创建信号量,邮箱,消息队列等任务间通信的结构
这些结构拥有一个相同的特点,他们都需要时间控制块ECB和ECB查找表的支持,这个机制类似于最高优先级查找表,能够选出相应优先级对应的事件控制块是不是已经进入就绪,任务的就绪使用OSxxPost函数实现
我们来看一个完整的信号量的实现函数组
OSSemCreate

点击(此处)折叠或打开

  1. /*
  2. *********************************************************************************************************
  3. * CREATE A SEMAPHORE
  4. *
  5. * Description: This function creates a semaphore.
  6. *
  7. * Arguments : cnt is the initial value for the semaphore. If the value is 0, no resource is
  8. * available (or no event has occurred). You initialize the semaphore to a
  9. * non-zero value to specify how many resources are available (e.g. if you have
  10. * 10 resources, you would initialize the semaphore to 10).
  11. *
  12. * Returns : != (void *)0 is a pointer to the event control clock (OS_EVENT) associated with the
  13. * created semaphore
  14. * == (void *)0 if no event control blocks were available
  15. *********************************************************************************************************
  16. */

  17. OS_EVENT *OSSemCreate (INT16U cnt)
  18. {
  19.     OS_EVENT *pevent;
  20. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  21.     OS_CPU_SR cpu_sr = 0;
  22. #endif



  23.     if (OSIntNesting > 0) { /* See if called from ISR ... */
  24.         return ((OS_EVENT *)0); /* ... can't CREATE from an ISR */
  25.     }
  26.     OS_ENTER_CRITICAL();
  27.     pevent = OSEventFreeList; /* Get next free event control block */
  28.     if (OSEventFreeList != (OS_EVENT *)0) { /* See if pool of free ECB pool was empty */
  29.         OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr;
  30.     }
  31.     OS_EXIT_CRITICAL();
  32.     if (pevent != (OS_EVENT *)0) { /* Get an event control block */
  33.         pevent->OSEventType = OS_EVENT_TYPE_SEM;
  34.         pevent->OSEventCnt = cnt; /* Set semaphore value */
  35.         pevent->OSEventPtr = (void *)0; /* Unlink from ECB free list */
  36. #if OS_EVENT_NAME_SIZE > 1
  37.         pevent->OSEventName[0] = '?'; /* Unknown name */
  38.         pevent->OSEventName[1] = OS_ASCII_NUL;
  39. #endif
  40.         OS_EventWaitListInit(pevent); /* Initialize to 'nobody waiting' on sem. */
  41.     }
  42.     return (pevent);
  43. }

首先,这个函数有一个叫做cnt的参数,这表示初始化的资源数,或者事件发生数
如果初始化为0表示没有发生,没有资源,如果初始化为10,表示已经发生了10次?
下面是返回值,如果返回值为NULL说明没有初始化成功信号量
如果成功,返回一个非空的指针,指向初始化好的ECB
 
第一步,检测是否在中断嵌套中,如果在嵌套中则不能成功初始化,返回NULL
第二步,关中断,从链表OSEventFreeList的表头取得一个空ECB,赋值给*pevent
如果链表不是空链表,那么表头指针指向下一个ECB元素,将这个ECB贡献出来
第三步,开中断,如果这个ECB不是空,pevent不是NULL,对这个ECB进行初始化
pevent->OSEventType    = OS_EVENT_TYPE_SEM;//设置ECB类型为信号量
pevent->OSEventCnt     = cnt; /* Set semaphore value *///设置初始值为cnt参数
pevent->OSEventPtr     = (void *)0; /* Unlink from ECB free list *///将原本指向下一个ECB的指针指向空
第四步,写一个?进名字数组中
第五步,OS_EventWaitListInit初始化EventWaitList,每一个初始化了的ECB会对应一个EWL,对应的Post函数能够将ECB中的EWL的对应项置1,具体我们在Post函数中再看
函数OS_EventWaitListInit

点击(此处)折叠或打开

  1. /*
  2. *********************************************************************************************************
  3. * INITIALIZE EVENT CONTROL BLOCK'S WAIT LIST
  4. *
  5. * Description: This function is called by other uC/OS-II services to initialize the event wait list.
  6. *
  7. * Arguments : pevent is a pointer to the event control block allocated to the event.
  8. *
  9. * Returns : none
  10. *
  11. * Note : This function is INTERNAL to uC/OS-II and your application should not call it.
  12. *********************************************************************************************************
  13. */
  14. #if OS_EVENT_EN
  15. void OS_EventWaitListInit (OS_EVENT *pevent)
  16. {
  17. #if OS_LOWEST_PRIO <= 63
  18.     INT8U *ptbl;
  19. #else
  20.     INT16U *ptbl;
  21. #endif
  22.     INT8U i;


  23.     pevent->OSEventGrp = 0; /* No task waiting on event */
  24.     ptbl = &pevent->OSEventTbl[0];

  25.     for (i = 0; i < OS_EVENT_TBL_SIZE; i++) {
  26.         *ptbl++ = 0;
  27.     }
  28. }
  29. #endif
将EWL初始化为0和0数组
 
悬挂等待函数

点击(此处)折叠或打开

  1. /*
  2. *********************************************************************************************************
  3. * PEND ON SEMAPHORE
  4. *
  5. * Description: This function waits for a semaphore.
  6. *
  7. * Arguments : pevent is a pointer to the event control block associated with the desired
  8. * semaphore.
  9. *
  10. * timeout is an optional timeout period (in clock ticks). If non-zero, your task will
  11. * wait for the resource up to the amount of time specified by this argument.
  12. * If you specify 0, however, your task will wait forever at the specified
  13. * semaphore or, until the resource becomes available (or the event occurs).
  14. *
  15. * err is a pointer to where an error message will be deposited. Possible error
  16. * messages are:
  17. *
  18. * OS_NO_ERR The call was successful and your task owns the resource
  19. * or, the event you are waiting for occurred.
  20. * OS_TIMEOUT The semaphore was not received within the specified
  21. * timeout.
  22. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore.
  23. * OS_ERR_PEND_ISR If you called this function from an ISR and the result
  24. * would lead to a suspension.
  25. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  26. *
  27. * Returns : none
  28. *********************************************************************************************************
  29. */

  30. void OSSemPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
  31. {
  32. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  33.     OS_CPU_SR cpu_sr = 0;
  34. #endif



  35. #if OS_ARG_CHK_EN > 0
  36.     if (err == (INT8U *)0) { /* Validate 'err' */
  37.         return;
  38.     }
  39.     if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  40.         *err = OS_ERR_PEVENT_NULL;
  41.         return;
  42.     }
  43. #endif
  44.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  45.         *err = OS_ERR_EVENT_TYPE;
  46.         return;
  47.     }
  48.     if (OSIntNesting > 0) { /* See if called from ISR ... */
  49.         *err = OS_ERR_PEND_ISR; /* ... can't PEND from an ISR */
  50.         return;
  51.     }
  52.     if (OSLockNesting > 0) { /* See if called with scheduler locked ... */
  53.         *err = OS_ERR_PEND_LOCKED; /* ... can't PEND when locked */
  54.         return;
  55.     }
  56.     OS_ENTER_CRITICAL();
  57.     if (pevent->OSEventCnt > 0) { /* If sem. is positive, resource available ... */
  58.         pevent->OSEventCnt--; /* ... decrement semaphore only if positive. */
  59.         OS_EXIT_CRITICAL();
  60.         *err = OS_NO_ERR;
  61.         return;
  62.     }
  63.                                                       /* Otherwise, must wait until event occurs */
  64.     OSTCBCur->OSTCBStat |= OS_STAT_SEM; /* Resource not available, pend on semaphore */
  65.     OSTCBCur->OSTCBPendTO = OS_FALSE;
  66.     OSTCBCur->OSTCBDly = timeout; /* Store pend timeout in TCB */
  67.     OS_EventTaskWait(pevent); /* Suspend task until event or timeout occurs */
  68.     OS_EXIT_CRITICAL();
  69.     OS_Sched(); /* Find next highest priority task ready */
  70.     OS_ENTER_CRITICAL();
  71.     if (OSTCBCur->OSTCBPendTO == OS_TRUE) { /* See if we timedout */
  72.         OS_EventTO(pevent);
  73.         OS_EXIT_CRITICAL();
  74.         *err = OS_TIMEOUT; /* Indicate that didn't get event within TO */
  75.         return;
  76.     }
  77.     OSTCBCur->OSTCBEventPtr = (OS_EVENT *)0;
  78.     OS_EXIT_CRITICAL();
  79.     *err = OS_NO_ERR;
  80. }

我们可以看到这个函数有三个参数,一个ECB指针,一个timeout变量,一个err指针,木有返回值
ECB不用说,是我们要等待的信号量的ECB指针,timeout以系统tick为单位等待时间如果过长就返回一个TIMEOUT的错误在err指针里
*OS_NO_ERR           The call was successful and your task owns the resource
*                    or, the event you are waiting for occurred.
*OS_TIMEOUT          The semaphore was not received within the specified
*                    timeout.
*OS_ERR_EVENT_TYPE   If you didn't pass a pointer to a semaphore.
*OS_ERR_PEND_ISR     If you called this function from an ISR and the result
*                    would lead to a suspension.
*OS_ERR_PEVENT_NULL  If 'pevent' is a NULL pointer.
这是err返回值的选项!
 
第一步,检查err指针,检查ECB指针是否为NULL指针
第二步,检查pevent->OSEventType != OS_EVENT_TYPE_SEM 如果ECB的等待类型不是信号量,那就搞错了应当使用的函数,比如消息队列你可以用消息队列对应的pend函数
检查是否在IRQ中使用pend函数,不能再IRQ中使用pend,导致IRQ时间太长,而且嵌套,导致系统混乱
检查系统调度是否被锁定,如果被锁定也不能使用pend函数,如果使用pend函数,系统又不调度,那么系统将不再进入下一个task
第三步,关中断,如果cnt>0,cnt--,返回NO_ERR,开中断,结束
第四步,将当前的task设置进入等待delay状态
OSTCBCur->OSTCBStat   |= OS_STAT_SEM; /* Resource not available, pend on semaphore     */
OSTCBCur->OSTCBPendTO  = OS_FALSE;
OSTCBCur->OSTCBDly     = timeout; /* Store pend timeout in TCB    */
第五步,调用OS_EventTaskWait设置相应的EWL

点击(此处)折叠或打开

  1. /*
  2. *********************************************************************************************************
  3. * MAKE TASK WAIT FOR EVENT TO OCCUR
  4. *
  5. * Description: This function is called by other uC/OS-II services to suspend a task because an event has
  6. * not occurred.
  7. *
  8. * Arguments : pevent is a pointer to the event control block for which the task will be waiting for.
  9. *
  10. * Returns : none
  11. *
  12. * Note : This function is INTERNAL to uC/OS-II and your application should not call it.
  13. *********************************************************************************************************
  14. */
  15. #if OS_EVENT_EN
  16. void OS_EventTaskWait (OS_EVENT *pevent)
  17. {
  18.     INT8U y;


  19.     OSTCBCur->OSTCBEventPtr = pevent; /* Store pointer to event control block in TCB */
  20.     y = OSTCBCur->OSTCBY; /* Task no longer ready */
  21.     OSRdyTbl[y] &= ~OSTCBCur->OSTCBBitX;
  22.     if (OSRdyTbl[y] == 0) {
  23.         OSRdyGrp &= ~OSTCBCur->OSTCBBitY; /* Clear event grp bit if this was only task pending */
  24.     }
  25.     pevent->OSEventTbl[OSTCBCur->OSTCBY] |= OSTCBCur->OSTCBBitX; /* Put task in waiting list */
  26.     pevent->OSEventGrp |= OSTCBCur->OSTCBBitY;
  27. }
  28. #endif
完成三件事,第一,将事件等待指针,指向ECB,第二,将task就绪表中的相应位置为没有就绪
第三,将ECB中的wait list中task的相应位置为等待
 
第六步,关中断,调度,开中断。
第七步,如果OSTCBCur->OSTCBPendTO == OS_TRUE(time out),执行OS_EventTO(pevent);
反向清除TCB和ECB中的等待信息,清除EWL中task 相应位和等待指针,因为没有post处理
如果不是time out不需要进行TCB和ECB信息的清理,因为在POST函数中有处理
 
我们来看用post怎么解除ECB中的等待信息
他大爷
阅读(4484) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~