欢迎来到思维库

思维库

鸿蒙轻内核M核源码分析系列二数据结构-任务就绪队列

时间:2025-11-05 16:00:15 出处:系统运维阅读(143)

想了解更多内容,鸿蒙核M核源请访问:

和华为官方合作共建的轻内鸿蒙技术社区

https://harmonyos.51cto.com

鸿蒙轻内核源码分析上一个系列,我们分析了双向循环链表的码分源码。本文会继续给读者介绍源码中重要的析系数据结构,任务基于优先级的列数就绪队列Priority Queue。在讲解时,据结会结合数据结构相关绘图,构任培养读者们的队列数据结构的平面想象能力,帮助更好的鸿蒙核M核源学习和理解这些数据结构的用法。

1 任务就绪队列

在任务调度模块,轻内就绪队列是码分个重要的数据结构。任务创建后即进入就绪态,析系并放入就绪队列。列数在鸿蒙轻内核中,据结就绪队列是构任一个双向循环链表数组,每个数组元素就是一个链表,相同优先级的任务放入同一个链表。

任务就绪队列Priority Queue主要供内部使用,用户进行业务开发时不涉及,所以并未对外提供接口。双向循环链表数组能够更加方便的服务器租用支持任务基于优先级进行调度。任务就绪队列的核心代码在kernel\src\los_task.c文件中。

1.1 任务就绪队列的定义

在kernel\src\los_task.c文件中定义了和任务就绪队列相关的主要变量。

源码如下:

⑴ LITE_OS_SEC_BSS LOS_DL_LIST *g_losPriorityQueueList = NULL; ⑵ static LITE_OS_SEC_BSS UINT32 g_priqueueBitmap = 0; ⑶ #define PRIQUEUE_PRIOR0_BIT              (UINT32)0x80000000 ⑷ #define OS_PRIORITY_QUEUE_PRIORITYNUM    32 

 其中⑴表示任务就绪队列,是一个双向链表数组,后文初始化该数组时会将数组长度设置为⑷处定义的OS_PRIORITY_QUEUE_PRIORITYNUM;⑵表示优先级位图,标识了任务就绪队列中已挂载的就绪任务所在的优先级;⑶表示优先级为0的比特位;⑷表示任务就绪队列支持的优先级个数32,所以鸿蒙轻内核优先级的取值范围为0-31,数值越小优先级越大。

优先级位图g_priqueueBitmap的bit位和优先级的关系为bit=31-priority,优先级数组g_losPriorityQueueList[priority]包含了OS_PRIORITY_QUEUE_PRIORITYNUM个数组元素,每个数组元素都是一个双向链表,同一优先级的处于就绪状态的所有任务都会挂载到对应优先级的双向链表中。

示意图如下:

2 任务就绪队列操作

2.1 初始化任务就绪队列

任务就绪队列初始化函数为OsPriQueueInit(),系统初始化阶段被调用,调用路径为:main.c:main() --> kernel\src\los_init.c:LOS_KernelInit() --> kernel\src\los_task.c:OsTaskInit() --> OsPriqueueInit()。

源码如下:

STATIC UINT32 OsPriqueueInit(VOID) {     UINT32 priority; ⑴  UINT32 size = OS_PRIORITY_QUEUE_PRIORITYNUM * sizeof(LOS_DL_LIST);     g_losPriorityQueueList = (LOS_DL_LIST *)LOS_MemAlloc(m_aucSysMem0, size);     if (g_losPriorityQueueList == NULL) {         return LOS_NOK;     }     for (priority = 0; priority < OS_PRIORITY_QUEUE_PRIORITYNUM; ++priority) { ⑵      LOS_ListInit(&g_losPriorityQueueList[priority]);     }     return LOS_OK; } 

 ⑴处计算就绪队列数组需要的企商汇内存大小,然后为任务就绪队列申请内存,占用内存为OS_PRIORITY_QUEUE_PRIORITYNUM个双向链表所需要的内存大小,运行期间该内存不会释放,为系统常驻内存。⑵处代码将每一个数组元素都初始化为双向循环链表。

2.2 任务就绪队列插入

任务就绪队列插入函数为OsPriqueueEnqueue(),该函数把就绪状态的任务插入任务就绪队列的尾部。在任务就绪队列中,先调用队列头部的任务,最后调用队列尾部的任务。

源码如下:

STATIC VOID OsPriqueueEnqueue(LOS_DL_LIST *priqueueItem, UINT32 priority) { ⑴  if (LOS_ListEmpty(&g_losPriorityQueueList[priority])) { ⑵      g_priqueueBitmap |= (PRIQUEUE_PRIOR0_BIT >> priority);     } ⑶  LOS_ListTailInsert(&g_losPriorityQueueList[priority], priqueueItem); } 

 ⑴处先判断指定优先级priority的任务就绪队列是否为空,如果为空,则在⑵处更新优先级位图,将第31-prioritybit位设置为1。⑶处把就绪状态的任务插入任务就绪队列的尾部,进行排队。

