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

全部博文(103)

文章存档

2013年(4)

2012年(99)

我的朋友

分类: LINUX

2012-11-16 10:22:54


对于函数OSSemPend来说,会使当前TCB挂起,ECB中的EventWaitList置位,TCB中的事件等待指针指向相应的ECB
那么对于OSSemPost函数来说,就应该解除ECB中的EventWaitList置位,然后修改TCB,使相应的task进入rdy状态

点击(此处)折叠或打开

  1. /*
  2. *********************************************************************************************************
  3. * POST TO A SEMAPHORE
  4. *
  5. * Description: This function signals a semaphore
  6. *
  7. * Arguments : pevent is a pointer to the event control block associated with the desired
  8. * semaphore.
  9. *
  10. * Returns : OS_NO_ERR The call was successful and the semaphore was signaled.
  11. * OS_SEM_OVF If the semaphore count exceeded its limit. In other words, you have
  12. * signalled the semaphore more often than you waited on it with either
  13. * OSSemAccept() or OSSemPend().
  14. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore
  15. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  16. *********************************************************************************************************
  17. */

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



  23. #if OS_ARG_CHK_EN > 0
  24.     if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  25.         return (OS_ERR_PEVENT_NULL);
  26.     }
  27. #endif
  28.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  29.         return (OS_ERR_EVENT_TYPE);
  30.     }
  31.     OS_ENTER_CRITICAL();
  32.     if (pevent->OSEventGrp != 0) { /* See if any task waiting for semaphore*/
  33.         (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM); /* Ready HPT waiting on event */
  34.         OS_EXIT_CRITICAL();
  35.         OS_Sched(); /* Find HPT ready to run */
  36.         return (OS_NO_ERR);
  37.     }
  38.     if (pevent->OSEventCnt < 65535u) { /* Make sure semaphore will not overflow */
  39.         pevent->OSEventCnt++; /* Increment semaphore count to register event */
  40.         OS_EXIT_CRITICAL();
  41.         return (OS_NO_ERR);
  42.     }
  43.     OS_EXIT_CRITICAL(); /* Semaphore value has reached its maximum */
  44.     return (OS_SEM_OVF);
  45. }
参数是ECB指针,对这个ECB输入一个信号量
首先检测ECB指针是否为空
检测type是否是信号量
关中断,
检测EWL是否为0,如果为0,说明没有任务在等待信号量,cnt++并且返回NO_ERR
如果不为零检测最高优先级的任务并使任务得到信号量,函数OS_EventTaskRdy

