📄 os_mutex.c
字号:
/*
*********************************************************************************************************
* uC/OS-II 实时内核
* 信号量管理
*
* (c) 版权 1992-2002, 所有版权归Jean J. Labrosse, Weston, FL 所有
*
*
* 文件名称 : OS_MUTEX.C
* 程序作者 : Jean J. Labrosse
*********************************************************************************************************
*/
#ifndef OS_MASTER_FILE
#include "includes.h"
#endif
/*
*********************************************************************************************************
* 局部 变量
*********************************************************************************************************
*/
#define OS_MUTEX_KEEP_LOWER_8 0x00FF
#define OS_MUTEX_KEEP_UPPER_8 0xFF00
#define OS_MUTEX_AVAILABLE 0x00FF
#if OS_MUTEX_EN > 0
/*
*********************************************************************************************************
* 获得互斥型信号量
*
* 函数描述: 该函数检查互斥型信号量看资源是否有效。假如资源无效或事件未发生,不象OSMutexPend()函数,
* OSMutexAccept() 不会挂起调用的任务。
*
* 输入函数: pevent 指向ECB的指针
*
* err 返回到应用程序的出错代码指针:
* OS_NO_ERR 调用成功
* OS_ERR_EVENT_TYPE 'pevent' 不是一个指向 mutex 的指针
* OS_ERR_PEVENT_NULL 'pevent' 是一个空指针
* OS_ERR_PEND_ISR 如果调用来自ISR
*
* 返回值: == 1 如果资源有效,得到互斥型信号量
* == 0 a) 如果信号量无效的返回值
* b) 没有传递一个互斥型信号量的返回值
* c) 从ISR中调用该函数的返回值
*
* 警告: 因为互斥型信号量仅为任务所用,所以该函数不能从ISR 中调用。
*********************************************************************************************************
*/
#if OS_MUTEX_ACCEPT_EN > 0
INT8U OSMutexAccept (OS_EVENT *pevent, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3 /* 为CPU状态寄存器分配存储变量 */
OS_CPU_SR cpu_sr;
#endif
if (OSIntNesting > 0)
{ /* 确信没有从 ISR 中调用 */
*err = OS_ERR_PEND_ISR;
return (0);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0)
{ /* 无效的 'pevent' */
*err = OS_ERR_PEVENT_NULL;
return (0);
}
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX)
{ /* 无效的事件控制块型 */
*err = OS_ERR_EVENT_TYPE;
return (0);
}
#endif
OS_ENTER_CRITICAL(); /* 得到互斥型的值(0或1) */
if ((pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE)
{
pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8; /* 屏蔽低字节 (得到互斥值) */
pevent->OSEventCnt |= OSTCBCur->OSTCBPrio; /* 在低字节中保存任务优先级 */
pevent->OSEventPtr = (void *)OSTCBCur; /* 链接占有互斥值的任务的TCB */
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return (1);
}
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return (0);
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
* 建立一个互斥型信号量
*
* 函数描述: 该函数建立一个互斥型信号量
*
* 输入参数 : prio 访问互斥型信号量时使用的优先级。换句话说,当信号量被使用时,一个更高的优先级
* 任务想得到该信号量,那么,占有该信号量的任务被提升到该优先级。它在数值上应是
* 所有竞争此互斥型信号量的任务当中,值最小的,也就是优先级最高的。
*
* err 返回到应用程序的出错代码的指针:
* OS_NO_ERR 如果调用成功
* OS_ERR_CREATE_ISR 如果从ISR中创建一个互斥型信号量
* OS_PRIO_EXIST 如果PIP 的任务级已经存在。
* OS_ERR_PEVENT_NULL 没有可用的ECB
* OS_PRIO_INVALID 如果指定的优先级高于最大允许值。(例如 > OS_LOWEST_PRIO)
*
* 返回值 : != (void *)0 指向带有已建好的互斥型信号量的ECB的指针。
* == (void *)0 如果错误被删除
*
* 注释 : 1) '.OSEventCnt' 的低8位用于保存占有互斥型信号量任务的优先级号,或者没有任务占有时保存0XFF。
* 2) '.OSEventCnt' 的高8位用于保存降解优先级反转的优先级号。
*********************************************************************************************************
*/
OS_EVENT *OSMutexCreate (INT8U prio, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3 /* 为CPU状态寄存器分配存储变量 */
OS_CPU_SR cpu_sr;
#endif
OS_EVENT *pevent;
if (OSIntNesting > 0)
{ /* 看是否从 ISR中调用? ... */
*err = OS_ERR_CREATE_ISR; /* ... 从ISR中不能建立一个互斥型信号量 */
return ((OS_EVENT *)0);
}
#if OS_ARG_CHK_EN > 0
if (prio >= OS_LOWEST_PRIO)
{ /* 无效的 PIP */
*err = OS_PRIO_INVALID;
return ((OS_EVENT *)0);
}
#endif
OS_ENTER_CRITICAL();
if (OSTCBPrioTbl[prio] != (OS_TCB *)0)
{ /* 互斥型信号量的优先级不能已经存在 */
OS_EXIT_CRITICAL(); /* 任务的优先级已经存在 ... */
*err = OS_PRIO_EXIST; /* ... 继承优先级 */
return ((OS_EVENT *)0);
}
OSTCBPrioTbl[prio] = (OS_TCB *)1; /* 保留优先级 */
pevent = OSEventFreeList; /* 得到ECB */
if (pevent == (OS_EVENT *)0)
{ /* 看ECB是否有效? */
OSTCBPrioTbl[prio] = (OS_TCB *)0; /* 无效, 释放优先级 */
OS_EXIT_CRITICAL();
*err = OS_ERR_PEVENT_NULL; /* 没有空余的ECB */
return (pevent);
}
OSEventFreeList = (OS_EVENT *)OSEventFreeList->OSEventPtr; /* 调整空余事件链表指针 */
OS_EXIT_CRITICAL();
pevent->OSEventType = OS_EVENT_TYPE_MUTEX;
pevent->OSEventCnt = (prio << 8) | OS_MUTEX_AVAILABLE;/* 资源有效 */
pevent->OSEventPtr = (void *)0; /* 没有任务占用互斥型信号量 */
OS_EventWaitListInit(pevent);
*err = OS_NO_ERR;
return (pevent);
}
/*$PAGE*/
/*
*********************************************************************************************************
* 删除一个互斥型信号量
*
* 函数描述: 该函数删除一个互斥型信号量以及就绪所有挂起的任务。
*
* 输入参数 : pevent 指向带有期望的互斥型信号量的ECB的指针。
*
* opt 决定删除的选择项:
* opt == OS_DEL_NO_PEND 没有任务挂起时,才删除互斥型信号量。
* opt == OS_DEL_ALWAYS 即使任务在等待,也要删除互斥型信号量。
* 该种情形下,所有挂起的任务都将就绪。
*
* err 包含指向下列值之一的出错代码的指针:
* OS_NO_ERR 调用成功,互斥型信号量被删除
* OS_ERR_DEL_ISR 试图从 ISR 中删除互斥型信号量
* OS_ERR_INVALID_OPT 指定的为无效选项
* OS_ERR_TASK_WAITING 一个或更多的任务正在等待互斥型信号量
* OS_ERR_EVENT_TYPE 没有传递一个指向互斥型信号量的指针
* OS_ERR_PEVENT_NULL 'pevent'是空指针
*
* 返回值 : pevent 以上出错代码
* (OS_EVENT *)0 如果互斥型信号量被成功删除
*
* 注释 : 1) 该函数一定要小心使用. 期望信号量的任务一定要检查OSMutexPend()的返回值。
* 2) 这种调用潜在地关闭中断很长时间。中断关闭时间直接正比于等待互斥型信号量的任务的数量。
* 3) 由于所有等待互斥型信号量的任务将被就绪,所以必须谨慎,因为资源不在被互斥型信号量保护。
*********************************************************************************************************
*/
#if OS_MUTEX_DEL_EN
OS_EVENT *OSMutexDel (OS_EVENT *pevent, INT8U opt, INT8U *err)
{
#if OS_CRITICAL_METHOD == 3 /* 为CPU状态寄存器分配存储变量 */
OS_CPU_SR cpu_sr;
#endif
BOOLEAN tasks_waiting;
INT8U pip;
if (OSIntNesting > 0)
{ /* 看是否从 ISR中调用? ... */
*err = OS_ERR_DEL_ISR; /* ... 从ISR中不能删除一个互斥型信号量 */
return (pevent);
}
#if OS_ARG_CHK_EN > 0
if (pevent == (OS_EVENT *)0)
{ /* 无效的 'pevent' */
*err = OS_ERR_PEVENT_NULL;
return ((OS_EVENT *)0);
}
if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX)
{ /* 无效的ECB型 */
*err = OS_ERR_EVENT_TYPE;
return (pevent);
}
#endif
OS_ENTER_CRITICAL();
if (pevent->OSEventGrp != 0x00)
{ /* 看是否有任务等待互斥型信号量? */
tasks_waiting = TRUE; /* 是 */
}
else
{
tasks_waiting = FALSE; /* 没有 */
}
switch (opt)
{
case OS_DEL_NO_PEND: /* 只在没有等待的任务时,才删除互斥型信号量 */
if (tasks_waiting == FALSE)
{
pip = (INT8U)(pevent->OSEventCnt >> 8);
OSTCBPrioTbl[pip] = (OS_TCB *)0; /* 置空PIP */
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent->OSEventPtr = OSEventFreeList; /* 把ECB返回到空余链表 */
OSEventFreeList = pevent;
OS_EXIT_CRITICAL();
*err = OS_NO_ERR;
return ((OS_EVENT *)0); /* 互斥型信号量被删除 */
}
else
{
OS_EXIT_CRITICAL();
*err = OS_ERR_TASK_WAITING;
return (pevent);
}
case OS_DEL_ALWAYS: /* 即使任务正在等待,也要删除互斥型信号量 */
while (pevent->OSEventGrp != 0x00) /* 就绪所有等待互斥型信号量的任务 */
{
OS_EventTaskRdy(pevent, (void *)0, OS_STAT_MUTEX);
}
pip = (INT8U)(pevent->OSEventCnt >> 8);
OSTCBPrioTbl[pip] = (OS_TCB *)0; /* 置空PIP */
pevent->OSEventType = OS_EVENT_TYPE_UNUSED;
pevent->OSEventPtr = OSEventFreeList; /* 把ECB返回到空余链表 */
OSEventFreeList = pevent;
OS_EXIT_CRITICAL();
if (tasks_waiting == TRUE)
{ /* 只有任务等待时才可调度 */
OS_Sched(); /* 寻找最高优先级就绪运行 */
}
*err = OS_NO_ERR;
return ((OS_EVENT *)0); /* 互斥型信号量被删除 */
default:
OS_EXIT_CRITICAL();
*err = OS_ERR_INVALID_OPT;
return (pevent);
}
}
#endif
/*$PAGE*/
/*
*********************************************************************************************************
* 挂起互斥型信号量
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -