提交 f2d53dd8 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

开始对信号量这块代码进行注释,信号量的出现为了解决task的同步问题

鸿蒙内核源码分析系列 【 CSDN | OSCHINA | WIKI 】
鸿蒙内核源码注释中文版 【 CSDN仓 | Gitee仓 | Github仓 | Coding仓 】四大仓库每日同步更新代码和wiki
给鸿蒙内核源码逐行加上中文注解,详细阐述设计细节, 助你快速精读 HarmonyOS 内核源码, 掌握整个鸿蒙内核运行机制.
上级 c7eee5a9
[鸿蒙内核源码注释中文版 【 Gitee仓](https://gitee.com/weharmony/kernel_liteos_a_note) | [CSDN仓](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [Github仓](https://github.com/kuangyufei/kernel_liteos_a_note) | [Coding仓 】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files) 给 HarmonyOS 源码逐行加上中文注解,详细阐述设计细节, 助你快速精读 HarmonyOS 内核源码, 掌握整个鸿蒙内核运行机制,四大码仓和wiki每日同步更新.
[鸿蒙内核源码注释中文版 【 Gitee仓 ](https://gitee.com/weharmony/kernel_liteos_a_note) | [ CSDN仓 ](https://codechina.csdn.net/kuangyufei/kernel_liteos_a_note) | [ Github仓 ](https://github.com/kuangyufei/kernel_liteos_a_note) | [ Coding仓 】](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files) 给 HarmonyOS 源码逐行加上中文注解,详细阐述设计细节, 助你快速精读 HarmonyOS 内核源码, 掌握整个鸿蒙内核运行机制,四大码仓和wiki每日同步更新.
[鸿蒙源码分析系列篇 【 CSDN](https://blog.csdn.net/kuangyufei/article/details/108727970) [| OSCHINA](https://my.oschina.net/u/3751245/blog/4626852) [| WIKI 】](https://gitee.com/weharmony/kernel_liteos_a_note/wikis/pages) 从 HarmonyOS 架构层视角整理成文, 并首创用生活场景讲故事的方式试图去解构内核,一窥究竟。
[鸿蒙源码分析系列篇 【 CSDN ](https://blog.csdn.net/kuangyufei/article/details/108727970) [| OSCHINA ](https://my.oschina.net/u/3751245/blog/4626852) [| WIKI 】](https://gitee.com/weharmony/kernel_liteos_a_note/wikis/pages) 从 HarmonyOS 架构层视角整理成文, 并首创用生活场景讲故事的方式试图去解构内核,一窥究竟。
---
# **[kernel\_liteos\_a_note](https://gitee.com/weharmony/kernel_liteos_a_note): 鸿蒙内核源码注释中文版**
[![star](https://gitee.com/weharmony/kernel_liteos_a_note/badge/star.svg?theme=dark)](https://gitee.com/weharmony/kernel_liteos_a_note/stargazers)[![Fork me on Gitee](https://gitee.com/oschina/git-osc/widgets/widget_3.svg)](https://gitee.com/oschina/git-osc)[![fork](https://gitee.com/weharmony/kernel_liteos_a_note/badge/fork.svg?theme=dark)](https://gitee.com/weharmony/kernel_liteos_a_note/members)
每个码农,职业生涯,都应精读一遍内核源码. 鸿蒙内核源码就是很好的精读项目.一旦熟悉内核代码级实现,将迅速拔高对计算机整体理解,从此高屋建瓴看问题.
## **做了些什么呢**
**[kernel\_liteos\_a_note](https://gitee.com/weharmony/kernel_liteos_a_note)** 是在鸿蒙官方开源项目 **[OpenHarmony/kernel\_liteos\_a](https://gitee.com/openharmony/kernel_liteos_a)** 基础上给源码加上中文注解的版本,目前几大核心模块加注已基本完成,正持续加注完善中...
......@@ -52,11 +55,7 @@
- ### **新增的zzz目录是干什么的?**
中文加注版比官方版无新增文件,只多了一个zzz的目录,里面放了一些笔者使用的文件,它与内核代码无关,大家可以忽略它,取名zzz是为了排在最后,减少对原有代码目录级的侵入,zzz的想法源于微信中名称为AAA的那批牛人,你的微信里应该也有他们熟悉的身影吧 :|P
- ### **笔者联系方式**
邮箱: [kuangyufei@126.com](mailto:kuangyufei@126.com) 私信请不要问没有基础能不能学? 兴趣是最好的老师,有兴趣一定能成,什么是兴趣, 不是一两天的头脑发热而是每天吃饭睡觉都在想着这个事的. 更不要问如何看待 鸿蒙 PK Android ? 用了多少别人的源码之类的问题. 因为时间太宝贵, 大量的工作要完成. 不建议没经过深度思考就人云亦云,亦步亦趋. 如果非要纠结就想想QQ和微信的关系? 为何有了QQ还得有个微信,而且得由不同的BG来开发. 去翻翻微信刚出来那会有多少看不懂而质疑的声音. 笔者坚信鸿蒙未来一定可以很成功,誓做鸿蒙坚定的追随者和传播者.
中文加注版比官方版无新增文件,只多了一个zzz的目录,里面放了一些笔者使用的文件,它与内核代码无关,大家可以忽略它,取名zzz是为了排在最后,减少对原有代码目录级的侵入,zzz的想法源于微信中名称为AAA的那批牛人,你的微信里应该也有他们熟悉的身影吧 :|P
- ### **既然选择了远方,就不要怕天高路远,行动起来!**
......
......@@ -1363,7 +1363,7 @@ UINT32 OsTaskWait(LOS_DL_LIST *list, UINT32 timeout, BOOL needSched)
runTask->taskStatus |= OS_TASK_STATUS_PEND;//给任务贴上阻塞任务标签
LOS_ListTailInsert(list, pendObj);//将阻塞任务挂到list上,,这步很关键,很重要!
if (timeout != LOS_WAIT_FOREVER) {//非永远等待的时候
runTask->taskStatus |= OS_TASK_STATUS_PEND_TIME;//阻塞任务再贴上一段时间内阻塞
runTask->taskStatus |= OS_TASK_STATUS_PEND_TIME;//阻塞任务再贴上在一段时间内阻塞的标签
OsAdd2TimerList(runTask, timeout);//把任务加到定时器链表中
}
......
......@@ -45,11 +45,11 @@ extern "C" {
* Semaphore control structure.
*/
typedef struct {
UINT8 semStat; /**< Semaphore state */
UINT16 semCount; /**< Number of available semaphores */
UINT16 maxSemCount; /**< Max number of available semaphores */
UINT32 semID; /**< Semaphore control structure ID */
LOS_DL_LIST semList; /**< Queue of tasks that are waiting on a semaphore */
UINT8 semStat; /**< Semaphore state *///信号量的状态
UINT16 semCount; /**< Number of available semaphores *///有效信号量的数量
UINT16 maxSemCount; /**< Max number of available semaphores *///有效信号量的最大数量
UINT32 semID; /**< Semaphore control structure ID *///信号ID
LOS_DL_LIST semList; /**< Queue of tasks that are waiting on a semaphore *///等待信号量的任务队列,作为一个节点挂上去
} LosSemCB;
/**
......
......@@ -61,7 +61,7 @@ extern "C" {
#define SIGNAL_AFFI (1U << 2)
/* scheduler lock */
extern SPIN_LOCK_S g_taskSpin;
extern SPIN_LOCK_S g_taskSpin;//任务自旋锁
#define SCHEDULER_LOCK(state) LOS_SpinLockSave(&g_taskSpin, &(state))
#define SCHEDULER_UNLOCK(state) LOS_SpinUnlockRestore(&g_taskSpin, state)
......
......@@ -50,8 +50,8 @@ extern "C" {
#error "sem maxnum cannot be zero"
#endif /* LOSCFG_BASE_IPC_SEM_LIMIT <= 0 */
LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_unusedSemList;
LITE_OS_SEC_BSS LosSemCB *g_allSem = NULL;
LITE_OS_SEC_DATA_INIT STATIC LOS_DL_LIST g_unusedSemList;//可用的信号量列表,干嘛不用freeList? 可以看出这里是另一个人写的代码
LITE_OS_SEC_BSS LosSemCB *g_allSem = NULL;//信号池,一次分配 LOSCFG_BASE_IPC_SEM_LIMIT 个信号量
/*
* Description : Initialize the semaphore doubly linked list
......@@ -62,18 +62,18 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsSemInit(VOID)//信号量初始化
LosSemCB *semNode = NULL;
UINT32 index;
LOS_ListInit(&g_unusedSemList);
LOS_ListInit(&g_unusedSemList);//初始
/* system resident memory, don't free */
g_allSem = (LosSemCB *)LOS_MemAlloc(m_aucSysMem0, (LOSCFG_BASE_IPC_SEM_LIMIT * sizeof(LosSemCB)));
g_allSem = (LosSemCB *)LOS_MemAlloc(m_aucSysMem0, (LOSCFG_BASE_IPC_SEM_LIMIT * sizeof(LosSemCB)));//分配信号池
if (g_allSem == NULL) {
return LOS_ERRNO_SEM_NO_MEMORY;
}
for (index = 0; index < LOSCFG_BASE_IPC_SEM_LIMIT; index++) {
semNode = ((LosSemCB *)g_allSem) + index;
semNode->semID = SET_SEM_ID(0, index);
semNode->semStat = OS_SEM_UNUSED;
LOS_ListTailInsert(&g_unusedSemList, &semNode->semList);
semNode = ((LosSemCB *)g_allSem) + index;//拿信号控制块, 可以直接g_allSem[index]来嘛
semNode->semID = SET_SEM_ID(0, index);//保存ID
semNode->semStat = OS_SEM_UNUSED;//标记未使用
LOS_ListTailInsert(&g_unusedSemList, &semNode->semList);//通过semList把 信号块挂到空闲链表上
}
if (OsSemDbgInitHook() != LOS_OK) {
......@@ -101,26 +101,26 @@ LITE_OS_SEC_TEXT_INIT UINT32 OsSemCreate(UINT16 count, UINT16 maxCount, UINT32 *
return LOS_ERRNO_SEM_PTR_NULL;
}
if (count > maxCount) {
if (count > maxCount) {//信号量不能大于最大值,两参数都是外面给的
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_OVERFLOW);
}
SCHEDULER_LOCK(intSave);
SCHEDULER_LOCK(intSave);//进入临界区了,拿自旋锁
if (LOS_ListEmpty(&g_unusedSemList)) {
if (LOS_ListEmpty(&g_unusedSemList)) {//没有可分配的空闲信号提供
SCHEDULER_UNLOCK(intSave);
OsSemInfoGetFullDataHook();
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_ALL_BUSY);
}
unusedSem = LOS_DL_LIST_FIRST(&g_unusedSemList);
LOS_ListDelete(unusedSem);
semCreated = GET_SEM_LIST(unusedSem);
semCreated->semCount = count;
semCreated->semStat = OS_SEM_USED;
semCreated->maxSemCount = maxCount;
LOS_ListInit(&semCreated->semList);
*semHandle = semCreated->semID;
unusedSem = LOS_DL_LIST_FIRST(&g_unusedSemList);//拿第一个出来创建
LOS_ListDelete(unusedSem);//从空闲链表上摘除
semCreated = GET_SEM_LIST(unusedSem);//通过semList挂到链表上的,这里也要通过它把LosSemCB头查到. 进程,线程等结构体也都是这么干的.
semCreated->semCount = count;//设置数量
semCreated->semStat = OS_SEM_USED;//设置可用状态
semCreated->maxSemCount = maxCount;//设置最大信号数量
LOS_ListInit(&semCreated->semList);//初始化链表,后续阻塞任务通过task->pendList挂到semList链表上,就知道哪些任务在等它了.
*semHandle = semCreated->semID;//参数带走 semID
OsSemDbgUpdateHook(semCreated->semID, OsCurrTaskGet()->taskEntry, count);
......@@ -140,7 +140,7 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_BinarySemCreate(UINT16 count, UINT32 *semHandle
{
return OsSemCreate(count, OS_SEM_BINARY_COUNT_MAX, semHandle);
}
//删除信号量,参数就是 semID
LITE_OS_SEC_TEXT_INIT UINT32 LOS_SemDelete(UINT32 semHandle)
{
UINT32 intSave;
......@@ -152,23 +152,23 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_SemDelete(UINT32 semHandle)
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_INVALID);
}
semDeleted = GET_SEM(semHandle);
semDeleted = GET_SEM(semHandle);//通过ID拿到信号量实体
SCHEDULER_LOCK(intSave);
if ((semDeleted->semStat == OS_SEM_UNUSED) || (semDeleted->semID != semHandle)) {
if ((semDeleted->semStat == OS_SEM_UNUSED) || (semDeleted->semID != semHandle)) {//参数判断
SCHEDULER_UNLOCK(intSave);
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_INVALID);
}
if (!LOS_ListEmpty(&semDeleted->semList)) {
if (!LOS_ListEmpty(&semDeleted->semList)) {//当前还有任务挂在这个信号上面,当然不能删除
SCHEDULER_UNLOCK(intSave);
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_PENDED);
OS_GOTO_ERR_HANDLER(LOS_ERRNO_SEM_PENDED);//这个宏很有意思,里面goto到ERR_HANDLER
}
LOS_ListTailInsert(&g_unusedSemList, &semDeleted->semList);
semDeleted->semStat = OS_SEM_UNUSED;
semDeleted->semID = SET_SEM_ID(GET_SEM_COUNT(semDeleted->semID) + 1, GET_SEM_INDEX(semDeleted->semID));
LOS_ListTailInsert(&g_unusedSemList, &semDeleted->semList);//通过semList从尾部插入空闲链表
semDeleted->semStat = OS_SEM_UNUSED;//状态变成了未使用
semDeleted->semID = SET_SEM_ID(GET_SEM_COUNT(semDeleted->semID) + 1, GET_SEM_INDEX(semDeleted->semID));//设置ID
OsSemDbgUpdateHook(semDeleted->semID, NULL, 0);
......@@ -178,11 +178,11 @@ LITE_OS_SEC_TEXT_INIT UINT32 LOS_SemDelete(UINT32 semHandle)
ERR_HANDLER:
OS_RETURN_ERROR_P2(errLine, errNo);
}
//挂起信号
LITE_OS_SEC_TEXT UINT32 LOS_SemPend(UINT32 semHandle, UINT32 timeout)
{
UINT32 intSave;
LosSemCB *semPended = GET_SEM(semHandle);
LosSemCB *semPended = GET_SEM(semHandle);//通过ID拿到信号体
UINT32 retErr = LOS_OK;
LosTaskCB *runTask = NULL;
......@@ -196,7 +196,7 @@ LITE_OS_SEC_TEXT UINT32 LOS_SemPend(UINT32 semHandle, UINT32 timeout)
return LOS_ERRNO_SEM_PEND_INTERR;
}
runTask = OsCurrTaskGet();
runTask = OsCurrTaskGet();//获取当前任务
if (runTask->taskStatus & OS_TASK_FLAG_SYSTEM_TASK) {
OsBackTrace();
return LOS_ERRNO_SEM_PEND_IN_SYSTEM_TASK;
......@@ -212,24 +212,24 @@ LITE_OS_SEC_TEXT UINT32 LOS_SemPend(UINT32 semHandle, UINT32 timeout)
/* Update the operate time, no matter the actual Pend success or not */
OsSemDbgTimeUpdateHook(semHandle);
if (semPended->semCount > 0) {
semPended->semCount--;
goto OUT;
if (semPended->semCount > 0) {//还有资源可用,返回肯定得成功,semCount=0时代表没资源了,task会必须去睡眠了
semPended->semCount--;//资源少了一个
goto OUT;//注意这里 retErr = LOS_OK ,所以返回是OK的
} else if (!timeout) {
retErr = LOS_ERRNO_SEM_UNAVAILABLE;
goto OUT;
}
if (!OsPreemptableInSched()) {
if (!OsPreemptableInSched()) {//不能申请调度 (不能调度的原因是因为没有持有调度任务自旋锁)
PRINT_ERR("!!!LOS_ERRNO_SEM_PEND_IN_LOCK!!!\n");
OsBackTrace();
retErr = LOS_ERRNO_SEM_PEND_IN_LOCK;
goto OUT;
}
runTask->taskSem = (VOID *)semPended;
retErr = OsTaskWait(&semPended->semList, timeout, TRUE);
if (retErr == LOS_ERRNO_TSK_TIMEOUT) {
runTask->taskSem = (VOID *)semPended;//标记当前任务在等这个信号量
retErr = OsTaskWait(&semPended->semList, timeout, TRUE);//任务进入等待状态,当前任务会挂到semList上,并在其中切换任务上下文
if (retErr == LOS_ERRNO_TSK_TIMEOUT) {//注意:这里是涉及到task切换的,把自己挂起,唤醒其他task
runTask->taskSem = NULL;
retErr = LOS_ERRNO_SEM_TIMEOUT;
}
......@@ -238,7 +238,7 @@ OUT:
SCHEDULER_UNLOCK(intSave);
return retErr;
}
//释放信号
LITE_OS_SEC_TEXT UINT32 OsSemPostUnsafe(UINT32 semHandle, BOOL *needSched)
{
LosSemCB *semPosted = NULL;
......@@ -256,18 +256,18 @@ LITE_OS_SEC_TEXT UINT32 OsSemPostUnsafe(UINT32 semHandle, BOOL *needSched)
/* Update the operate time, no matter the actual Post success or not */
OsSemDbgTimeUpdateHook(semHandle);
if (semPosted->semCount == OS_SEM_COUNT_MAX) {
if (semPosted->semCount == OS_SEM_COUNT_MAX) {//当前信号资源不能大于最大资源量
return LOS_ERRNO_SEM_OVERFLOW;
}
if (!LOS_ListEmpty(&semPosted->semList)) {
resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(semPosted->semList)));
resumedTask->taskSem = NULL;
OsTaskWake(resumedTask);
if (needSched != NULL) {
*needSched = TRUE;
if (!LOS_ListEmpty(&semPosted->semList)) {//当前有任务挂在semList上,要去唤醒任务
resumedTask = OS_TCB_FROM_PENDLIST(LOS_DL_LIST_FIRST(&(semPosted->semList)));//semList上面挂的都是task->pendlist节点,取第一个task下来唤醒
resumedTask->taskSem = NULL;//任务不用等信号了,重新变成NULL值
OsTaskWake(resumedTask);//唤醒任务,注意resumedTask一定不是当前任务,OsTaskWake里面并不会自己切换任务上下文,只是设置状态
if (needSched != NULL) {//参数不为空,就返回需要调度的标签
*needSched = TRUE;//TRUE代表需要调度
}
} else {
semPosted->semCount++;
} else {//当前没有任务挂在semList上,
semPosted->semCount++;//信号资源多一个
}
return LOS_OK;
......@@ -282,9 +282,9 @@ LITE_OS_SEC_TEXT UINT32 LOS_SemPost(UINT32 semHandle)
SCHEDULER_LOCK(intSave);
ret = OsSemPostUnsafe(semHandle, &needSched);
SCHEDULER_UNLOCK(intSave);
if (needSched) {
LOS_MpSchedule(OS_MP_CPU_ALL);
LOS_Schedule();
if (needSched) {//需要调度的情况
LOS_MpSchedule(OS_MP_CPU_ALL);//向所有CPU发送调度指令
LOS_Schedule();////发起调度
}
return ret;
......
......@@ -240,7 +240,7 @@ extern UINT32 __heap_end; // 堆区结束地址
* Configuration item for semaphore module tailoring
*/
#ifndef LOSCFG_BASE_IPC_SEM
#define LOSCFG_BASE_IPC_SEM YES
#define LOSCFG_BASE_IPC_SEM YES //信号量支持
#endif
/**
......@@ -248,7 +248,7 @@ extern UINT32 __heap_end; // 堆区结束地址
* Maximum supported number of semaphores
*/
#ifndef LOSCFG_BASE_IPC_SEM_LIMIT
#define LOSCFG_BASE_IPC_SEM_LIMIT 1024
#define LOSCFG_BASE_IPC_SEM_LIMIT 1024 //信号量的最大个数
#endif
/****************************** mutex module configuration ******************************/
......@@ -257,7 +257,7 @@ extern UINT32 __heap_end; // 堆区结束地址
* Configuration item for mutex module tailoring
*/
#ifndef LOSCFG_BASE_IPC_MUX
#define LOSCFG_BASE_IPC_MUX YES
#define LOSCFG_BASE_IPC_MUX YES //互斥量的支持
#endif
/****************************** Queue module configuration ********************************/
......@@ -266,7 +266,7 @@ extern UINT32 __heap_end; // 堆区结束地址
* Configuration item for queue module tailoring
*/
#ifndef LOSCFG_BASE_IPC_QUEUE
#define LOSCFG_BASE_IPC_QUEUE YES
#define LOSCFG_BASE_IPC_QUEUE YES //是否支持IPC队列?
#endif
/**
......@@ -274,17 +274,17 @@ extern UINT32 __heap_end; // 堆区结束地址
* Maximum supported number of queues rather than the number of usable queues
*/
#ifndef LOSCFG_BASE_IPC_QUEUE_LIMIT
#define LOSCFG_BASE_IPC_QUEUE_LIMIT 1024
#define LOSCFG_BASE_IPC_QUEUE_LIMIT 1024 //队列个数
#endif
/****************************** Software timer module configuration **************************/
#if (LOSCFG_BASE_IPC_QUEUE == YES)
#if (LOSCFG_BASE_IPC_QUEUE == YES) //软时钟模块需打开IPC队列
/**
* @ingroup los_config
* Configuration item for software timer module tailoring
*/
#ifndef LOSCFG_BASE_CORE_SWTMR
#define LOSCFG_BASE_CORE_SWTMR YES
#define LOSCFG_BASE_CORE_SWTMR YES //是否支持软时钟?
#endif
/**
......
......@@ -190,7 +190,7 @@ LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinUnlock(SPIN_LOCK_S *lock)
* @see LOS_SpinLock
*/
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinLockSave(SPIN_LOCK_S *lock, UINT32 *intSave)
{
{//自旋锁是不切换任务上下文的,忙等状态.锁的是细颗粒的操作,代码量小,运行时间端的临界区
*intSave = LOS_IntLock();
LOS_SpinLock(lock);
}
......@@ -288,7 +288,7 @@ LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinUnlock(SPIN_LOCK_S *lock)
}
LITE_OS_SEC_ALW_INLINE STATIC INLINE VOID LOS_SpinLockSave(SPIN_LOCK_S *lock, UINT32 *intSave)
{
{//自旋锁是不切换任务上下文的,忙等状态.锁的是细颗粒的操作,代码量小,运行时间端的临界区
(VOID)lock;
*intSave = LOS_IntLock();
}
......
#ifndef _NOTE_IPC_H
#define _NOTE_IPC_H
/****************************************************************
信号量是为了解决task的资源同步问题,有多少资源就设多大的资源最大值
信号量机制:
以一个停车场的运作为例。假设停车场只有三个车位,一开始三个车位都是空的。这时如果同时来了五辆车,
看门人允许其中三辆直接进入,然后放下车拦,剩下的车则必须在入口等待,此后来的车也都不得不在入口处等待。
这时,有一辆车离开停车场,看门人得知后,打开车拦,放入外面的一辆进去,如果又离开两辆,则又可以放入两辆,如此往复。
信号量的规则:
如果当前资源计数器大于0,那么信号量处于触发状态
如果当前资源计数器等于0,那么信号量处于未触发状态
系统绝对不会让当前资源计数器变为负数
当前资源计数器决定不会大于最大资源计数
最大资源计数,表示可以控件的最大资源数量
当前资源计数,表示当前可用资源的数量
****************************************************************/
#endif
git add -A
git commit -m '加入了wiki的支持,后续四大码仓wiki也同步推
git commit -m '开始对信号量这块代码进行注释,信号量的出现为了解决task的同步问题
鸿蒙内核源码分析系列 【 CSDN | OSCHINA | WIKI 】
鸿蒙内核源码注释中文版 【 CSDN仓 | Gitee仓 | Github仓 | Coding仓 】四大仓库每日同步更新代码和wiki
给鸿蒙内核源码逐行加上中文注解,详细阐述设计细节, 助你快速精读 HarmonyOS 内核源码, 掌握整个鸿蒙内核运行机制.'
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册