点击(此处)折叠或打开

  1. /*
  2. *********************************************************************************************************
  3. * MAKE TASK READY TO RUN BASED ON EVENT OCCURING
  4. *
  5. * Description: This function is called by other uC/OS-II services and is used to ready a task that was
  6. * waiting for an event to occur.
  7. *
  8. * Arguments : pevent is a pointer to the event control block corresponding to the event.
  9. *
  10. * msg is a pointer to a message. This pointer is used by message oriented services
  11. * such as MAILBOXEs and QUEUEs. The pointer is not used when called by other
  12. * service functions.
  13. *
  14. * msk is a mask that is used to clear the status byte of the TCB. For example,
  15. * OSSemPost() will pass OS_STAT_SEM, OSMboxPost() will pass OS_STAT_MBOX etc.
  16. *
  17. * Returns : none
  18. *
  19. * Note : This function is INTERNAL to uC/OS-II and your application should not call it.
  20. *********************************************************************************************************
  21. */
  22. #if OS_EVENT_EN
  23. INT8U OS_EventTaskRdy (OS_EVENT *pevent, void *msg, INT8U msk)
  24. {
  25.     OS_TCB *ptcb;
  26.     INT8U x;
  27.     INT8U y;
  28.     INT8U prio;
  29. #if OS_LOWEST_PRIO <= 63
  30.     INT8U bitx;
  31.     INT8U bity;
  32. #else
  33.     INT16U bitx;
  34.     INT16U bity;
  35.     INT16U *ptbl;
  36. #endif


  37. #if OS_LOWEST_PRIO <= 63
  38.     y = OSUnMapTbl[pevent->OSEventGrp]; /* Find HPT waiting for message */
  39.     bity = (INT8U)(1 << y);
  40.     x = OSUnMapTbl[pevent->OSEventTbl[y]];
  41.     bitx = (INT8U)(1 << x);
  42.     prio = (INT8U)((y << 3) + x); /* Find priority of task getting the msg */
  43. #else
  44.     if ((pevent->OSEventGrp & 0xFF) != 0) { /* Find HPT waiting for message */
  45.         y = OSUnMapTbl[pevent->OSEventGrp & 0xFF];
  46.     } else {
  47.         y = OSUnMapTbl[(pevent->OSEventGrp >> 8) & 0xFF] + 8;
  48.     }
  49.     bity = (INT16U)(1 << y);
  50.     ptbl = &pevent->OSEventTbl[y];
  51.     if ((*ptbl & 0xFF) != 0) {
  52.         x = OSUnMapTbl[*ptbl & 0xFF];
  53.     } else {
  54.         x = OSUnMapTbl[(*ptbl >> 8) & 0xFF] + 8;
  55.     }
  56.     bitx = (INT16U)(1 << x);
  57.     prio = (INT8U)((y << 4) + x); /* Find priority of task getting the msg */
  58. #endif

  59.     pevent->OSEventTbl[y] &= ~bitx; /* Remove this task from the waiting list */
  60.     if (pevent->OSEventTbl[y] == 0) {
  61.         pevent->OSEventGrp &= ~bity; /* Clr group bit if this was only task pending */
  62.     }
  63.     ptcb = OSTCBPrioTbl[prio]; /* Point to this task's OS_TCB */
  64.     ptcb->OSTCBDly = 0; /* Prevent OSTimeTick() from readying task */
  65.     ptcb->OSTCBEventPtr = (OS_EVENT *)0; /* Unlink ECB from this task */
  66. #if ((OS_Q_EN > 0) && (OS_MAX_QS > 0)) || (OS_MBOX_EN > 0)
  67.     ptcb->OSTCBMsg = msg; /* Send message directly to waiting task */
  68. #else
  69.     msg = msg; /* Prevent compiler warning if not used */
  70. #endif
  71.     ptcb->OSTCBPendTO = OS_FALSE; /* Cancel 'any' timeout because of post */
  72.     ptcb->OSTCBStat &= ~msk; /* Clear bit associated with event type */
  73.     if (ptcb->OSTCBStat == OS_STAT_RDY) { /* See if task is ready (could be susp'd) */
  74.         OSRdyGrp |= bity; /* Put task in the ready to run list */
  75.         OSRdyTbl[y] |= bitx;
  76.     }
  77.     return (prio);
  78. }
  79. #endif

这个函数有三个参数,第一个是ECB,第二个是指向信号内容的指针,只在信号是消息邮箱或者消息队列的时候才有用,第三个是TCB中的stat信号
木有返回值
第一步,通过EWL查找到最高优先级等待任务,求出其优先级prio
第二步,将这个task从EWL中移除
第三步。找到这个prio的TCB,并将其中的delaytime置0,将event连接指针指向NULL
第四步,如果是消息邮箱,消息队列,那么将msg赋值给TCB中的msg指针,否则不使用这个msg参数
第五步,将TCB中的pendto置为false,表示不是timeout结束的等待,将stat等待的sem位清除,其余保持不变
第六步,将就绪表中的prio位置1,并返回prio
完成这个函数之后回到Post主函数中,主函数开中断,并进入调度函数
 
我们来看另外一种不同于pend的非等待信号接收函数accept,他们的不同在于,一个进入调度,而另一个不进入

