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

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