0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

鸿蒙内核源码分析:如何安装和发送信号?

鸿蒙系统HarmonyOS 来源:my.oschina 作者:鸿蒙内核源码分析 2021-04-23 17:27 次阅读

信号生产

关于信号篇,本只想写一篇,但发现把它想简单了,内容不多,难度极大.整理了好长时间,理解了为何<<深入理解linux内核>>要单独为它开一章,原因有二

信号相关的结构体多,而且还容易搞混.所以看本篇要注意结构体的名字和作用.

系统调用太多了,涉及面广,信号的来源分硬件和软件.相当于软中断和硬中断,这就会涉及到汇编代码,但信号的处理函数又在用户空间,CPU是禁止内核态执行用户态代码的,所以运行过程需在用户空间和内核空间来回的折腾,频繁的切换上下文.

信号思想来自Unix,在发展了50年之后,许多方面都没有发生太大的变化.信号可以由内核产生,也可以由用户进程产生,并由内核传送给特定的进程或线程(组),若这个进程定义了自己的信号处理程序,则调用这个程序去处理信号,否则则执行默认的程序或者忽略.

信号为系统提供了一种进程间异步通讯的方式,一个进程不必通过任何操作来等待信号的到达。事实上,进程也不可能知道信号到底什么时候到达。一般来说,只需用户进程提供信号处理函数,内核会想方设法调用信号处理函数,网上查阅了很多的关于信号的资料.个人想换个视角去看信号.把异步过程理解为生产者(安装和发送信号)和消费者(捕捉和处理信号)两个过程.鉴于此,系列篇将分成两篇说明,本篇为信号生产篇

信号分类

每个信号都有一个名字和编号,这些名字都以SIG开头,例如SIGQUIT、SIGCHLD等等。 信号定义在signal.h头文件中,信号名都定义为正整数。 具体的信号名称可以使用kill -l来查看信号的名字以及序号,信号是从1开始编号的,不存在0号信号。不过kill对于信号0有特殊的应用。啥用呢? 可用来查询进程是否还在. 敲下kill 0 pid就知道了.

信号分为两大类:可靠信号与不可靠信号,前32种信号为不可靠信号,后32种为可靠信号。

不可靠信号: 也称为非实时信号,不支持排队,信号可能会丢失, 比如发送多次相同的信号, 进程只能收到一次. 信号值取值区间为1~31;

可靠信号: 也称为实时信号,支持排队, 信号不会丢失, 发多少次, 就可以收到多少次. 信号值取值区间为32~64

  #define SIGHUP    1	//终端挂起或者控制进程终止
  #define SIGINT    2	//键盘中断(ctrl + c)
  #define SIGQUIT   3	//键盘的退出键被按下
  #define SIGILL    4	//非法指令
  #define SIGTRAP   5	//跟踪陷阱(trace trap),启动进程,跟踪代码的执行
  #define SIGABRT   6	//由abort(3)发出的退出指令
  #define SIGIOT    SIGABRT //abort发出的信号
  #define SIGBUS    7	//总线错误 
  #define SIGFPE    8	//浮点异常
  #define SIGKILL   9	//常用的命令 kill 9 123 | 不能被忽略、处理和阻塞
  #define SIGUSR1   10	//用户自定义信号1 
  #define SIGSEGV   11	//无效的内存引用, 段违例(segmentation     violation),进程试图去访问其虚地址空间以外的位置 
  #define SIGUSR2   12	//用户自定义信号2
  #define SIGPIPE   13	//向某个非读管道中写入数据 
  #define SIGALRM   14	//由alarm(2)发出的信号,默认行为为进程终止
  #define SIGTERM   15	//终止信号
  #define SIGSTKFLT 16	//栈溢出
  #define SIGCHLD   17	//子进程结束信号
  #define SIGCONT   18	//进程继续(曾被停止的进程)
  #define SIGSTOP   19	//终止进程  	 | 不能被忽略、处理和阻塞
  #define SIGTSTP   20	//控制终端(tty)上 按下停止键
  #define SIGTTIN   21	//进程停止,后台进程企图从控制终端读
  #define SIGTTOU   22	//进程停止,后台进程企图从控制终端写
  #define SIGURG    23	//I/O有紧急数据到达当前进程
  #define SIGXCPU   24	//进程的CPU时间片到期
  #define SIGXFSZ   25	//文件大小的超出上限
  #define SIGVTALRM 26	//虚拟时钟超时
  #define SIGPROF   27	//profile时钟超时
  #define SIGWINCH  28	//窗口大小改变
  #define SIGIO     29	//I/O相关
  #define SIGPOLL   29	//
  #define SIGPWR    30	//电源故障,关机
  #define SIGSYS    31	//系统调用中参数错,如系统调用号非法 
  #define SIGUNUSED SIGSYS//不使用

  #define _NSIG 65