点击(此处)折叠或打开

  1. /*
  2. *********************************************************************************************************
  3. * ACCEPT SEMAPHORE
  4. *
  5. * Description: This function checks the semaphore to see if a resource is available or, if an event
  6. * occurred. Unlike OSSemPend(), OSSemAccept() does not suspend the calling task if the
  7. * resource is not available or the event did not occur.
  8. *
  9. * Arguments : pevent is a pointer to the event control block
  10. *
  11. * Returns : > 0 if the resource is available or the event did not occur the semaphore is
  12. * decremented to obtain the resource.
  13. * == 0 if the resource is not available or the event did not occur or,
  14. * if 'pevent' is a NULL pointer or,
  15. * if you didn't pass a pointer to a semaphore
  16. *********************************************************************************************************
  17. */

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



  25. #if OS_ARG_CHK_EN > 0
  26.     if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  27.         return (0);
  28.     }
  29. #endif
  30.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  31.         return (0);
  32.     }
  33.     OS_ENTER_CRITICAL();
  34.     cnt = pevent->OSEventCnt;
  35.     if (cnt > 0) { /* See if resource is available */
  36.         pevent->OSEventCnt--; /* Yes, decrement semaphore and notify caller */
  37.     }
  38.     OS_EXIT_CRITICAL();
  39.     return (cnt); /* Return semaphore count */
  40. }
  41. #endif

这个函数只有一个参数ECB,pend有三个参数,一个ECB表示信号,一个timeout限制等待时间,一个err返回错误
检测是否为空指针参数,检测eventtype是不是sem
取得ECB中的cnt计数值,检测是否大于0,如果大于0 则--,函数返回cnt自减之前的值。
 
删除一个信号量ECB的函数

