鸿蒙内核源码分析(自旋锁篇) | 汇编到令人心碎的自旋锁

    搜索 @note_pic 可查看绘制的全部字符图
    搜索 @note_why 是尚未看明白的地方,有看明白的,请Pull Request完善
    搜索 @note_thinking 是一些的思考和建议
    搜索 @note_#if0 是由第三方项目提供不在内核源码中定义的极为重要结构体,为方便理解而添加的。
    搜索 @note_good 是给源码点赞的地方
    公众号: 鸿蒙内核源码分析
上级 fce5ba8f
此差异已折叠。
......@@ -349,31 +349,34 @@ OsIrqContextRestoreToKernel:
ADD SP, SP, #4
LDMFD SP!, {PC}^
FUNCTION(ArchSpinLock)
mov r1, #1
1:
ldrex r2, [r0]
cmp r2, #0
wfene
strexeq r2, r1, [r0]
cmpeq r2, #0
bne 1b
dmb
bx lr
FUNCTION(ArchSpinTrylock)
mov r1, #1
mov r2, r0
ldrex r0, [r2]
cmp r0, #0
strexeq r0, r1, [r2]
dmb
bx lr
FUNCTION(ArchSpinUnlock)
mov r1, #0
dmb
str r1, [r0]
dsb
sev
bx lr
FUNCTION(ArchSpinLock) @对变量上锁
mov r1, #1 @r1=1
1: @循环的作用,因SEV是广播事件.不一定lock->rawLock的值已经改变了
ldrex r2, [r0] @r0 = &lock->rawLock, r2 = lock->rawLock
cmp r2, #0 @r20比较
wfene @不相等时,说明资源被占用,CPU核进入睡眠状态
strexeq r2, r1, [r0]@此时CPU被重新唤醒,尝试令lock->rawLock=1,成功写入则r2=0
cmpeq r2, #0 @再来比较r2是否等于0,如果相等则获取到了锁
bne 1b @如果不相等,继续进入循环
dmb @DMB指令来隔离,以保证缓冲中的数据已经落实到RAM
bx lr @此时是一定拿到锁了,跳回调用ArchSpinLock函数
FUNCTION(ArchSpinTrylock) @对变量尝试上锁
mov r1, #1 @r1=1
mov r2, r0 @r2 = r0
ldrex r0, [r2] @r2 = &lock->rawLock, r0 = lock->rawLock
cmp r0, #0 @r00比较
strexeq r0, r1, [r2] @尝试令lock->rawLock=1,成功写入则r0=0,否则 r0 =1
dmb @数据存储隔离,以保证缓冲中的数据已经落实到RAM
bx lr @跳回调用ArchSpinLock函数
FUNCTION(ArchSpinUnlock) @释放锁
mov r1, #0 @r1=0
dmb @数据存储隔离,以保证缓冲中的数据已经落实到RAM
str r1, [r0] @lock->rawLock = 0
dsb @数据同步隔离
sev @给各CPU广播事件,唤醒沉睡的CPU
bx lr @跳回调用ArchSpinLock函数
......@@ -63,7 +63,7 @@ extern "C" {
#endif /* __cplusplus */
/******************************************************************************
并发(Concurrent):多个线程在单个核心运行,同一时间一个线程运行,系统不停切换线程,
并发(Concurrent):多个线程在单个核心运行,同一时间只能一个线程运行,内核不停切换线程,
看起来像同时运行,实际上是线程不停切换
并行(Parallel)每个线程分配给独立的CPU核心,线程同时运行
单核CPU多个进程或多个线程内能实现并发(微观上的串行,宏观上的并行)
......
......@@ -936,7 +936,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskCreate(UINT32 *taskID, TSK_INIT_PARAM_S *in
if (initParam->uwResved & OS_TASK_FLAG_IDLEFLAG) {//OS_TASK_FLAG_IDLEFLAG 是属于内核 idle进程专用的
initParam->processID = OsGetIdleProcessID();//获取空闲进程
} else if (OsProcessIsUserMode(OsCurrProcessGet())) {//当前进程是否为用户模式
initParam->processID = OsGetKernelInitProcessID();//是就取"Kernel"进程
initParam->processID = OsGetKernelInitProcessID();//是就取"Kernel"进程
} else {
initParam->processID = OsCurrProcessGet()->processID;//获取当前进程 ID赋值
}
......@@ -1518,40 +1518,40 @@ LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskYield(VOID)
SCHEDULER_UNLOCK(intSave);
return LOS_OK;
}
//锁任务调度,但任务仍可被中断打断
//任务上锁
LITE_OS_SEC_TEXT_MINOR VOID LOS_TaskLock(VOID)
{
UINT32 intSave;
UINT32 *losTaskLock = NULL;
intSave = LOS_IntLock();//禁止所有IRQ和FIQ中断
losTaskLock = &OsPercpuGet()->taskLockCnt;//task lock 的计数器
(*losTaskLock)++;
losTaskLock = &OsPercpuGet()->taskLockCnt;//获取cpu 上锁任务数
(*losTaskLock)++;//任务上锁数量自增
LOS_IntRestore(intSave);//启用所有IRQ和FIQ中断
}
//解锁任务调度
//解锁任务
LITE_OS_SEC_TEXT_MINOR VOID LOS_TaskUnlock(VOID)
{
UINT32 intSave;
UINT32 *losTaskLock = NULL;
Percpu *percpu = NULL;
intSave = LOS_IntLock();
intSave = LOS_IntLock();//禁止所有IRQ和FIQ中断
percpu = OsPercpuGet();
losTaskLock = &OsPercpuGet()->taskLockCnt;
if (*losTaskLock > 0) {
(*losTaskLock)--;
percpu = OsPercpuGet();//获取当前CPU
losTaskLock = &OsPercpuGet()->taskLockCnt;//获取cpu 上锁任务数
if (*losTaskLock > 0) {//说明有存在上锁的任务
(*losTaskLock)--;//减少一个上锁任务
if ((*losTaskLock == 0) && (percpu->schedFlag == INT_PEND_RESCH) &&
OS_SCHEDULER_ACTIVE) {
percpu->schedFlag = INT_NO_RESCH;
LOS_IntRestore(intSave);
LOS_IntRestore(intSave);//启用所有IRQ和FIQ中断
LOS_Schedule();
return;
}
}
LOS_IntRestore(intSave);
LOS_IntRestore(intSave);//启用所有IRQ和FIQ中断
}
//获取任务信息,给shell使用的
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_TaskInfoGet(UINT32 taskID, TSK_INFO_S *taskInfo)
......
......@@ -85,11 +85,11 @@ extern VOID ArchSpinUnlock(size_t *lock);
extern INT32 ArchSpinTrylock(size_t *lock);
typedef struct Spinlock {
size_t rawLock;
#if (LOSCFG_KERNEL_SMP_LOCKDEP == YES)
UINT32 cpuid;
VOID *owner;
const CHAR *name;
size_t rawLock;//记录次数
#if (LOSCFG_KERNEL_SMP_LOCKDEP == YES) // 死锁检测模块开关
UINT32 cpuid; //持有锁的CPU
VOID *owner; //持有锁任务
const CHAR *name; //锁名称
#endif
} SPIN_LOCK_S;
......@@ -144,12 +144,12 @@ LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinLock(SPIN_LOCK_S *lock)
* disable the scheduler, so it won't do schedule untill
* scheduler is reenabled. The LOS_TaskUnlock should not
* be directly called along this critic area.
*/
LOS_TaskLock();
*/////调度被重新启用之前,禁止调度,LOS_TaskUnlock不能在这里被调用
LOS_TaskLock();//1.先告诉CPU有个任务要上锁
LOCKDEP_CHECK_IN(lock);
ArchSpinLock(&lock->rawLock);
LOCKDEP_RECORD(lock);
LOCKDEP_CHECK_IN(lock);//2.检查自旋锁
ArchSpinLock(&lock->rawLock);//3.自旋锁工作主体,一段汇编代码
LOCKDEP_RECORD(lock);//4.记录自旋锁
}
/**
......@@ -205,7 +205,7 @@ LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinUnlock(SPIN_LOCK_S *lock)
LOCKDEP_CHECK_OUT(lock);
ArchSpinUnlock(&lock->rawLock);//注意ArchSpinUnlock是一个汇编函数 见于 los_dispatch.s
/* restore the scheduler flag */
/* restore the scheduler flag */ //恢复调度标签
LOS_TaskUnlock();
}
......
git add -A
git commit -m '鸿蒙内核源码分析(进程概念篇) | 进程都管理了哪些资源? < CSDN | 开源中国 | WeHarmony >
git commit -m '鸿蒙内核源码分析(自旋锁篇) | 汇编到令人心碎的自旋锁
搜索 @note_pic 可查看绘制的全部字符图
搜索 @note_why 是尚未看明白的地方,有看明白的,请Pull Request完善
搜索 @note_thinking 是一些的思考和建议
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册