2.3 从任务就绪队列中删除

从任务就绪队列中删除的函数为OsPriqueueDequeue()。任务被删除、进入suspend阻塞状态、优先级调整等场景中,都需要调用该函数把任务从任务就绪队列中删除。

源码如下:

STATIC VOID OsPriqueueDequeue(LOS_DL_LIST *priqueueItem) {     LosTaskCB *runningTask = NULL; ⑴  LOS_ListDelete(priqueueItem); ⑵  runningTask = LOS_DL_LIST_ENTRY(priqueueItem, LosTaskCB, pendList); ⑶  if (LOS_ListEmpty(&g_losPriorityQueueList[runningTask->priority])) { ⑷      g_priqueueBitmap &= ~(PRIQUEUE_PRIOR0_BIT >> runningTask->priority);     } } 

 ⑴把任务从任务就绪队列中删除。香港云服务器⑵获取被删除任务的任务控制块信息,以获取任务的优先级。删除完任务后队列可能成为空队列,所以⑶处代码判断任务就绪队列是否为空,如果为空,则需要执行⑷处代码,更新优先级位图,将第31-prioritybit位设置为0。

2.4 获取队列中的最高优先级节点

获取任务就绪队列中优先级最高的链表节点的函数为OsPriQueueTop()。

源码如下:

STATIC LOS_DL_LIST *OsPriqueueTop(VOID) {     UINT32 priority; ⑴  if (g_priqueueBitmap != 0) { ⑵      priority = CLZ(g_priqueueBitmap); ⑶      return LOS_DL_LIST_FIRST(&g_losPriorityQueueList[priority]);     }     return (LOS_DL_LIST *)NULL; } 

 ⑴处判断优先级位图g_priqueueBitmap是否为0,如果为0则直接返回NULL,说明任务就绪队列中没有任何就绪状态的任务。 ⑵处计算g_priqueueBitmap以二进制表示时高位为0的位数,其值就是任务的优先级priority,以此方法得到的优先级就是任务就绪队列中所有优先级里最高的。然后⑶处从该优先级的队列&g_losPriorityQueueList[priority]中获取第一个链表节点,获取的就是任务就绪队列中优先级最高的任务。

2.5 获取指定优先级的就绪任务的数量

获取任务就绪队列中指定优先级的任务数量的函数为OsPriqueueSize()。

源码如下:

STATIC UINT32 OsPriqueueSize(UINT32 priority) {     UINT32 itemCnt = 0;     LOS_DL_LIST *curPQNode = (LOS_DL_LIST *)NULL; ⑴  LOS_DL_LIST_FOR_EACH(curPQNode, &g_losPriorityQueueList[priority]) { ⑵      ++itemCnt;     }     return itemCnt; } 

 ⑴处代码使用宏LOS_DL_LIST_FOR_EACH定义的for循环遍历指定优先级priority的双向链表,如果获取到新节点则表示该优先级下有一个就绪任务,然后执行⑵处代码,对计数进行加1操作,返回的结果就是指定优先级下有多少个就绪任务。

小结

掌握鸿蒙轻内核的优先级就绪队列Priority Queue这一重要的数据结构,会给进一步学习、分析鸿蒙轻内核源代码打下了基础,让后续的学习更加容易。后续也会陆续推出更多的分享文章,敬请期待。

想了解更多内容,请访问:

和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

分享到:

上一篇:Ubuntu是一个流行的Linux操作系统,基于Debian发行版和GNOME桌面环境,和其他Linux发行版相比,Ubuntu非常易用,和Windows相容性很好,非常适合Windows用户的迁移,预装了大量常用软件,中文版的功能也较全,支持拼音输入法,预装了Firefox、Open Office、多媒体播放、图像处理等大多数常用软件,一般会自动安装网卡、音效卡等设备的驱动,对于不打游戏不用网银的用户来说,基本上能用的功能都有了,在Windows操作系统下不用分区即可安装使用,就如同安装一个应用软件那么容易,整个Ubuntu操作系统在Windows下就如同一个大文件一样,很容易卸载掉。下面我就介绍一下Ubuntu操作系统安装使用的方法,供Ubuntu新手参考,希望能起到Linux扫盲的作用。     下载Ubuntu   Ubuntu有三个版本,分别是桌面版(Desktop Edition),服务器版(Server Edition),上网本版(Netbook Remix),普通桌面电脑使用桌面版即可,下载地址请点这里,32位CPU请选择32bit version,上网本则可下载Netbook Remix,目前Ubuntu已经占据三分之一的上网本市场,仅次于Windows XP系统。Google的Chrome操作系统强有力的对手就是Ubuntu Netbook Remix。   目前最新的版本是9.04版,下载后的文件名是ubuntu-9.04-desktop-i386.iso,大小是698M,通过迅雷下载非常快,大约半个小时左右可以下载完毕。   安装Ubuntu   在Windows下可以不用重新分区,直接像安装一个应用程序那样安装Ubuntu,安装方法是,先使用一个虚拟光驱(例如微软的Windows虚拟光驱)装载ubuntu-9.04-desktop-i386.iso文件,然后运行根目录下的wubi.exe,运行前要将本地磁盘的名字都修改为英文名,否则会出现错误信息“UnicodeEncodeError: ascii codec cant encode characters in position 0-3: ordinal not in range(128)”而无法运行。       运行之后,会出现如下界面,选择“Install inside Windows”即可在Windows下直接安装而无需分区。    接着出现下面的安装界面,选择一个磁盘,然后将语言选择为“Chinese(Simplified)简体中文”,Installation size为Ubuntu环境的总共磁盘大小,然后是登录用户名和密码,设置好了以后就点安装继续。    后面的安装操作很简单,不需要手动干预就可以直接安装好整个操作系统,大部分的硬件驱动都可以自动安装好。提示安装完毕后,重启系统,就可以使用Ubuntu了。   自动登录Ubuntu   Ubuntu默认是每次登录都是要输入用户名和密码的,这是基于安全方面的考虑,不过对于桌面版,大家都习惯自己的电脑能自动登录,类似Windows XP系统那样,通过一些设置可以实现Ubuntu自动登录。设置的方法是:点击“系统”—“系统管理”—“登录窗口” (需要输入管理员密码),然后在“安全”选项页—勾选(启用自动登录),然后在下拉列表里选择自己的用户名。之后Ubuntu就能够自动登录了。   开机自动运行程序   类似Windows的启动菜单,在Linux也可以实现开机自动运行一些命令,比较简单的方法是修改 /etc/rc.local 文件,将需要执行的命令添加进去。     桌面设置   Ubuntu的桌面,默认有两个任务栏,一个在上面,一个在下面,通常习惯Windows的用户喜欢将上面的移到下面,Ubuntu的面板无法拖动,在上面点右键后,可以让其显示在屏幕下端。   桌面背景设置和Windows很类似,在“桌面”上点右键,点更改桌面背景,就可以进行修改设置。   修改root密码   Ubuntu默认的用户并不是root,我们可以通过操作来使用root这个超级管理员帐号,以获得更大的权限。先打开终端,然后执行下面的语句   sudo passwd root   就可以修改超级管理员root的密码,之后就可以使用su命令切换到root用户来执行某些更高权限的操作。   Hosts修改   在Windows下,我们上Twitter等网站都需要修改hosts文件,在Linux下也有hosts文件,文件位于/etc/hosts,使用root用户可以编辑修改这个文件,主机名和IP的格式与Windows的完全相同,例如:   127.0.0.1 localhost   在Ubuntu下安装软件   Ubuntu下的软件安装有几种方式,常用的是deb包的安装方式,deb是debian系列的Linux包管理方式,ubuntu属于debian的派生,也默认支持这种软件安装方式,当下载到一个deb格式的软件后,直接在界面上就可以安装。   另一种常见的安装方式是源代码编译安装,很多软件会提供了源代码给最终用户,用户需要自行编译安装,先使用tar将源代码解压缩到一个目录下,然后进入这个目录,执行以下三条命令:   ./configure     make   sudo make install   执行完成后,即可完成软件的编译和安装。   还有一种方式是apt-get的安装方法,APT是Debian及其衍生发行版的软件包管理器,APT可以自动下载,配置,安装二进制或者源代码格式的软件包,因此简化了Unix系统上管理软件的过程。常用的安装命令是:   sudo apt-get install 软件名   sudo apt-get remove 软件名   Firefox浏览器的更新   Ubuntu安装完成后会自动安装一个Firefox浏览器,遗憾的是这个Firefox版本通常较低,例如Ubuntu 9.04会安装Firefox 3.0,不过我们可以想办法下载最新的Firefox覆盖掉老版本Firefox,具体方法是,先上Firefox官方网站下载最新的Linux版本Firefox,然后将其解压缩到某一个目录下,例如firefox目录,进入终端,到这个目录的父目录,执行下面的语句:   sudo cp -r firefox /usr/lib/firefox-3.5.2   sudo mv /usr/bin/firefox /usr/bin/firefox.old   sudo ln -s /usr/lib/firefox-3.5.2/firefox /usr/bin/firefox-3.5.2   sudo ln -s /usr/bin/firefox-3.5.2 /usr/bin/firefox   之后就可以将Firefox成功替换为最新的Firefox 3.52版本,未来的Firefox更新也可以使用这种方法。     Firefox的Flash问题   经过我的实际测试,Ubuntu自动安装的Flash插件swfdec存在很多问题,在Firefox中,很多网页的Flash无法显示,包括Google音乐和开心网等,因此建议使用下面两条语句将其卸载。   sudo apt-get remove swfdec-mozilla   sudo apt-get remove swfdec-gnome   之后可安装官方的Adobe Flash Player的Linux版,下载地址是: http://get.adobe.com/flashplayer/   安装完成后,还要解决中文乱码问题,解决方法是执行下面语句:   sudo cp /etc/fonts/conf.d/49-sansserif.conf /etc/fonts/conf.d/49-sansserif.conf.bak   sudo rm /etc/fonts/conf.d/49-sansserif.conf   之后,Firefox的Flash就完全正常了,在Firefox中访问开心网等Flash网站,显示都正常。   安装常用软件   介绍完了安装的方法和Firefox,下面就可以去各个网站下载一些常用的Linux软件来安装了,下面是我整理的一些常用的Linux软件列表:   Linux QQ:访问这个地址,下载deb文件安装,可以在Linux下玩腾讯QQ。   防火墙 firestarter: 使用 sudo apt-get install firestarter 安装。   杀毒软件 AntiVir: 虽然Linux下的病毒很少,但对于新手还是有必要安装一个杀毒软件,访问这个地址可以下载免费版的AntiVir杀毒软件,这个软件我曾经在《五个最佳的防病毒软件》中介绍过。   rpm 转 deb 工具: 使用 sudo apt-get install alien 安装   JAVA环境安装: JRE的安装 sudo apt-get install sun-java6-jre ,JDK的安装 sudo apt-get install sun-java6-jdk       eclipse安装: 先到这个地址下载最新的eclipse,然后使用tar xvfz eclipse-php-galileo-linux-gtk.tar.gz -C /opt 解压缩后就可以使用。    Picasa 3 for Linux安装: 访问这个地址,下载后直接安装。   Google Earth安装: 在这里下载最新版本的Google Earth,下载下来是个BIN文件,在图形界面上右击 GoogleEarthLinux.bin,在“权限”选项卡中勾选“允许以程序执行文件”,如下图。    之后在终端上执行 ./GoogleEarthLinux.bin 即可安装。    安装LAMP环境   Ubuntu的桌面版也可以安装LAMP(Linux + Apache + MySQL + PHP)环境,这里我介绍一个最简单的方法,就是使用XAMPP,这个项目我曾经在《常见的WAMP集成环境》中介绍过,XAMPP不但支持Windows,还支持Linux,在其网站下载之后,运行下面两条命令:   tar xvfz xampp-linux-1.7.2.tar.gz -C /opt   /opt/lampp/lampp start   就可以启动LAMP环境,XAMPP是功能全面的集成环境,软件包中包含Apache、MySQL、SQLite、PHP、Perl、FileZilla FTP Server、Tomcat等等,很适合开发环境使用。   安装程序添加程序菜单和桌面       有些程序是直接解压缩安装的,因此不会添加“应用程序”的菜单项,我们可以手动将其添加菜单项,具体方法是,打开“系统”—“首选项”—“主菜单”,新增即可。   添加桌面快捷方式是,在桌面上点右键,创建启动器。这个“启动器”就是Windows里面的“快捷方式”。   将“应用程序”的菜单项创建到桌面快捷方式的方法是,在“应用程序”的菜单项上单击鼠标右键,选择“将此启动器添加到桌面”或“将此启动器添加到面板”,就可以了。

下一篇:一、用户概述SSH对于远程管理一台服务器来说是一个好方法。然而,SSH仍然存在着诸多问题。服务器和客户端的通信是安全的,不过这并不意味着涉及到的主机也是安全的。向外部世界打开一个SSH服务也就意味着允许强力攻击。复制代码代码如下:DenyHosts意在由Linux系统管理员运行,以帮助其挫败对SSH服务器的攻击(也称为基于字典的攻击或强力攻击)的企图。DenyHosts充当着一个对SSH和其它服务的动态阻击器,它依靠/etc/hosts.deny和 hosts.allow进行工作,并能够以动态方式构建重复地与我们的服务器连接的主机列表。默认情况下,这项服务会阻止来自那些不断地试图与我们的主机连接并实施访问的IP地址源。Denyhosts的处理在/etc/denyhosts.conf中进行配置。我们还可以通过Iptables行连接速率的限制,而且我们还应该在服务器上部署防火墙。一旦这些布置停当,我们就会确信自己在一台面向公众的主机上拥有了一个更加安全的SSH。

温馨提示:以上内容和图片整理于网络,仅供参考,希望对您有帮助!如有侵权行为请联系删除!

猜你喜欢

友情链接: