Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >OpenHarmony 内核源码分析(远程登录篇) | 内核如何接待远方的客人

OpenHarmony 内核源码分析(远程登录篇) | 内核如何接待远方的客人

原创
作者头像
小帅聊鸿蒙
发布于 2025-04-01 05:45:08
发布于 2025-04-01 05:45:08
7900
代码可运行
举报
文章被收录于专栏:鸿蒙开发笔记鸿蒙开发笔记
运行总次数:0
代码可运行

什么是远程登录?

  • 每个人都有上门做客的经历,抖音也一直在教我们做人,做客不要空手去,总得带点东西,而对中国人你就不能送,不能送,最好也别送,因他们与 终 离 邪 谐音,犯忌讳. 这是人情世故,叫礼仪,是中华文明圈的共识,是相互交流信任的基础.
  • 那互联网圈有没有这种共识呢? 当然有,互联网世界的人情世故就是协议, 种种协议映射到人类社会来说就是种种礼仪,协议有TCP,HTTP,SSH,Telnet等等,就如同礼仪分商业礼仪,外交礼仪,校园礼仪,家庭礼仪等等. 孔圣人不也说 不学礼,无以立 应该就是这个道理, 登门拜访的礼仪可类比远程登录协议Telnet. 来了就跟自己家一样, 我家的东西就是你家的,随便用,甭客气.

Telnet协议的具体内容可以查看以下文档.

协议

时间

英文版

中文版

标题

Telnet

1983

rfc854

rfc854

TELNET PROTOCOL SPECIFICATION(远程登录协议规范)

Telnet

1983

rfc855

rfc855

TELNET OPTION SPECIFICATIONS(远程登录选项规范)

Telnet协议细节不是本篇讨论的重点,后续会有专门的 Lwip协议栈 系列博客说清楚.本篇要说清楚的是内核如何接待远方的客人.

Shell | 控制台 | 远程登录模型

对远程登录来有客户端和服务端的说法,跟别人来你家你是主人和你去别人家你是客人一样,身份不同,职责不同,主人要做的事明显要更多,本篇只说鸿蒙对telnet服务端的实现,说清楚它是如何接待外面来的客人.至于图中提到的客户端任务是指主人为每个客人专门提供了一个对接人的意思.下图为看完三部分源码后整理的模型图

模型解释

  • 通过本地的shell命令telnet on启动远程登录模块,由此创建Telnet的服务任务TelnetServer
  • TelnetServer任务,创建socket监听23端口,接受来自远程终端的 telnet xx.xx.xx.xx 23请求
  • 收到请求后创建一个TelnetClientLoop用于接待客户的任务,对接详细的客户需求.
  • 在接待客户期间创建一个远程登录类型的控制台,来处理和转发远程客户的请求给shell进程最终执行远程命令.
  • shell处理完成后通过专门的任务SendToSer回写远程终端,控制台部分详细看 系列篇的(控制台篇)

鸿蒙是如何实现的?