点击(此处)折叠或打开

  1. /*
  2. *********************************************************************************************************
  3. * DELETE A SEMAPHORE
  4. *
  5. * Description: This function deletes a semaphore and readies all tasks pending on the semaphore.
  6. *
  7. * Arguments : pevent is a pointer to the event control block associated with the desired
  8. * semaphore.
  9. *
  10. * opt determines delete options as follows:
  11. * opt == OS_DEL_NO_PEND Delete semaphore ONLY if no task pending
  12. * opt == OS_DEL_ALWAYS Deletes the semaphore even if tasks are waiting.
  13. * In this case, all the tasks pending will be readied.
  14. *
  15. * err is a pointer to an error code that can contain one of the following values:
  16. * OS_NO_ERR The call was successful and the semaphore was deleted
  17. * OS_ERR_DEL_ISR If you attempted to delete the semaphore from an ISR
  18. * OS_ERR_INVALID_OPT An invalid option was specified
  19. * OS_ERR_TASK_WAITING One or more tasks were waiting on the semaphore
  20. * OS_ERR_EVENT_TYPE If you didn't pass a pointer to a semaphore
  21. * OS_ERR_PEVENT_NULL If 'pevent' is a NULL pointer.
  22. *
  23. * Returns : pevent upon error
  24. * (OS_EVENT *)0 if the semaphore was successfully deleted.
  25. *
  26. * Note(s) : 1) This function must be used with care. Tasks that would normally expect the presence of
  27. * the semaphore MUST check the return code of OSSemPend().
  28. * 2) OSSemAccept() callers will not know that the intended semaphore has been deleted unless
  29. * they check 'pevent' to see that it's a NULL pointer.
  30. * 3) This call can potentially disable interrupts for a long time. The interrupt disable
  31. * time is directly proportional to the number of tasks waiting on the semaphore.
  32. * 4) Because ALL tasks pending on the semaphore will be readied, you MUST be careful in
  33. * applications where the semaphore is used for mutual exclusion because the resource(s)
  34. * will no longer be guarded by the semaphore.
  35. *********************************************************************************************************
  36. */

  37. #if OS_SEM_DEL_EN > 0
  38. OS_EVENT *OSSemDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
  39. {
  40.     BOOLEAN tasks_waiting;
  41.     OS_EVENT *pevent_return;
  42. #if OS_CRITICAL_METHOD == 3 /* Allocate storage for CPU status register */
  43.     OS_CPU_SR cpu_sr = 0;
  44. #endif



  45. #if OS_ARG_CHK_EN > 0
  46.     if (err == (INT8U *)0) { /* Validate 'err' */
  47.         return (pevent);
  48.     }
  49.     if (pevent == (OS_EVENT *)0) { /* Validate 'pevent' */
  50.         *err = OS_ERR_PEVENT_NULL;
  51.         return (pevent);
  52.     }
  53. #endif
  54.     if (pevent->OSEventType != OS_EVENT_TYPE_SEM) { /* Validate event block type */
  55.         *err = OS_ERR_EVENT_TYPE;
  56.         return (pevent);
  57.     }
  58.     if (OSIntNesting > 0) { /* See if called from ISR ... */
  59.         *err = OS_ERR_DEL_ISR; /* ... can't DELETE from an ISR */
  60.         return (pevent);
  61.     }
  62.     OS_ENTER_CRITICAL();
  63.     if (pevent->OSEventGrp != 0) { /* See if any tasks waiting on semaphore */
  64.         tasks_waiting = OS_TRUE; /* Yes */
  65.     } else {
  66.         tasks_waiting = OS_FALSE; /* No */
  67.     }
  68.     switch (opt) {
  69.         case OS_DEL_NO_PEND: /* Delete semaphore only if no task waiting */
  70.              if (tasks_waiting == OS_FALSE) {
  71. #if OS_EVENT_NAME_SIZE > 1
  72.                  pevent->OSEventName[0] = '?'; /* Unknown name */
  73.                  pevent->OSEventName[1] = OS_ASCII_NUL;
  74. #endif
  75.                  pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  76.                  pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
  77.                  pevent->OSEventCnt = 0;
  78.                  OSEventFreeList = pevent; /* Get next free event control block */
  79.                  OS_EXIT_CRITICAL();
  80.                  *err = OS_NO_ERR;
  81.                  pevent_return = (OS_EVENT *)0; /* Semaphore has been deleted */
  82.              } else {
  83.                  OS_EXIT_CRITICAL();
  84.                  *err = OS_ERR_TASK_WAITING;
  85.                  pevent_return = pevent;
  86.              }
  87.              break;

  88.         case OS_DEL_ALWAYS: /* Always delete the semaphore */
  89.              while (pevent->OSEventGrp != 0) { /* Ready ALL tasks waiting for semaphore */
  90.                  (void)OS_EventTaskRdy(pevent, (void *)0, OS_STAT_SEM);
  91.              }
  92. #if OS_EVENT_NAME_SIZE > 1
  93.              pevent->OSEventName[0] = '?'; /* Unknown name */
  94.              pevent->OSEventName[1] = OS_ASCII_NUL;
  95. #endif
  96.              pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
  97.              pevent->OSEventPtr = OSEventFreeList; /* Return Event Control Block to free list */
  98.              pevent->OSEventCnt = 0;
  99.              OSEventFreeList = pevent; /* Get next free event control block */
  100.              OS_EXIT_CRITICAL();
  101.              if (tasks_waiting == OS_TRUE) { /* Reschedule only if task(s) were waiting */
  102.                  OS_Sched(); /* Find highest priority task ready to run */
  103.              }
  104.              *err = OS_NO_ERR;
  105.              pevent_return = (OS_EVENT *)0; /* Semaphore has been deleted */
  106.              break;

  107.         default:
  108.              OS_EXIT_CRITICAL();
  109.              *err = OS_ERR_INVALID_OPT;
  110.              pevent_return = pevent;
  111.              break;
  112.     }
  113.     return (pevent_return);
  114. }
  115. #endif
 
该函数有三个参数,第一是ECB,第二是opt选项,有两个选项,一个是只有不等待时才删除该信号量,另一个是always删除,第三个参数是err
第一步,检测err指针和ECB指针
第二部,检测type是不是sem
第三步,检测是否在中断嵌套中
第四步,关中断,检查EWL是否还有task在等待,一个switch语句,如果opt是非等待删除,并且没有等待task,将ECB清除并加入eventfreelist中,如果有task在等待,返回错误跳出。
如果opt是直接删除,如果有task在等待,先要将所等待的task置为rdy,再清除ECB,类似初始化ECB,然后进入调度函数,返回NULL说明删除成功,否则返回TCB
如果没有task等待
阅读(3172) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~