Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
鸿蒙内核源码分析
注释鸿蒙内核源码
提交
87137deb
注释鸿蒙内核源码
项目概览
鸿蒙内核源码分析
/
注释鸿蒙内核源码
通知
270
Star
29
Fork
11
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
106
Wiki
分析
仓库
DevOps
项目成员
Pages
注释鸿蒙内核源码
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
106
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
87137deb
编写于
4月 15, 2021
作者:
鸿蒙内核源码分析
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
注解信号注册,发送过程
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
https://my.oschina.net/weharmony
上级
1cb5f01b
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
55 addition
and
50 deletion
+55
-50
kernel/base/include/los_process_pri.h
kernel/base/include/los_process_pri.h
+1
-1
kernel/base/include/los_signal.h
kernel/base/include/los_signal.h
+2
-2
kernel/base/include/los_task_pri.h
kernel/base/include/los_task_pri.h
+4
-4
kernel/base/ipc/los_signal.c
kernel/base/ipc/los_signal.c
+42
-37
syscall/ipc_syscall.c
syscall/ipc_syscall.c
+2
-2
syscall/los_syscall.c
syscall/los_syscall.c
+3
-3
zzz/git/push.sh
zzz/git/push.sh
+1
-1
未找到文件。
kernel/base/include/los_process_pri.h
浏览文件 @
87137deb
...
...
@@ -245,7 +245,7 @@ typedef struct ProcessCB {
* @ingroup los_process
* Used to check if the process control block is unused.
*/
STATIC
INLINE
BOOL
OsProcessIsUnused
(
const
LosProcessCB
*
processCB
)
//查下进程是否
没
在使用?
STATIC
INLINE
BOOL
OsProcessIsUnused
(
const
LosProcessCB
*
processCB
)
//查下进程是否
还
在使用?
{
return
((
processCB
->
processStatus
&
OS_PROCESS_FLAG_UNUSED
)
!=
0
);
}
...
...
kernel/base/include/los_signal.h
浏览文件 @
87137deb
...
...
@@ -232,10 +232,10 @@ typedef struct {//信号切换上下文
typedef
struct
{
//信号控制块(描述符)
sigset_t
sigFlag
;
//信号标签集
sigset_t
sigPendFlag
;
//信号阻塞标签集,记录因哪些信号被阻塞
sigset_t
sigprocmask
;
/* Signals that are blocked */
//
进程
屏蔽了哪些信号
sigset_t
sigprocmask
;
/* Signals that are blocked */
//
任务
屏蔽了哪些信号
sq_queue_t
sigactionq
;
//信号捕捉队列
LOS_DL_LIST
waitList
;
//等待链表,上面挂的是等待信号到来的任务, 请查找 OsTaskWait(&sigcb->waitList, timeout, TRUE) 理解
sigset_t
sigwaitmask
;
/* Waiting for pending signals */
//任务在等待
阻塞信号
sigset_t
sigwaitmask
;
/* Waiting for pending signals */
//任务在等待
哪些信号的到来
siginfo_t
sigunbinfo
;
/* Signal info when task unblocked */
//任务解锁时的信号信息
sig_switch_context
context
;
//信号切换上下文, 用于保存切换现场, 比如发生系统调用时的返回,涉及同一个任务的两个栈进行切换
}
sig_cb
;
...
...
kernel/base/include/los_task_pri.h
浏览文件 @
87137deb
...
...
@@ -358,10 +358,10 @@ typedef struct {
struct
ProcessSignalInfo
{
//进程信号描述符
siginfo_t
*
sigInfo
;
/**< Signal to be dispatched */
//要发送的信号
LosTaskCB
*
defaultTcb
;
/**< Default TCB */
//默认task,
指的是信号的发送方
LosTaskCB
*
unblockedTcb
;
/**< The signal unblock on this TCB*/
//
此任务的信号阻塞解除
LosTaskCB
*
awakenedTcb
;
/**< This TCB was awakened */
//
被唤醒的任务
LosTaskCB
*
receivedTcb
;
/**< This TCB received the signal */
//
接收信号的任务
LosTaskCB
*
defaultTcb
;
/**< Default TCB */
//默认task,
默认接收信号的任务.
LosTaskCB
*
unblockedTcb
;
/**< The signal unblock on this TCB*/
//
信号在此TCB上解除阻塞
LosTaskCB
*
awakenedTcb
;
/**< This TCB was awakened */
//
即 任务在等待这个信号,此信号一来任务被唤醒.
LosTaskCB
*
receivedTcb
;
/**< This TCB received the signal */
//
如果没有屏蔽信号,任务将接收这个信号.
};
typedef
int
(
*
ForEachTaskCB
)(
LosTaskCB
*
tcb
,
void
*
arg
);
//回调任务函数,例如:进程被kill 9 时,通知所有任务善后处理
...
...
kernel/base/ipc/los_signal.c
浏览文件 @
87137deb
...
...
@@ -117,7 +117,7 @@ void OsSigMaskSwitch(LosTaskCB * const rtcb, sigset_t set)
}
}
/******************************************************************
不同how参数,实现不同功能
向信号集设置信号屏蔽的方法
SIG_BLOCK:将set指向信号集中的信号,添加到进程阻塞信号集;
SIG_UNBLOCK:将set指向信号集中的信号,从进程阻塞信号集删除;
SIG_SETMASK:将set指向信号集中的信号,设置成进程阻塞信号集;
...
...
@@ -184,7 +184,7 @@ int OsSigProcessForeachChild(LosProcessCB *spcb, ForEachTaskCB handler, void *ar
{
int
ret
;
/* Visit the main thread last (if present) */
//最后访问主线程(如果有)
/* Visit the main thread last (if present) */
LosTaskCB
*
taskCB
=
NULL
;
//遍历进程的 threadList 链表,里面存放的都是task节点
LOS_DL_LIST_FOR_EACH_ENTRY
(
taskCB
,
&
(
spcb
->
threadSiblingList
),
LosTaskCB
,
threadList
)
{
//遍历进程的任务列表
ret
=
handler
(
taskCB
,
arg
);
//回调参数函数
...
...
@@ -204,17 +204,17 @@ static int SigProcessSignalHandler(LosTaskCB *tcb, void *arg)
}
/* If the default tcb is not setted, then set this one as default. */
if
(
!
info
->
defaultTcb
)
{
//如果没有默认发送方的任务,
就
默认参数任务.
if
(
!
info
->
defaultTcb
)
{
//如果没有默认发送方的任务,
即
默认参数任务.
info
->
defaultTcb
=
tcb
;
}
isMember
=
OsSigIsMember
(
&
tcb
->
sig
.
sigwaitmask
,
info
->
sigInfo
->
si_signo
);
if
(
isMember
&&
(
!
info
->
awakenedTcb
))
{
//
这意味着任务正在等待此信号。
isMember
=
OsSigIsMember
(
&
tcb
->
sig
.
sigwaitmask
,
info
->
sigInfo
->
si_signo
);
//任务是否在等待这个信号
if
(
isMember
&&
(
!
info
->
awakenedTcb
))
{
//
是在等待,并尚未向该任务时发送信号时
/* This means the task is waiting for this signal. Stop looking for it and use this tcb.
* The requirement is: if more than one task in this task group is waiting for the signal,
* then only one indeterminate task in the group will receive the signal.
*/
ret
=
OsTcbDispatch
(
tcb
,
info
->
sigInfo
);
//发送信号,注意这是给其他任务发送信号
ret
=
OsTcbDispatch
(
tcb
,
info
->
sigInfo
);
//发送信号,注意这是给其他任务发送信号
,tcb不是当前任务
OS_RETURN_IF
(
ret
<
0
,
ret
);
//这种写法很有意思
/* set this tcb as awakenedTcb */
...
...
@@ -222,17 +222,17 @@ static int SigProcessSignalHandler(LosTaskCB *tcb, void *arg)
OS_RETURN_IF
(
info
->
receivedTcb
!=
NULL
,
SIG_STOP_VISIT
);
/* Stop search */
}
/* Is this signal unblocked on this thread? */
isMember
=
OsSigIsMember
(
&
tcb
->
sig
.
sigprocmask
,
info
->
sigInfo
->
si_signo
);
if
((
!
isMember
)
&&
(
!
info
->
receivedTcb
)
&&
(
tcb
!=
info
->
awakenedTcb
))
{
isMember
=
OsSigIsMember
(
&
tcb
->
sig
.
sigprocmask
,
info
->
sigInfo
->
si_signo
);
//任务是否屏蔽了这个信号
if
((
!
isMember
)
&&
(
!
info
->
receivedTcb
)
&&
(
tcb
!=
info
->
awakenedTcb
))
{
//没有屏蔽,有唤醒任务没有接收任务.
/* if unblockedTcb of this signal is not setted, then set it. */
if
(
!
info
->
unblockedTcb
)
{
info
->
unblockedTcb
=
tcb
;
}
ret
=
OsTcbDispatch
(
tcb
,
info
->
sigInfo
);
ret
=
OsTcbDispatch
(
tcb
,
info
->
sigInfo
);
//向任务发送信号
OS_RETURN_IF
(
ret
<
0
,
ret
);
/* set this tcb as receivedTcb */
info
->
receivedTcb
=
tcb
;
info
->
receivedTcb
=
tcb
;
//设置这个任务为接收任务
OS_RETURN_IF
(
info
->
awakenedTcb
!=
NULL
,
SIG_STOP_VISIT
);
/* Stop search */
}
return
0
;
/* Keep searching */
...
...
@@ -244,14 +244,14 @@ static int SigProcessKillSigHandler(LosTaskCB *tcb, void *arg)
if
((
tcb
!=
NULL
)
&&
(
info
!=
NULL
)
&&
(
info
->
sigInfo
!=
NULL
))
{
//进程有信号
sig_cb
*
sigcb
=
&
tcb
->
sig
;
if
(
!
LOS_ListEmpty
(
&
sigcb
->
waitList
)
&&
OsSigIsMember
(
&
sigcb
->
sigwaitmask
,
info
->
sigInfo
->
si_signo
))
{
//
waitlist 不为空 且 有
信号
OsTaskWake
(
tcb
);
//唤醒这个任务,加入进程的就绪队列
OsSigEmptySet
(
&
sigcb
->
sigwaitmask
);
//清空信号等待位,不等任何信号了.
if
(
!
LOS_ListEmpty
(
&
sigcb
->
waitList
)
&&
OsSigIsMember
(
&
sigcb
->
sigwaitmask
,
info
->
sigInfo
->
si_signo
))
{
//
如果任务在等待这个
信号
OsTaskWake
(
tcb
);
//唤醒这个任务,加入进程的就绪队列
,,并不申请调度
OsSigEmptySet
(
&
sigcb
->
sigwaitmask
);
//清空信号等待位,不等任何信号了.
因为这是SIGKILL信号
}
}
return
0
;
}
//
进程加载task控制块信号
//
处理信号发送
static
void
SigProcessLoadTcb
(
struct
ProcessSignalInfo
*
info
,
siginfo_t
*
sigInfo
)
{
LosTaskCB
*
tcb
=
NULL
;
...
...
@@ -274,16 +274,17 @@ int OsSigProcessSend(LosProcessCB *spcb, siginfo_t *sigInfo)
int
ret
;
struct
ProcessSignalInfo
info
=
{
.
sigInfo
=
sigInfo
,
//信号内容
.
defaultTcb
=
NULL
,
.
defaultTcb
=
NULL
,
//以下四个值将在OsSigProcessForeachChild中根据条件完善
.
unblockedTcb
=
NULL
,
.
awakenedTcb
=
NULL
,
.
receivedTcb
=
NULL
};
//总之是要从进程中找个至少一个任务来接受这个信号,优先级
//awakenedTcb > receivedTcb > unblockedTcb > defaultTcb
/* visit all taskcb and dispatch signal */
//访问所有任务和分发信号
if
((
info
.
sigInfo
!=
NULL
)
&&
(
info
.
sigInfo
->
si_signo
==
SIGKILL
))
{
//需要干掉进程时 SIGKILL = 9, #linux kill 9 14
(
void
)
OsSigProcessForeachChild
(
spcb
,
SigProcessKillSigHandler
,
&
info
);
//进程要被干掉了,通知所有task做善后处理
OsSigAddSet
(
&
spcb
->
sigShare
,
info
.
sigInfo
->
si_signo
);
OsSigAddSet
(
&
spcb
->
sigShare
,
info
.
sigInfo
->
si_signo
);
//信号集中增加信号
OsWaitSignalToWakeProcess
(
spcb
);
//等待信号唤醒进程
return
0
;
}
else
{
...
...
@@ -292,7 +293,7 @@ int OsSigProcessSend(LosProcessCB *spcb, siginfo_t *sigInfo)
if
(
ret
<
0
)
{
return
ret
;
}
SigProcessLoadTcb
(
&
info
,
sigInfo
);
SigProcessLoadTcb
(
&
info
,
sigInfo
);
//确保能给一个任务发送信号
return
0
;
}
//信号集全部清0
...
...
@@ -302,7 +303,7 @@ int OsSigEmptySet(sigset_t *set)
return
0
;
}
/* Privilege process can't send to kernel and privilege process */
//
特权进程无法发送到内核和特权进程
/* Privilege process can't send to kernel and privilege process */
//
内核进程组和用户特权进程组无法发送
static
int
OsSignalPermissionToCheck
(
const
LosProcessCB
*
spcb
)
{
UINT32
gid
=
spcb
->
group
->
groupID
;
...
...
@@ -315,18 +316,18 @@ static int OsSignalPermissionToCheck(const LosProcessCB *spcb)
return
0
;
}
//信号分发
//信号分发
,发送信号权限/进程组过滤.
int
OsDispatch
(
pid_t
pid
,
siginfo_t
*
info
,
int
permission
)
{
LosProcessCB
*
spcb
=
OS_PCB_FROM_PID
(
pid
);
//找到这个进程
if
(
OsProcessIsUnused
(
spcb
))
{
//进程是否还在使用
if
(
OsProcessIsUnused
(
spcb
))
{
//进程是否还在使用
,不一定是当前进程但必须是个有效进程
return
-
ESRCH
;
}
#ifdef LOSCFG_SECURITY_CAPABILITY //启用能力安全模式
LosProcessCB
*
current
=
OsCurrProcessGet
();
//获取当前进程
/* If the process you want to kill had been inactive, but still exist. should return LOS_OK */
if
(
OsProcessIsInactive
(
spcb
))
{
//
如果要终止的进程处于非活动状态,但仍然存在,应该
返回OK
if
(
OsProcessIsInactive
(
spcb
))
{
//
不向非活动进程发送信息,但
返回OK
return
LOS_OK
;
}
...
...
@@ -376,7 +377,7 @@ int OsKillLock(pid_t pid, int sig)
unsigned
int
intSave
;
SCHEDULER_LOCK
(
intSave
);
ret
=
OsKill
(
pid
,
sig
,
OS_USER_KILL_PERMISSION
);
//用户
进程申请干掉其他进程,能成功吗? 满足条件就行
ret
=
OsKill
(
pid
,
sig
,
OS_USER_KILL_PERMISSION
);
//用户
权限向进程发送信号
SCHEDULER_UNLOCK
(
intSave
);
return
ret
;
}
...
...
@@ -566,7 +567,7 @@ int OsSigAction(int sig, const sigaction_t *act, sigaction_t *oact)
if
(
sig
==
SIGSYS
)
{
//系统调用中参数错,如系统调用号非法
addr
=
OsGetSigHandler
();
//获取进程信号处理函数
if
(
addr
==
0
)
{
if
(
addr
==
0
)
{
//进程没有信号处理函数时
OsSetSigHandler
((
unsigned
long
)(
UINTPTR
)
action
.
sa_handler
);
//设置进程信号处理函数
return
LOS_OK
;
}
...
...
@@ -577,6 +578,7 @@ int OsSigAction(int sig, const sigaction_t *act, sigaction_t *oact)
}
/**********************************************
产生系统调用时,也就是软中断时,保存用户栈寄存器现场信息
改写PC寄存器的值
**********************************************/
void
OsSaveSignalContext
(
unsigned
int
*
sp
)
{
...
...
@@ -595,8 +597,9 @@ void OsSaveSignalContext(unsigned int *sp)
task
=
OsCurrTaskGet
();
process
=
OsCurrProcessGet
();
sigcb
=
&
task
->
sig
;
//获取任务的信号控制块
if
((
sigcb
->
context
.
count
==
0
)
&&
((
sigcb
->
sigFlag
!=
0
)
||
(
process
->
sigShare
!=
0
)))
{
//未保存上下文且关注了信号
//1.未保存任务上下文任务
//2.任何的信号标签集不为空或者进程有信号要处理
if
((
sigcb
->
context
.
count
==
0
)
&&
((
sigcb
->
sigFlag
!=
0
)
||
(
process
->
sigShare
!=
0
)))
{
sigHandler
=
OsGetSigHandler
();
//获取信号处理函数
if
(
sigHandler
==
0
)
{
//信号没有注册
sigcb
->
sigFlag
=
0
;
...
...
@@ -606,14 +609,14 @@ void OsSaveSignalContext(unsigned int *sp)
return
;
}
/* One pthread do the share signal */
sigcb
->
sigFlag
|=
process
->
sigShare
;
//
记录由一个线程执行可进程的共享信号,这些恢复上下文时就找到对应的任务
sigcb
->
sigFlag
|=
process
->
sigShare
;
//
扩展任务的信号标签集
unsigned
int
signo
=
(
unsigned
int
)
FindFirstSetedBit
(
sigcb
->
sigFlag
)
+
1
;
OsProcessExitCodeSignalSet
(
process
,
signo
);
//设置进程退出信号
sigcb
->
context
.
CPSR
=
cpsr
;
//保存当前各寄存器的信息
sigcb
->
context
.
PC
=
sp
[
REG_PC
];
//获取被打断现场寄存器的值
sigcb
->
context
.
USP
=
sp
[
REG_SP
];
sigcb
->
context
.
ULR
=
sp
[
REG_LR
];
sigcb
->
context
.
R0
=
sp
[
REG_R0
];
sigcb
->
context
.
USP
=
sp
[
REG_SP
];
//用户栈顶位置,以便能从内核栈切回用户栈
sigcb
->
context
.
ULR
=
sp
[
REG_LR
];
//用户栈返回地址
sigcb
->
context
.
R0
=
sp
[
REG_R0
];
//系统调用的返回值
sigcb
->
context
.
R1
=
sp
[
REG_R1
];
sigcb
->
context
.
R2
=
sp
[
REG_R2
];
sigcb
->
context
.
R3
=
sp
[
REG_R3
];
...
...
@@ -647,20 +650,22 @@ void OsSaveSignalContextIrq(unsigned int *sp, unsigned int r7)
SCHEDULER_LOCK
(
intSave
);
task
=
OsCurrTaskGet
();
//获取当前任务
process
=
OsCurrProcessGet
();
process
=
OsCurrProcessGet
();
//必须是需要当前任务
sigcb
=
&
task
->
sig
;
//获取任务的信号控制块
//1.未保存任务上下文任务
//2.任何的信号标签集不为空或者进程有信号要处理
if
((
sigcb
->
context
.
count
==
0
)
&&
((
sigcb
->
sigFlag
!=
0
)
||
(
process
->
sigShare
!=
0
)))
{
sigHandler
=
OsGetSigHandler
();
//获取进程的信号处理函数
if
(
sigHandler
==
0
)
{
//没有设置处理函数
if
(
sigHandler
==
0
)
{
//没有设置
信号
处理函数
sigcb
->
sigFlag
=
0
;
//进程没有设置信号处理函数,所以任务的信号无意义,标签回0
process
->
sigShare
=
0
;
//进程的共享位也无意义,回0
SCHEDULER_UNLOCK
(
intSave
);
PRINT_ERR
(
"The current process pid =%d starts fail!
\n
"
,
task
->
processID
);
return
;
}
sigcb
->
sigFlag
|=
process
->
sigShare
;
unsigned
int
signo
=
(
unsigned
int
)
FindFirstSetedBit
(
sigcb
->
sigFlag
)
+
1
;
OsProcessExitCodeSignalSet
(
process
,
signo
);
sigcb
->
sigFlag
|=
process
->
sigShare
;
//扩展任务的信号标签集
unsigned
int
signo
=
(
unsigned
int
)
FindFirstSetedBit
(
sigcb
->
sigFlag
)
+
1
;
//找到第一个被设置的位置,+1是因为信号时从[1-64]的
OsProcessExitCodeSignalSet
(
process
,
signo
);
//设置进程的退出码的信号为(0 ~ 7)位
(
VOID
)
memcpy_s
(
&
sigcb
->
context
.
R0
,
sizeof
(
TaskIrqDataSize
),
&
context
->
R0
,
sizeof
(
TaskIrqDataSize
));
//拷贝中断上下文到任务的信号上下文
//这里其实类似于 OsSaveSignalContext 中的 sigcb->context.USP = sp[REG_SP] ...
sigcb
->
context
.
R7
=
r7
;
//因为是硬件触发,所以此处不同于 OsSaveSignalContext(unsigned int *sp),需要通过底层将 R7 带过来. MOV R1,R7, BL OsSaveSignalContextIrq
...
...
@@ -669,8 +674,8 @@ void OsSaveSignalContextIrq(unsigned int *sp, unsigned int r7)
context
->
R0
=
signo
;
//参数1.信号ID
context
->
R1
=
(
UINT32
)(
UINTPTR
)
sigcb
->
sigunbinfo
.
si_value
.
sival_ptr
;
//参数2
/* sig No bits 00000100 present sig No 3, but 1<< 3 = 00001000, so signo needs minus 1 */
sigcb
->
sigFlag
^=
1ULL
<<
(
signo
-
1
);
sigcb
->
context
.
count
++
;
sigcb
->
sigFlag
^=
1ULL
<<
(
signo
-
1
);
//减1跟上面 + 1 的道理一样. @note_thinking 但为啥要用 ^= 呢?
sigcb
->
context
.
count
++
;
//代表已经保存过信号的上下文了
}
SCHEDULER_UNLOCK
(
intSave
);
}
...
...
syscall/ipc_syscall.c
浏览文件 @
87137deb
...
...
@@ -238,12 +238,12 @@ int SysSigprocMask(int how, const sigset_t_l *restrict setl, sigset_t_l *restric
/* Let nxsig_procmask do all of the work */
return
OsSigprocMask
(
how
,
setl
,
oldl
);
}
//系统调用之
干掉进程
//系统调用之
向进程发送信号
int
SysKill
(
pid_t
pid
,
int
sig
)
{
return
OsKillLock
(
pid
,
sig
);
}
//系统调用之
干掉线程
//系统调用之
之向进程发送信号
int
SysPthreadKill
(
pid_t
pid
,
int
sig
)
{
return
OsPthreadKill
(
pid
,
sig
);
...
...
syscall/los_syscall.c
浏览文件 @
87137deb
...
...
@@ -112,8 +112,8 @@ LITE_OS_SEC_TEXT UINT32 *OsArmA32SyscallHandle(UINT32 *regs)
return
regs
;
}
if
(
cmd
==
__NR_sigreturn
)
{
//收到 __NR_sigreturn 信号
OsRestorSignalContext
(
regs
);
//恢复信号上下文
if
(
cmd
==
__NR_sigreturn
)
{
//收到 __NR_sigreturn 信号
,说明信号处理结束了
OsRestorSignalContext
(
regs
);
//恢复信号上下文
,回到用户栈运行.
return
regs
;
}
...
...
@@ -146,7 +146,7 @@ LITE_OS_SEC_TEXT UINT32 *OsArmA32SyscallHandle(UINT32 *regs)
}
regs
[
REG_R0
]
=
ret
;
//R0保存系统调用返回值
OsSaveSignalContext
(
regs
);
//
保存信号上下文现场
OsSaveSignalContext
(
regs
);
//
如果有信号要处理
/* Return the last value of curent_regs. This supports context switches on return from the exception.
* That capability is only used with theSYS_context_switch system call.
...
...
zzz/git/push.sh
浏览文件 @
87137deb
git add
-A
git commit
-m
'
信号模块代码注解
git commit
-m
'
注解信号注册,发送过程
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
https://my.oschina.net/weharmony
'
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录