本文档可作为Linux驱动源码或库源码快速移植至SylixOS的参考。
2. 互斥信号量2.1 概念简介
互斥信号量(Linux中亦称为互斥锁)是因为多线程对临界区访问而存在的。只有拥有互斥对象的线程才具有访问资源的权限,当前占据资源的线程在任务处理完后应将拥有的互斥对象交出,以便其他线程在获得后得以访问资源。
互斥信号量可以理解为初始值为TRUE的带优先级天花板和优先级继承机制(意在解决优先级反转问题)的二进制信号量。
因为互斥信号量需要记录拥有者线程和调整优先级,所以中断服务程序不能等待和释放互斥信号量,并且只有互斥信号量的拥有者线程才有权释放互斥信号量。
2.2 Linux接口与SylixOS接口对应关系
Linux中操作互斥信号量的API与SylixOS中操作互斥信号量的API对应关系如表 2-1所示。
表 2-1互斥信号量接口对应关系
Linux中接口 | SylixOS中接口 | 功能说明 |
mutex_init | API_SemaphoreMCreate | 创建互斥信号量 |
mutex_destroy | API_SemaphoreMDelete | 销毁互斥信号量 |
mutex_lock | API_SemaphoreMPend | 阻塞申请互斥信号量 |
mutex_trylock | API_SemaphoreMPend | 非阻塞申请互斥信号量 |
mutex_unlock | API_SemaphoreMPost | 释放互斥信号量 |
mutex_is_locked | API_SemaphoreMStatus | 判断互斥信号量状态 |
3. 详细说明
3.1 互斥信号量结构
在Linux中互斥信号量是使用struct mutex表示的,结构如程序清单 3-1所示,而在SylixOS中,互斥信号量是通过LW_HANDLE类型的互斥信号量句柄表示。
程序清单 3-1 Linux的struct mutex结构
struct mutex { /* 1: unlocked, 0: locked, negative: locked, possible waiters */ atomic_t count; spinlock_t wait_lock; struct list_head wait_list; #if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_SMP) struct task_struct *owner; #endif #ifdef CONFIG_MUTEX_SPIN_ON_OWNER void *spin_mlock; #endif #ifdef CONFIG_DEBUG_MUTEXES const char *name; void *magic; #endif #ifdef CONFIG_DEBUG_LOCK_ALLOC struct lockdep_map dep_map; #endif };
3.2 创建互斥信号量
Linux : void mutex_init (struct mutex *mutex); SylixOS: LW_HANDLE Lw_SemaphoreM_Create (CPCHAR pcName, UINT8 ucCeilingPriority, ULONG ulOption, LW_OBJECT_ID *pulId);
Linux:
创建一个互斥信号量只需要定义一个struct mutex变量并调用mutex_init即可,Linux系统会自己为mutex命名。
创建成功后,申请和释放互斥信号量时可以直接使用该已定义的mutex变量。
SylixOS:
创建互斥信号量时需要指定信号量的名称,并且手动设置选项。
创建成功后,申请和释放互斥信号量时需要使用Lw_SemaphoreM_Create返回的信号量句柄。
3.3 销毁互斥信号量
Linux : void mutex_init (struct mutex *mutex); SylixOS: LW_HANDLE Lw_SemaphoreM_Create (CPCHAR pcName, UINT8 ucCeilingPriority, ULONG ulOption, LW_OBJECT_ID *pulId);
Linux:
销毁一个互斥信号量是将mutex变量的地址传入。
SylixOS:
销毁一个互斥信号量是将互斥信号量句柄地址传入。
3.4 阻塞申请互斥信号量
Linux : void mutex_lock (struct mutex *mutex); SylixOS: ULONG Lw_SemaphoreM_Wait (LW_HANDLE ulId, ULONG ulTimeout);
Linux:
mutex_lock的基本逻辑为:如果互斥锁可以获得,则直接获取,跳出;否则进入循环反复测试互斥锁的状态。
在循环中,判断如果可以获取到互斥锁,则退出循环;否则设置当前进程的状态为不可中断状态,解锁自身的自旋锁,进入睡眠状态。待被调度唤醒时,再获得自身的自旋锁,进入新一次的查询其自身状态(该互斥锁的状态)的循环。
SylixOS:
如果将参数ulTimeout设置为LW_OPTION_WAIT_INFINITE,则使用效果和Linux的mutex_lock相同。
3.5 非阻塞申请互斥信号量
Linux : int mutex_trylock (struct mutex *mutex); SylixOS: ULONG Lw_SemaphoreM_Wait (LW_HANDLE ulId, ULONG ulTimeout);
Linux:
mutex_trylock用于不等待地尝试获取互斥锁,如果成功获取则返回1,否则返回0,不等待。
SylixOS:
将ulTimeout设置为LW_OPTION_NOT_WAIT,则使用效果和mutex_trylock相同。
3.6 释放互斥信号量
Linux : int mutex_unlock (struct mutex *mutex); SylixOS: ULONG Lw_SemaphoreM_Post (LW_HANDLE ulId);
Linux:
释放一个互斥信号量是将mutex变量的地址传入。
SylixOS:
销毁一个互斥信号量是将互斥信号量句柄传入。
3.7 判断互斥信号量状态
Linux : int mutex_is_locked (struct mutex *mutex); SylixOS: ULONG Lw_SemaphoreM_Status (LW_HANDLE ulId, BOOL *pbValue, ULONG *pulOption, ULONG *pulThreadBlockNum); ULONG Lw_SemaphoreM_StatusEx (LW_HANDLE ulId, BOOL *pbValue, ULONG *pulOption, ULONG *pulThreadBlockNum, LW_HANDLE *pulOwnerId);
Linux:
mutex_is_locked可以返回一个mutex当前状态,返回1表示互斥量已经被申请,0则表示未被申请。
SylixOS:
获取互斥量的当前状态,需要使用Lw_SemaphoreM_Status或Lw_SemaphoreM_StatusEx接口。这两个函数参数pbValue可以返回当前互斥信号量的状态。
本文章说明了Linux驱动源码或库源码中使用到互斥信号量时,怎样快速移植到SylixOS中,并没有详细讲解各接口实现时原理有何不同,目前这种替换关系已经在移植gpu库时采用。