信号来源

信号来源分为硬件类和软件类:

硬件类

用户输入:比如在终端上按下组合键ctrl+C,产生SIGINT信号;

硬件异常:CPU检测到内存非法访问等异常,通知内核生成相应信号,并发送给发生事件的进程;

软件类

通过系统调用,发送signal信号:kill(),raise(),sigqueue(),alarm(),setitimer(),abort()

kill命令就是一个发送信号的工具,用于向进程或进程组发送信号.例如:kill 9 PID(SIGKILL)来杀死PID进程.

sigqueue():只能向一个进程发送信号,不能向进程组发送信号;主要针对实时信号提出,与sigaction()组合使用,当然也支持非实时信号的发送;

alarm():用于调用进程指定时间后发出SIGALARM信号;

setitimer():设置定时器,计时达到后给进程发送SIGALRM信号,功能比alarm更强大;

abort():向进程发送SIGABORT信号,默认进程会异常退出。

raise():用于向进程自身发送信号;

信号与进程的关系

主要是通过系统调用sigaction将用户态信号处理函数注册到PCB保存.所有进程的任务都共用这个信号注册函数sigHandler,在信号的消费阶段内核用一种特殊的方式'回调'它.

typedef struct ProcessCB {//PCB中关于信号的信息
    UINTPTR              sigHandler;   /**< signal handler */   //捕捉信号后的处理函数
    sigset_t             sigShare;     /**< signal share bit */	//信号共享位,64个信号各站一位
}LosProcessCB;
typedef unsigned _Int64 sigset_t; //一个64位的变量,每个信号代表一位.

struct sigaction {//信号处理机制结构体
	union {
		void (*sa_handler)(int); //信号处理函数——普通版
		void (*sa_sigaction)(int, siginfo_t *, void *);//信号处理函数——高级版
	} __sa_handler;
	sigset_t sa_mask;//指定信号处理程序执行过程中需要阻塞的信号;
	int sa_flags;	 //标示位
					 //	SA_RESTART:使被信号打断的syscall重新发起。
					 //	SA_NOCLDSTOP:使父进程在它的子进程暂停或继续运行时不会收到 SIGCHLD 信号。
					 //	SA_NOCLDWAIT:使父进程在它的子进程退出时不会收到SIGCHLD信号,这时子进程如果退出也不会成为僵 尸进程。
					 //	SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。
					 //	SA_RESETHAND:信号处理之后重新设置为默认的处理方式。
					 //	SA_SIGINFO:使用sa_sigaction成员而不是sa_handler作为信号处理函数。
	void (*sa_restorer)(void);
};
typedef struct sigaction sigaction_t;

解读

每个信号都对应一个位. 信号从1开始编号 [1 ~ 64] 对应sigShare的[0 ~ 63]位,所以中间会差一个.记住这点,后续代码会提到.

sigHandler信号处理函数的注册过程,由系统调用sigaction(用户空间) ->OsSigAction(内核空间)完成绑定动作.

#include 
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);
int OsSigAction(int sig, const sigaction_t *act, sigaction_t *oact)
{
    UINTPTR addr;
    sigaction_t action;

    if (!GOOD_SIGNO(sig) || sig < 1 || act == NULL) {
        return -EINVAL;
    }
    //将数据从用户空间拷贝到内核空间
    if (LOS_ArchCopyFromUser(&action, act, sizeof(sigaction_t)) != LOS_OK) {
        return -EFAULT;
    }

    if (sig == SIGSYS) {//鸿蒙此处通过错误的系统调用 来安装信号处理函数,有点巧妙. 
        addr = OsGetSigHandler();//获取进程信号处理函数
        if (addr == 0) {//进程没有设置信号处理函数时
            OsSetSigHandler((unsigned long)(UINTPTR)action.sa_handler);//设置进程信号处理函数——普通版
            return LOS_OK;
        }
        return -EINVAL;
    }

    return LOS_OK;
}

sigaction(...)第一个参数是要安装的信号; 第二个参数与sigaction函数同名的结构体,这里会让人很懵,函数名和结构体一直,没明白为毛要这么搞? 结构体内定义了信号处理方法;第三个为输出参数,将信号的当前的sigaction结构带回.但鸿蒙显然没有认真对待第三个参数.把musl实现给阉割了.

对结构体的sigaction鸿蒙目前只支持信号处理函数——普通版,sa_handler表示自定义信号处理函数,该函数返回值为void,可以带一个int参数,通过参数可以得知当前信号的编号,这样就可以用同一个函数处理多种信号。

sa_mask指定信号处理程序执行过程中需要阻塞的信号。

sa_flags字段包含一些选项,具体看注释

sa_sigaction是实时信号的处理函数,union二选一.鸿蒙暂时不支持这种方式.

信号与任务的关系

typedef struct {//TCB中关于信号的信息
    sig_cb          sig;	//信号控制块,用于异步通信,类似于 linux singal模块
} LosTaskCB;
typedef struct {//信号控制块(描述符)
    sigset_t sigFlag;		//不屏蔽的信号标签集
    sigset_t sigPendFlag;	//信号阻塞标签集,记录因哪些信号被阻塞
    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         */	//任务在等待阻塞信号
    siginfo_t sigunbinfo; /* Signal info when task unblocked     */	//任务解锁时的信号信息
    sig_switch_context context;	//信号切换上下文, 用于保存切换现场, 比如发生系统调用时的返回,涉及同一个任务的两个栈进行切换							
} sig_cb;

解读

系列篇已多次说过,进程只是管理资源的容器,真正让cpu干活的是任务task,所以发给进程的信号最终还是需要分发给具体任务来处理.所以能想到的是关于任务部分会更复杂.

context信号处理很复杂的原因在于信号的发起在用户空间,发送需要系统调用,而处理信号的函数又是用户空间提供的, 所以需要反复的切换任务上下文.而且还有硬中断的问题,比如 ctrl + c ,需要从硬中断中回调用户空间的信号处理函数,处理完了再回到内核空间,最后回到用户空间.没听懂吧,我自己都说晕了,所以需要专门的一篇来说清楚信号的处理问题.本篇不展开说.

sig_cb结构体是任务处理信号的结构体,要响应,屏蔽哪些信号等等都由它完成,这个结构体虽不复杂,但是很绕,很难搞清楚它们之间的区别.笔者是经过一番痛苦的阅读理解后才明白各自的含义.并想通过用打比方的例子试图让大家明白.

以下用追女孩打比方理解.任务相当于某个男,没错说的就是屏幕前的你,除了苦逼的码农谁会有耐心能坚持看到这里.64个信号对应64个女孩.允许一男同时追多个女孩,女孩也可同时被多个男追.女孩也可以主动追男的.理解如下:

waitList等待信号的任务链表,上面挂的是因等待信号而被阻塞的任务.众男在排队追各自心爱的女孩们,处于无所事事的挂起的状态,等待女孩们的出现.

sigwaitmask任务在等待的信号集合,只有这些信号能唤醒任务.相当于列出喜欢的各位女孩,只要出现一位就能让你满血复活.

sigprocmask指任务对哪些信号不感冒.来了也不处理.相当于列出不喜欢的各位女孩,请她们别来骚扰你,嘚瑟.

sigPendFlag信号到达但并未唤醒任务.相当于喜欢你的女孩来追你,但她不在你喜欢的列表内,结果是不搭理人家继续等喜欢的出现.

sigFlag记录不屏蔽的信号集合,相当于你并不反感的女孩们.记录来过的那些女孩(除掉你不喜欢的).

信号发送过程

用户进程调用kill()的过程如下:

kill(pid_t pid, int sig) - 系统调用   
|                    用户空间
---------------------------------------------------------------------------------------
|                    内核空间
SysKill(...)
|---> OsKillLock(...)
    |---> OsKill(.., OS_USER_KILL_PERMISSION)
        |---> OsDispatch()  //鉴权,向进程发送信号
            |---> OsSigProcessSend()    //选择任务发送信号
                |---> OsSigProcessForeachChild(..,ForEachTaskCB handler,..)
                    |---> SigProcessKillSigHandler() //处理 SIGKILL
                        |---> OsTaskWake() //唤醒所有等待任务
                        |---> OsSigEmptySet() //清空信号等待集
                    |---> SigProcessSignalHandler()
                        |---> OsTcbDispatch() //向目标任务发送信号
                            |---> OsTaskWake() //唤醒任务
                            |---> OsSigEmptySet() //清空信号等待集

流程

通过 系统调用kill陷入内核空间

因为是用户态进程,使用OS_USER_KILL_PERMISSION权限发送信号

#define OS_KERNEL_KILL_PERMISSION 0U	//内核态 kill 权限
#define OS_USER_KILL_PERMISSION   3U	//用户态 kill 权限

鉴权之后进程轮询任务组,向目标任务发送信号.这里分三种情况:

SIGKILL信号,将所有等待任务唤醒,拉入就绪队列等待被调度执行,并情况信号等待集

非SIGKILL信号时,将通过sigwaitmask和sigprocmask过滤,找到一个任务向它发送信号OsTcbDispatch.

代码细节

    int OsKill(pid_t pid, int sig, int permission)
    {
        siginfo_t info;
        int ret;

        /* Make sure that the para is valid */
        if (!GOOD_SIGNO(sig) || pid < 0) {//有效信号 [0,64]
            return -EINVAL;
        }
        if (OsProcessIDUserCheckInvalid(pid)) {//检查参数进程 
            return -ESRCH;
        }

        /* Create the siginfo structure */ //创建信号结构体
        info.si_signo = sig;	//信号编号
        info.si_code = SI_USER;	//来自用户进程信号
        info.si_value.sival_ptr = NULL;

        /* Send the signal */
        ret = OsDispatch(pid, &info, permission);//发送信号
        return ret;
    }

    //信号分发
    int OsDispatch(pid_t pid, siginfo_t *info, int permission)
    {
        LosProcessCB *spcb = OS_PCB_FROM_PID(pid);//找到这个进程
        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
            return LOS_OK;
        }

        /* Kernel process always has kill permission and user process should check permission *///内核进程总是有kill权限,用户进程需要检查权限
        if (OsProcessIsUserMode(current) && !(current->processStatus & OS_PROCESS_FLAG_EXIT)) {//用户进程检查能力范围
            if ((current != spcb) && (!IsCapPermit(CAP_KILL)) && (current->user->userID != spcb->user->userID)) {
                return -EPERM;
            }
        }
    #endif
        if ((permission == OS_USER_KILL_PERMISSION) && (OsSignalPermissionToCheck(spcb) < 0)) {
            return -EPERM;
        }
        return OsSigProcessSend(spcb, info);//给参数进程发送信号
    }

    //给参数进程发送参数信号
    int OsSigProcessSend(LosProcessCB *spcb, siginfo_t *sigInfo)
    {
        int ret;
        struct ProcessSignalInfo info = {
            .sigInfo = sigInfo, //信号内容
            .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);
            OsWaitSignalToWakeProcess(spcb);//等待信号唤醒进程
            return 0;
        } else {
            ret = OsSigProcessForeachChild(spcb, SigProcessSignalHandler, &info);//进程通知所有task处理信号
        }
        if (ret < 0) {
            return ret;
        }
        SigProcessLoadTcb(&info, sigInfo);
        return 0;
    }
    //让进程的每一个task执行参数函数
    int OsSigProcessForeachChild(LosProcessCB *spcb, ForEachTaskCB handler, void *arg)
    {
        int ret;

        /* 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);//回调参数函数
            OS_RETURN_IF(ret != 0, ret);//这个宏的意思就是只有ret = 0时,啥也不处理.其余就返回 ret
        }
        return LOS_OK;
    }

如果是SIGKILL信号,让spcb的所有任务执行SigProcessKillSigHandler函数,查看旗下的所有任务是否又在等待这个信号的,如果有就将任务唤醒,放在就绪队列等待被调度执行.

//进程收到 SIGKILL 信号后,通知任务tcb处理.
static int SigProcessKillSigHandler(LosTaskCB *tcb, void *arg)
{
    struct ProcessSignalInfo *info = (struct ProcessSignalInfo *)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)) {//如果任务在等待这个信号
            OsTaskWake(tcb);//唤醒这个任务,加入进程的就绪队列,并不申请调度
            OsSigEmptySet(&sigcb->sigwaitmask);//清空信号等待位,不等任何信号了.因为这是SIGKILL信号
        }
    }
    return 0;
}

非SIGKILL信号,让spcb的所有任务执行SigProcessSignalHandler函数

static int SigProcessSignalHandler(LosTaskCB *tcb, void *arg)
{
    struct ProcessSignalInfo *info = (struct ProcessSignalInfo *)arg;//先把参数解出来
    int ret;
    int isMember;

    if (tcb == NULL) {
        return 0;
    }

    /* If the default tcb is not setted, then set this one as default. */
    if (!info->defaultTcb) {//如果没有默认发送方的任务,即默认参数任务.
        info->defaultTcb = tcb;
    }

    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);//发送信号,注意这是给其他任务发送信号,tcb不是当前任务
        OS_RETURN_IF(ret < 0, ret);//这种写法很有意思

        /* set this tcb as awakenedTcb */
        info->awakenedTcb = tcb;
        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)) {//没有屏蔽,有唤醒任务没有接收任务.
        /* if unblockedTcb of this signal is not setted, then set it. */
        if (!info->unblockedTcb) {
            info->unblockedTcb = tcb;
        }

        ret = OsTcbDispatch(tcb, info->sigInfo);//向任务发送信号
        OS_RETURN_IF(ret < 0, ret);
        /* set this tcb as receivedTcb */
        info->receivedTcb = tcb;//设置这个任务为接收任务
        OS_RETURN_IF(info->awakenedTcb != NULL, SIG_STOP_VISIT); /* Stop search */
    }
    return 0; /* Keep searching */
}
解读

函数的意思是,当进程中有多个任务在等待这个信号时,发送信号给第一个等待的任务awakenedTcb.

如果没有任务在等待信号,那就从不屏蔽这个信号的任务集中随机找一个receivedTcb接受信号.

只要不屏蔽unblockedTcb就有值,随机的.

如果上面的都不满足,信号发送给defaultTcb.

寻找发送任务的优先级是awakenedTcb>receivedTcb>unblockedTcb>defaultTcb

信号相关函数

信号集操作函数

sigemptyset(sigset_t *set):信号集全部清0;

sigfillset(sigset_t *set): 信号集全部置1,则信号集包含linux支持的64种信号;

sigaddset(sigset_t *set, int signum):向信号集中加入signum信号;

sigdelset(sigset_t *set, int signum):向信号集中删除signum信号;

sigismember(const sigset_t *set, int signum):判定信号signum是否存在信号集中。

信号阻塞函数

sigprocmask(int how, const sigset_t *set, sigset_t *oldset)); 不同how参数,实现不同功能

SIG_BLOCK:将set指向信号集中的信号,添加到进程阻塞信号集;

SIG_UNBLOCK:将set指向信号集中的信号,从进程阻塞信号集删除;

SIG_SETMASK:将set指向信号集中的信号,设置成进程阻塞信号集;

sigpending(sigset_t *set)):获取已发送到进程,却被阻塞的所有信号;

sigsuspend(const sigset_t *mask)):用mask代替进程的原有掩码,并暂停进程执行,直到收到信号再恢复原有掩码并继续执行进程。

编辑:hfy

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • cpu
    cpu
    +关注

    关注

    68

    文章

    10443

    浏览量

    206565
  • 实时信号
    +关注

    关注

    0

    文章

    4

    浏览量

    5176
  • 鸿蒙系统
    +关注

    关注

    183

    文章

    2619

    浏览量

    65273