1. 启动 Telnet
代码语言:c
代码运行次数:0
运行
AI代码解释
复制
//SHELLCMD_ENTRY(telnet_shellcmd, CMD_TYPE_EX, "telnet", 1, (CmdCallBackFunc)TelnetCmd);/// 以静态方式注册shell 命令
/// 本命令用于启动或关闭telnet server服务 
INT32 TelnetCmd(UINT32 argc, const CHAR **argv)
{
    if (strcmp(argv[0], "on") == 0) { // 输入 telnet on
        /* telnet on: try to start telnet server task */
        TelnetdTaskInit(); //启动远程登录 服务端任务
        return 0;
    }
    if (strcmp(argv[0], "off") == 0) {// 输入 telnet off
        /* telnet off: try to stop clients, then stop server task */
        TelnetdTaskDeinit();//关闭所有的客户端,并关闭服务端任务
        return 0;
    }
    return 0;
}
2. 创建Telnet服务端任务
代码语言:c
代码运行次数:0
运行
AI代码解释
复制
STATIC VOID TelnetdTaskInit(VOID)
{
    UINT32 ret;
    TSK_INIT_PARAM_S initParam = {0};
    initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)TelnetdMain; // telnet任务入口函数
    initParam.uwStackSize = TELNET_TASK_STACK_SIZE;	// 8K
    initParam.pcName = "TelnetServer"; //任务名称
    initParam.usTaskPrio = TELNET_TASK_PRIORITY; //优先级 9,和 shell 的优先级一样
    initParam.uwResved = LOS_TASK_STATUS_DETACHED; //独立模式
    if (atomic_read(&g_telnetTaskId) != 0) {//只支持一个 telnet 服务任务
        PRINT_ERR("telnet server is already running!\n");
        return;
    }
    ret = LOS_TaskCreate((UINT32 *)&g_telnetTaskId, &initParam);//创建远程登录服务端任务并发起调度
}
3. Telnet服务端任务入口函数
代码语言:c
代码运行次数:0
运行
AI代码解释
复制
//远程登录操作命令
STATIC const struct file_operations_vfs g_telnetOps = {
    TelnetOpen,
    TelnetClose,
    TelnetRead,
    TelnetWrite,
    NULL,
    TelnetIoctl,
    NULL,
#ifndef CONFIG_DISABLE_POLL
    TelnetPoll,
#endif
    NULL,
};
STATIC INT32 TelnetdMain(VOID)
{
    sock = TelnetdInit(TELNETD_PORT);//1.初始化创建 socket ,socket的本质就是打开了一个虚拟文件
    TelnetLock();
    ret = TelnetedRegister();//2.注册驱动程序 /dev/telnet ,g_telnetOps g_telnetDev
    TelnetUnlock();
    TelnetdAcceptLoop(sock);//3.等待连接,处理远程终端过来的命令 例如#task 命令
    return 0;
}
DD一下:欢迎大家关注公众号<程序猿百晓生>,可以了解到以下知识点。
代码语言:erlang
AI代码解释
复制
`欢迎大家关注公众号<程序猿百晓生>,可以了解到以下知识点。`
1.OpenHarmony开发基础
2.OpenHarmony北向开发环境搭建
3.鸿蒙南向开发环境的搭建
4.鸿蒙生态应用开发白皮书V2.0 & V3.0
5.鸿蒙开发面试真题(含参考答案) 
6.TypeScript入门学习手册
7.OpenHarmony 经典面试题(含参考答案)
8.OpenHarmony设备开发入门【最新版】
9.沉浸式剖析OpenHarmony源代码
10.系统定制指南
11.OpenHarmonyUboot 驱动加载流程
12.OpenHarmony构建系统--GN与子系统、部件、模块详解
13.ohos开机init启动流程
14.鸿蒙版性能优化指南
.......
4. 循环等待远程终端的连接请求
代码语言:c
代码运行次数:0
运行
AI代码解释
复制
STATIC VOID TelnetdAcceptLoop(INT32 listenFd)
{
    while (g_telnetListenFd >= 0) {//必须启动监听
        TelnetUnlock();
        (VOID)memset_s(&inTelnetAddr, sizeof(inTelnetAddr), 0, sizeof(inTelnetAddr));
        clientFd = accept(listenFd, (struct sockaddr *)&inTelnetAddr, (socklen_t *)&len);//接收数据
        if (TelnetdAcceptClient(clientFd, &inTelnetAddr) == 0) {//
            /*
             * Sleep sometime before next loop: mostly we already have one connection here,
             * and the next connection will be declined. So don't waste our cpu.
             | 在下一个循环来临之前休息片刻,因为鸿蒙只支持一个远程登录,此时已经有一个链接,
             在TelnetdAcceptClient中创建线程不会立即调度, 休息下任务会挂起,重新调度
             */
            LOS_Msleep(TELNET_ACCEPT_INTERVAL);//以休息的方式发起调度. 直接申请调度也未尝不可吧 @note_thinking 
        } else {
            return;
        }
        TelnetLock();
    }
    TelnetUnlock();
}
5. 远方的客人到来,安排专人接待

鸿蒙目前只支持接待一位远方的客人,g_telnetClientFd是个全局变量,创建专门任务接待客人.

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
STATIC INT32 TelnetdAcceptClient(INT32 clientFd, const struct sockaddr_in *inTelnetAddr)
{
    g_telnetClientFd = clientFd;
	//创建一个线程处理客户端的请求
    if (pthread_create(&tmp, &useAttr, TelnetClientLoop, (VOID *)(UINTPTR)clientFd) != 0) {
        PRINT_ERR("Failed to create client handle task\n");
        g_telnetClientFd = -1;
        goto ERROUT_UNLOCK;
    }
}
6. 接待员做好接待工作

因接待工作很重要,这边把所有代码贴出来,并加上了大量的注释,目的只有一个,让咱客人爽.

代码语言:c
代码运行次数:0
运行
AI代码解释
复制
STATIC VOID *TelnetClientLoop(VOID *arg)
{
    struct pollfd pollFd;
    INT32 ret;
    INT32 nRead;
    UINT32 len;
    UINT8 buf[TELNET_CLIENT_READ_BUF_SIZE];
    UINT8 *cmdBuf = NULL;
    INT32 clientFd = (INT32)(UINTPTR)arg;
    (VOID)prctl(PR_SET_NAME, "TelnetClientLoop", 0, 0, 0);
    TelnetLock();
    if (TelnetClientPrepare(clientFd) != 0) {//做好准备工作
        TelnetUnlock();
        (VOID)close(clientFd);
        return NULL;
    }
    TelnetUnlock();
    while (1) {//死循环接受远程输入的数据
        pollFd.fd = clientFd;
        pollFd.events = POLLIN | POLLRDHUP;//监听读数据和挂起事件
        pollFd.revents = 0;
		/*
		POLLIN 普通或优先级带数据可读
		POLLRDNORM 普通数据可读
		POLLRDBAND 优先级带数据可读
		POLLPRI 高优先级数据可读
		POLLOUT 普通数据可写
		POLLWRNORM 普通数据可写
		POLLWRBAND 优先级带数据可写
		POLLERR 发生错误
		POLLHUP 发生挂起
		POLLNVAL 描述字不是一个打开的文件
		poll本质上和select没有区别,它将用户传入的数组拷贝到内核空间,然后查询每个fd对应的设备状态,
		如果设备就绪则在设备等待队列中加入一项并继续遍历,如果遍历完所有fd后没有发现就绪设备,则挂起当前进程,
		直到设备就绪或者主动超时,被唤醒后它又要再次遍历fd。
	  这个过程经历了多次无谓的遍历。
	  poll还有一个特点是“水平触发”,如果报告了fd后,没有被处理,那么下次poll时会再次报告该fd。
	  poll与select的不同,通过一个pollfd数组向内核传递需要关注的事件,故没有描述符个数的限制,
			pollfd中的events字段和revents分别用于标示关注的事件和发生的事件,故pollfd数组只需要被初始化一次
	  poll的实现机制与select类似,其对应内核中的sys_poll,只不过poll向内核传递pollfd数组,
			然后对pollfd中的每个描述符进行poll,相比处理fdset来说,poll效率更高。poll返回后,
			需要对pollfd中的每个元素检查其revents值,来得指事件是否发生。
			优点
			1)poll() 不要求开发者计算最大文件描述符加一的大小。
			2)poll() 在应付大数目的文件描述符的时候速度更快,相比于select。
			3)它没有最大连接数的限制,原因是它是基于链表来存储的。
			缺点
			1)大量的fd的数组被整体复制于用户态和内核地址空间之间,而不管这样的复制是不是有意义。
			2)与select一样,poll返回后,需要轮询pollfd来获取就绪的描述符
		*/
        ret = poll(&pollFd, 1, TELNET_CLIENT_POLL_TIMEOUT);//等2秒钟返回
        if (ret < 0) {//失败时,poll()返回-1
            break;
			/*	ret < 0 各值
			  EBADF  		一个或多个结构体中指定的文件描述符无效。
			  EFAULTfds   指针指向的地址超出进程的地址空间。
			  EINTR      请求的事件之前产生一个信号,调用可以重新发起。
			  EINVALnfds  参数超出PLIMIT_NOFILE值。
			  ENOMEM  	   可用内存不足,无法完成请求

			*/
        }
        if (ret == 0) {//如果在超时前没有任何事件发生,poll()返回0
            continue;
        }
        /* connection reset, maybe keepalive failed or reset by peer | 连接重置,可能keepalive失败或被peer重置*/
        if ((UINT16)pollFd.revents & (POLLERR | POLLHUP | POLLRDHUP)) {
            break;
        }
        if ((UINT16)pollFd.revents & POLLIN) {//数据事件
            nRead = read(clientFd, buf, sizeof(buf));//读远程终端过来的数据
            if (nRead <= 0) {
                /* telnet client shutdown */
                break;
            }
            cmdBuf = ReadFilter(buf, (UINT32)nRead, &len);//对数据过滤
            if (len > 0) {
                (VOID)TelnetTx((CHAR *)cmdBuf, len);//对数据加工处理
            }
        }
    }
    TelnetLock();
    TelnetClientClose();
    (VOID)close(clientFd);
    clientFd = -1;
    g_telnetClientFd = -1;
    TelnetUnlock();
    return NULL;
}

结语

理解远程登录的实现建议结合 shell编辑篇 ,shell执行篇 ,控制台篇 三篇来理解,实际上它们是上中下三层.

写在最后

如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:

  • 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力;
  • 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识;
  • 想要获取更多完整鸿蒙最新学习知识点,可关注B站:码牛课堂;

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
OpenHarmony 内核源码分析(Shell解析篇) | 应用窥视内核的窗口
系列篇从内核视角用一句话概括shell的底层实现为:两个任务,三个阶段。其本质是独立进程,因而划到进程管理模块。每次创建shell进程都会再创建两个任务。
小帅聊鸿蒙
2025/03/31
850
OpenHarmony 内核源码分析(Shell解析篇) | 应用窥视内核的窗口
OpenHarmony 内核源码分析(Shell编辑篇) | 两个任务,三个阶段
系列篇从内核视角用一句话概括shell的底层实现为:两个任务,三个阶段。其本质是独立进程,因而划到进程管理模块。每次创建shell进程都会再创建两个任务。
小帅聊鸿蒙
2025/03/31
690
OpenHarmony 内核源码分析(控制台篇)
ConsoleTaskReg将 shellCB和consoleCB捆绑在一块,二者可以相互查找.ShellEntry任务个人更愿意称之为shell的客户端任务,用死循环不断一个字符一个字符的读取用户的输入,为何要单字符 读取可翻看系列篇的Shell编辑篇,简单的说是因为要处理控制字符(如:删除,回车==)
小帅聊鸿蒙
2025/03/31
840
OpenHarmony 内核源码分析(控制台篇)
OpenHarmony 内核源码分析(时间管理篇) | 谁是内核基本时间单位
时间管理以系统时钟 g_sysClock 为基础,给应用程序提供所有和时间有关的服务。
小帅聊鸿蒙
2025/03/17
760
OpenHarmony内核源码分析(任务调度篇) | 任务是内核调度的单元
从系统的角度看,线程是竞争系统资源的最小运行单元。线程可以使用或等待CPU、使用内存空间等系统资源,并独立于其它线程运行。
小帅聊鸿蒙
2025/03/07
680
OpenHarmony 内核源码分析(特殊进程篇)
2号进程为内核态的老祖宗,是内核创建的首个进程,源码过程如下,省略了不相干的代码.
小帅聊鸿蒙
2025/03/21
670
OpenHarmony 内核源码分析(特殊进程篇)
OpenHarmony 内核源码分析(中断管理篇) | 江湖从此不再怕中断
hi3516dv300 中断控制器选择了 LOSCFG_PLATFORM_BSP_GIC_V2 ,对应代码为 gic_v2.c
小帅聊鸿蒙
2025/03/20
790
OpenHarmony 内核源码分析(中断管理篇) | 江湖从此不再怕中断
OpenHarmony 内核源码分析(Fork篇) | 一次调用,两次返回
笔者第一次看到fork时,说是一次调用,两次返回,当时就懵圈了,多新鲜,真的很难理解.因为这足以颠覆了以往对函数的认知, 函数调用还能这么玩,父进程调用一次,父子进程各返回一次.而且只能通过返回值来判断是哪个进程的返回.所以一直有几个问题缠绕在脑海中.
小帅聊鸿蒙
2025/03/20
590
OpenHarmony 内核源码分析(Fork篇) | 一次调用,两次返回
OpenHarmony 内核源码分析(原子操作篇) | 谁在为原子操作保驾护航
在支持多任务的操作系统中,修改一块内存区域的数据需要“读取-修改-写入”三个步骤。然而同一内存区域的数据可能同时被多个任务访问,如果在修改数据的过程中被其他任务打断,就会造成该操作的执行结果无法预知。
小帅聊鸿蒙
2025/03/17
690
OpenHarmony 内核源码分析(原子操作篇) | 谁在为原子操作保驾护航
OpenHarmony 内核源码分析(读写锁) | 内核如何实现多读单写
读写锁 :是计算机程序的并发控制的一种同步机制,也称“共享-互斥锁”、多读者-单写者锁。读操作可并发重入,写操作是互斥的。
小帅聊鸿蒙
2025/04/02
330
OpenHarmony 内核源码分析(管道文件篇) | 如何降低数据流动成本
管道符号是两个命令之间的一道竖杠 |,简单而优雅,例如,ls用于显示某个目录中文件,wc用于统计行数.
小帅聊鸿蒙
2025/03/30
581
OpenHarmony 内核源码分析(管道文件篇) | 如何降低数据流动成本
OpenHarmony内核源码分析(调度队列篇) | 内核有多少个调度队列
鸿蒙内核代码中有两个源文件是关于队列的,一个是用于调度的队列,另一个是用于线程间通讯的IPC队列。
小帅聊鸿蒙
2025/03/07
590
OpenHarmony内核源码分析(调度队列篇) | 内核有多少个调度队列
OpenHarmony 内核源码分析(任务切换篇) | 看汇编如何切换任务
您一定注意到了TaskContext,说的全是它,这就是任务上下文结构体,理解它是理解任务切换的钥匙.它不仅在C语言层面出现,而且还在汇编层出现,TaskContext是连接或者说打通 C->汇编->C 实现任务切换的最关键概念.本篇全是围绕着它来展开.先看看它张啥样,LOOK!
小帅聊鸿蒙
2025/03/19
800
OpenHarmony 内核源码分析(文件句柄篇) | 你为什么叫句柄?
只要写过应用程序代码操作过文件不会陌生这几个函数,文件操作的几个关键步骤嘛,跟把大象装冰箱分几步一样.先得把冰箱门打开,再把大象放进去,再关上冰箱门.其中最重要的一个参数就是fd,应用程序所有对文件的操作都基于它.fd可称为文件描述符,或者叫文件句柄(handle),个人更愿意称后者. 因为更形象,handle英文有手柄的意思,跟开门一样,握住手柄才能开门,手柄是进门关门的抓手.映射到文件系统,fd是应用层出入内核层的抓手.句柄是一个数字编号, open | creat去申请这个编号,内核会创建文件相关的一系列对象,返回编号,后续通过编号就可以操作这些对象.原理就是这么的简单,本篇将从fd入手,跟踪文件操作的整个过程.
小帅聊鸿蒙
2025/03/30
940
OpenHarmony 内核源码分析(消息封装篇) | 剖析LiteIpc 进程通讯内容
LiteIPC是OpenHarmony LiteOS-A内核提供的一种新型IPC(Inter-Process Communication,即进程间通信)机制,为轻量级进程间通信组件,为面向服务的系统服务框架提供进程间通信能力,分为内核实现和用户态实现两部分,其中内核实现完成进程间消息收发、IPC内存管理、超时通知和死亡通知等功能;用户态提供序列化和反序列化能力,并完成IPC回调消息和死亡消息的分发。
小帅聊鸿蒙
2025/04/01
600
OpenHarmony 内核源码分析(调度机制篇) | 任务是如何被调度执行的
鸿蒙的内核中 Task 和 线程 在广义上可以理解为是一个东西,但狭义上肯定会有区别,区别在于管理体系的不同,Task是调度层面的概念,线程是进程层面概念。比如 main() 函数中首个函数 OsSetMainTask(); 就是设置启动任务,但此时啥都还没开始呢,Kprocess 进程都没创建,怎么会有大家一般意义上所理解的线程呢。狭义上的后续有 鸿蒙内核源码分析(启动过程篇) 来说明。不知道大家有没有这种体会,学一个东西的过程中要接触很多新概念,尤其像 Java/android 的生态,概念贼多,很多同学都被绕在概念中出不来,痛苦不堪。那问题是为什么需要这么多的概念呢?
小帅聊鸿蒙
2025/03/07
980
OpenHarmony 内核源码分析(调度机制篇) | 任务是如何被调度执行的
OpenHarmony内核源码分析——(自旋锁篇)
自旋锁顾名思义,是一把自动旋转的锁,这很像厕所里的锁,进入前标记是绿色可用的,进入格子间后,手一带,里面的锁转个圈,外面标记变成了红色表示在使用,外面的只能等待.这是形象的比喻,但实际也是如此.
小帅聊鸿蒙
2025/03/13
520
OpenHarmony内核源码分析——(自旋锁篇)
OpenHarmony内核源码分析(内存管理篇) | 虚拟内存全景图是怎样的
内存一开始一张白纸,这些extern就是给它画大界线的,从哪到哪是属于什么段。这些值大小取决实际项目内存条的大小,不同的内存条,地址肯定会不一样,所以必须由外部提供,鸿蒙内核采用了Linux的段管理方式。结合上图对比以下的解释自行理解下位置。
小帅聊鸿蒙
2025/03/08
930
OpenHarmony内核源码分析(内存管理篇) | 虚拟内存全景图是怎样的
OpenHarmony 内核源码分析(内核态锁篇) | 如何实现快锁Futex(下)
本篇为快锁下篇,说清楚快锁在内核态的实现,解答以下问题,它们在上篇的末尾被提出来。
小帅聊鸿蒙
2025/04/02
660
OpenHarmony 内核源码分析(内核态锁篇) | 如何实现快锁Futex(下)
OpenHarmony 内核源码分析(物理内存篇) | 怎么管理物理内存
鸿蒙内核物理内存采用了段页式管理,先看两个主要结构体.结构体的每个成员变量的含义都已经注解出来,请结合源码理解.
小帅聊鸿蒙
2025/03/10
1010
OpenHarmony 内核源码分析(物理内存篇) | 怎么管理物理内存
推荐阅读
OpenHarmony 内核源码分析(Shell解析篇) | 应用窥视内核的窗口
850
OpenHarmony 内核源码分析(Shell编辑篇) | 两个任务,三个阶段
690
OpenHarmony 内核源码分析(控制台篇)
840
OpenHarmony 内核源码分析(时间管理篇) | 谁是内核基本时间单位
760
OpenHarmony内核源码分析(任务调度篇) | 任务是内核调度的单元
680
OpenHarmony 内核源码分析(特殊进程篇)
670
OpenHarmony 内核源码分析(中断管理篇) | 江湖从此不再怕中断
790
OpenHarmony 内核源码分析(Fork篇) | 一次调用,两次返回
590
OpenHarmony 内核源码分析(原子操作篇) | 谁在为原子操作保驾护航
690
OpenHarmony 内核源码分析(读写锁) | 内核如何实现多读单写
330
OpenHarmony 内核源码分析(管道文件篇) | 如何降低数据流动成本
581
OpenHarmony内核源码分析(调度队列篇) | 内核有多少个调度队列
590
OpenHarmony 内核源码分析(任务切换篇) | 看汇编如何切换任务
800
OpenHarmony 内核源码分析(文件句柄篇) | 你为什么叫句柄?
940
OpenHarmony 内核源码分析(消息封装篇) | 剖析LiteIpc 进程通讯内容
600
OpenHarmony 内核源码分析(调度机制篇) | 任务是如何被调度执行的
980
OpenHarmony内核源码分析——(自旋锁篇)
520
OpenHarmony内核源码分析(内存管理篇) | 虚拟内存全景图是怎样的
930
OpenHarmony 内核源码分析(内核态锁篇) | 如何实现快锁Futex(下)
660
OpenHarmony 内核源码分析(物理内存篇) | 怎么管理物理内存
1010
相关推荐
OpenHarmony 内核源码分析(Shell解析篇) | 应用窥视内核的窗口
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验