收藏 人收藏

    评论

    相关推荐

    鸿蒙内核源码分析:用通俗易懂的语言告诉你鸿蒙内核发生了什么?

    查看。内存在内核的比重极大内存模块占了鸿蒙内核约15%代码量, 近50个文件,非常复杂。鸿蒙源码分析
    发表于 11-19 10:14

    鸿蒙内核源码分析源码注释篇):给HarmonyOS源码逐行加上中文注释

    都懂的概念去诠释或者映射一个他们从没听过的概念.说别人能听得懂的话这很重要!!! 一个没学过计算机知识的卖菜大妈就不可能知道内核的基本运作了吗? NO!,笔者在系列篇中试图用 鸿蒙源码分析
    发表于 11-19 10:32

    鸿蒙内核源码分析:给HarmonyOS源码逐行加上中文注释

    过计算机知识的卖菜大妈就不可能知道内核的基本运作了吗? NO!,笔者在系列篇中试图用 鸿蒙源码分析系列篇|张大爷系列故事【 CSDN | OSCHINA】 去构建这一层级的认知,希望能
    发表于 11-19 15:06

    鸿蒙源码分析系列(总目录) | 给HarmonyOS源码逐行加上中文注释

    同步更新。鸿蒙源码分析系列篇|- 鸿蒙内核源码分析
    发表于 11-20 11:24

    鸿蒙内核源码分析(内存概念篇) :手眼通天的虚拟内存

    最难讲的章节内存模块占了 HarmonyOS 内核约15%代码量, 近20个.c文件,很复杂。系列篇将用九篇来介绍HarmonyOS内存部分,分别是 鸿蒙内核源码
    发表于 11-20 13:52

    鸿蒙内核源码分析(内存概念篇) :手眼通天的虚拟内存

    内存模块占了 HarmonyOS 内核约15%代码量, 近20个.c文件,很复杂。系列篇将用九篇来介绍HarmonyOS内存部分,分别是 鸿蒙内核源码
    发表于 11-20 16:30

    鸿蒙内核源码分析(必读篇):用故事说内核

    本文基于开源鸿蒙内核分析,官方源码【kernel_liteos_a】官方文档【docs】参考文档【Huawei LiteOS】本文作者:鸿蒙
    发表于 11-23 10:15

    鸿蒙内核源码分析(必读篇)

    本文基于开源鸿蒙内核分析,官方源码【kernel_liteos_a】官方文档【docs】参考文档【Huawei LiteOS】本文作者:鸿蒙
    发表于 11-25 09:28

    HarmonyOS内核源码分析(上)电子书-上线了

    `为方便大家开发鸿蒙系统,小编为大家编辑整理了一本HarmonyOS内核源码分析系列电子书,需要参考学习的朋友快来下吧!本电子书主要介绍如何给鸿蒙
    发表于 11-25 17:13

    鸿蒙内核源码分析(百篇博客分析.挖透鸿蒙内核)

    致敬内核开发者感谢开放原子开源基金会,致敬鸿蒙内核开发者。可以毫不夸张的说鸿蒙内核源码可作为大学
    发表于 07-04 17:16

    为何要精读鸿蒙内核源码?

    一个没学过计算机知识的卖菜大妈就不可能知道内核的基本运作了吗? 不一定!在系列篇中试图用 鸿蒙内核源码分析(总目录)之故事篇 去引导这一层级
    的头像 发表于 04-26 15:00 1459次阅读
    为何要精读<b class='flag-5'>鸿蒙</b><b class='flag-5'>内核</b><b class='flag-5'>源码</b>?

    鸿蒙内核源码分析鸿蒙内核的每段汇编代码解析

    本篇说清楚CPU的工作模式 读本篇之前建议先读鸿蒙内核源码分析(总目录)其他篇. 正如一个互联网项目的后台管理系统有权限管理一样,CPU工作是否也有权限(模式)? 一个成熟的软硬件架构
    的头像 发表于 03-02 09:56 3731次阅读
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>内核</b><b class='flag-5'>源码</b><b class='flag-5'>分析</b>:<b class='flag-5'>鸿蒙</b><b class='flag-5'>内核</b>的每段汇编代码解析

    鸿蒙内核源码分析: 虚拟内存和物理内存是怎么管理的

    有了上篇鸿蒙内核源码分析(内存概念篇)的基础,本篇讲内存管理部分,本章源码超级多,很烧脑,但笔者关键处都加了注释。废话不多说,开始吧。内存一
    发表于 11-23 11:45 19次下载
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>内核</b><b class='flag-5'>源码</b><b class='flag-5'>分析</b>: 虚拟内存和物理内存是怎么管理的

    鸿蒙内核源码分析内核最重要结构体

    为何鸿蒙内核源码分析系列开篇就说 LOS_DL_LIST ? 因为它在鸿蒙 LOS 内核中无处
    发表于 11-24 17:54 35次下载
    <b class='flag-5'>鸿蒙</b><b class='flag-5'>内核</b><b class='flag-5'>源码</b><b class='flag-5'>分析</b> :<b class='flag-5'>内核</b>最重要结构体

    华为鸿蒙系统内核源码分析上册

    鸿蒙內核源码注释中文版【 Gitee仓】给 Harmoηy○S源码逐行加上中文注解,详细阐述设计细节,助你快速精读 Harmonyos内核源码
    发表于 04-09 14:40 16次下载