Nuttx之nxsched_add_blocked

声明:此处代码分析,来源与 nuttx 12.8.0版本。

在分析之前,需要一图镇楼。

/***************************************************************************** Name: nxsched_add_blocked** Description:*   This function adds a TCB to one of the blocked state task lists as*   inferred from task_state.** Input Parameters:*   btcb - Points to the TCB that is blocked*   task_state - identifies the state of the blocked task** Returned Value:*   None** Assumptions:* - The caller has established a critical section before*   calling this function.*****************************************************************************/void nxsched_add_blocked(FAR struct tcb_s *btcb, tstate_t task_state)
{FAR dq_queue_t *tasklist;/* Make sure that we received a valid blocked state */DEBUGASSERT(task_state >= FIRST_BLOCKED_STATE &&task_state <= LAST_BLOCKED_STATE);/* Make sure the TCB's state corresponds to the list */btcb->task_state = task_state;/* Add the TCB to the blocked task list associated with this state. */tasklist = TLIST_BLOCKED(btcb);/* Determine if the task is to be added to a prioritized task list. */if (TLIST_ISPRIORITIZED(task_state)){/* Add the task to a prioritized list */nxsched_add_prioritized(btcb, tasklist);}else{/* Add the task to a non-prioritized list */dq_addlast((FAR dq_entry_t *)btcb, tasklist);}
}

显然,此函数的作用是依据task_state,将btcb放入阻塞队列。

既然是放入队列,首先是要找到具体的队列。

 /* Make sure the TCB's state corresponds to the list */btcb->task_state = task_state;/* Add the TCB to the blocked task list associated with this state. */tasklist = TLIST_BLOCKED(btcb);

TLIST_BLOCKED在sched.h中的定义如下。

/* List attribute flags */#define TLIST_ATTR_PRIORITIZED   (1 << 0) /* Bit 0: List is prioritized */
#define TLIST_ATTR_INDEXED       (1 << 1) /* Bit 1: List is indexed by CPU */
#define TLIST_ATTR_RUNNABLE      (1 << 2) /* Bit 2: List includes running tasks */
#define TLIST_ATTR_OFFSET        (1 << 3) /* Bit 3: Pointer of task list is offset */#define __TLIST_ATTR(s)          g_tasklisttable[s].attr
#define TLIST_ISPRIORITIZED(s)   ((__TLIST_ATTR(s) & TLIST_ATTR_PRIORITIZED) != 0)
#define TLIST_ISINDEXED(s)       ((__TLIST_ATTR(s) & TLIST_ATTR_INDEXED) != 0)
#define TLIST_ISRUNNABLE(s)      ((__TLIST_ATTR(s) & TLIST_ATTR_RUNNABLE) != 0)
#define TLIST_ISOFFSET(s)        ((__TLIST_ATTR(s) & TLIST_ATTR_OFFSET) != 0)#define __TLIST_HEAD(t) \(TLIST_ISOFFSET((t)->task_state) ? (FAR dq_queue_t *)((FAR uint8_t *)((t)->waitobj) + \(uintptr_t)g_tasklisttable[(t)->task_state].list) : g_tasklisttable[(t)->task_state].list)#ifdef CONFIG_SMP
#  define TLIST_HEAD(t,c) \((TLIST_ISINDEXED((t)->task_state)) ? (&(__TLIST_HEAD(t))[c]) : __TLIST_HEAD(t))
#  define TLIST_BLOCKED(t)       __TLIST_HEAD(t)
#else
#  define TLIST_HEAD(t)          __TLIST_HEAD(t)
#  define TLIST_BLOCKED(t)       __TLIST_HEAD(t)
#endif

在计算__TLIST_HEAD的时候,会有一个TLIST_ISOFFSET的判断。那什么队列会符合要求呢?根据定义,我们知道当g_tasklisttable[s].attr &TLIST_ATTR_OFFSET  != 0 就满足条件。

那,具体是什么队列呢?

static void tasklist_initialize(void)
{....../* TSTATE_WAIT_SEM */tlist[TSTATE_WAIT_SEM].list = (FAR void *)offsetof(sem_t, waitlist);tlist[TSTATE_WAIT_SEM].attr = TLIST_ATTR_PRIORITIZED |TLIST_ATTR_OFFSET;....../* TSTATE_WAIT_MQNOTEMPTY */tlist[TSTATE_WAIT_MQNOTEMPTY].list =(FAR void *)offsetof(struct mqueue_inode_s, cmn.waitfornotempty);tlist[TSTATE_WAIT_MQNOTEMPTY].attr = TLIST_ATTR_PRIORITIZED |TLIST_ATTR_OFFSET;/* TSTATE_WAIT_MQNOTFULL */tlist[TSTATE_WAIT_MQNOTFULL].list =(FAR void *)offsetof(struct mqueue_inode_s, cmn.waitfornotfull);tlist[TSTATE_WAIT_MQNOTFULL].attr = TLIST_ATTR_PRIORITIZED |TLIST_ATTR_OFFSET;......}

显然,信号量和消息队列会符合要求。

那么,

(FAR dq_queue_t *)((FAR uint8_t *)((t)->waitobj) + (uintptr_t)g_tasklisttable[(t)->task_state].list)具体指向那里呢?

为回答此问题,我们需要弄清楚对于信号量和消息队列来说,waitobj 和g_tasklisttable[(t)->task_state].list各指代什么意思。

对于g_tasklisttable[(t)->task_state].list,由上述代码可知,g_tasklisttable[TSTATE_WAIT_SEM].list 是 struct mqueue_inode_s结构体中,waitlist的偏移量。

struct sem_s
{......dq_queue_t waitlist;......}typedef struct sem_s sem_t;

对于g_tasklisttable[(t)->task_state].list,由上述代码可知,g_tasklisttable[TSTATE_WAIT_MQNOTEMPTY].list 是 sem_t结构体中,mn.waitfornotempty的偏移量。

struct mqueue_inode_s
{struct mqueue_cmn_s cmn;    /* Common prologue */......
}struct mqueue_cmn_s
{dq_queue_t waitfornotempty; /* Task list waiting for not empty */dq_queue_t waitfornotfull;  /* Task list waiting for not full */......
};

g_tasklisttable[TSTATE_WAIT_MQNOTFULL].list 同理。

waitobj的定义如下。

struct tcb_s
{..../* POSIX Semaphore and Message Queue Control Fields ***********************/FAR void *waitobj;                     /* Object thread waiting on        */......
}

那么,waitobj的赋值是什么呢?

int nxmq_wait_receive(FAR struct mqueue_inode_s *msgq,FAR struct mqueue_msg_s **rcvmsg,FAR const struct timespec *abstime,sclock_t ticks)
{......FAR struct tcb_s *rtcb = this_task();......rtcb->waitobj = msgq;......
}

对于信号量,waitobj同理。可见,waitobj指代的是具体等待的信号量或者消息队列。

那,为什么要这样呢?答案就藏在数据结构的定义里。

以sem_t来说,

struct sem_s
{......dq_queue_t waitlist;......}typedef struct sem_s sem_t;

有人可能会问,这能说明什么?这能说明,对于每一个sem_t实例来说,他们都有各自的队列。与之对应的g_tasklisttable.list中存放的是偏移值。

为什么这样设计呢? 

这样设计实现了所有阻塞类型的统一管理。

找到具体的队列之后,调用nxsched_add_prioritized或dq_addlast 将tcb_s加入队列。

除了,信号量和消息队列,还有哪些阻塞队列呢?

enum tstate_e
{......TSTATE_TASK_INACTIVE,       /* BLOCKED      - Initialized but not yet activated */TSTATE_WAIT_SEM,            /* BLOCKED      - Waiting for a semaphore */TSTATE_WAIT_SIG,            /* BLOCKED      - Waiting for a signal */
#if !defined(CONFIG_DISABLE_MQUEUE) || !defined(CONFIG_DISABLE_MQUEUE_SYSV)TSTATE_WAIT_MQNOTEMPTY,     /* BLOCKED      - Waiting for a MQ to become not empty. */TSTATE_WAIT_MQNOTFULL,      /* BLOCKED      - Waiting for a MQ to become not full. */
#endif
#ifdef CONFIG_LEGACY_PAGINGTSTATE_WAIT_PAGEFILL,       /* BLOCKED      - Waiting for page fill */
#endif
#ifdef CONFIG_SIG_SIGSTOP_ACTIONTSTATE_TASK_STOPPED,        /* BLOCKED      - Waiting for SIGCONT */
#endif......
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/88490.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/88490.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python 包含虚拟环境venv项目的移动

python 包含虚拟环境venv项目的移动 在ubuntu环境下&#xff0c;移动一个包含venv虚拟环境的项目后&#xff0c;在执行时会报错: 错误1&#xff1a; Traceback (most recent call last):File "app.py", line 2, in <module>from flask import Flask, request…

WPF中实现TreeView的SelectedItem双向绑定到ViewModel

WPF中实现TreeView的SelectedItem双向绑定到ViewModel WPF中实现TreeView的SelectedItem双向绑定到ViewModel问题背景解决方案一&#xff1a;附加行为&#xff08;推荐&#xff09;实现步骤优点 解决方案二&#xff1a;通过IsSelected属性绑定实现步骤注意事项 两种方案对比补充…

类型转换运算符重载

C 类型转换函数详解 类型转换函数是C中用于实现类类型与其他类型之间相互转换的特殊成员函数&#xff0c;分为两种主要形式&#xff1a;转换构造函数和类型转换运算符。 1. 转换构造函数 (Conversion Constructor) 基本概念 转换构造函数是一种特殊的构造函数&#xff0c;它…

ES10(ES2019)新特性整理

一、Array.prototype.flat() 和 flatMap()&#xff08;数组扁平化&#xff09; &#xff08;1&#xff09;flat(depth) 将嵌套数组“拉平”到指定深度&#xff08;默认 depth1&#xff09;。 const arr [1, [2, [3]]]; arr.flat(); // [1, 2, [3]]&#xff08;默认深度 …

基于 LCD1602 的超声波测距仪设计与实现:从原理到应用

具体材料可在主页资源里下载 超声波测距技术作为非接触式测量的重要手段&#xff0c;在工业检测、智能家居、机器人避障等领域有着广泛应用。本文将详细介绍一款基于 STC89C51 单片机与 LCD1602 显示屏的超声波测距系统&#xff0c;从硬件架构到软件实现&#xff0c;完整呈现一…

2.5G/5G/10G自协商An

IEEE 802.3 协议中&#xff0c;**2.5GBASE-T、5GBASE-T 和 10GBASE-T** 的链路自协商&#xff08;auto-negotiation&#xff0c;简称 AN&#xff09;是在物理层&#xff08;PHY&#xff09;完成的。它的作用是&#xff1a; * **让连接双方&#xff08;主机和对端&#xff09;自…

闲庭信步使用SV搭建图像测试平台:第五课——使用task

&#xff08;本系列只需要modelsim即可完成数字图像的处理&#xff0c;每个工程都搭建了全自动化的仿真环境&#xff0c;只需要双击top_tb.bat文件就可以完成整个的仿真&#xff0c;大大降低了初学者的门槛&#xff01;&#xff01;&#xff01;&#xff01;如需要该系列的工程…

Android数据库GreenDao的使用

简介 GreenDao 是一个轻量级的对象关系映射&#xff08;ORM&#xff09;库&#xff0c;用于简化 Android 应用中的数据库操作。它提供了以下主要功能&#xff1a; 简化数据库操作&#xff1a;通过注解定义实体类&#xff0c;GreenDao 自动生成 DAO&#xff08;数据访问对象&a…

24小时留言板

title: 24小时留言板 date: 2025-06-25 23:32:53 tags: 代码工具 24小时留言板 核心效果如图所示 代码解析 # TodoController 代码解析## 整体架构 这是一个基于Spring WebFlux的响应式控制器&#xff0c;结合Redis发布\订阅机制实现实时更新的待办事项系统。关键组件包括&a…

深入理解Redis整数集合(intset)的升级策略:内存优化的核心魔法

引言 作为Redis中最节省内存的数据结构之一&#xff0c;整数集合&#xff08;intset&#xff09; 专门用于高效存储整型数据。但你可能不知道&#xff0c;它背后藏着一个精妙的「动态升级」机制——能在不浪费内存的前提下&#xff0c;灵活适配不同大小的整数。今天我们就来扒…

高性能计算(HPC)集群和工作流:intel-oneapi-hpc-toolkit安装与使用

成功安装了 Intel oneAPI HPC Toolkit&#xff01;这个工具包包含了很多强大的工具&#xff0c;可以帮助你优化和加速高性能计算&#xff08;HPC&#xff09;任务&#xff0c;特别是在使用 Intel 的硬件&#xff08;如 Xeon 处理器和 GPU&#xff09;时。 接下来&#xff0c;…

QT vscode cmake 编译 undefined reference to `vtable for 问题解决

编译时出现undefined reference to vtable for 问题&#xff0c;是没有添加头文件到目标&#xff0c;添加即可&#xff1a; 如果使用的是qt5, 没有qt_add_executable, 使用qt 5的 自动处理即可&#xff1a; # 启用 Qt 自动处理功能 set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC …

linux内核奔溃转储之kexec、kdump

一、kexec是什么&#xff1f; kexec 是 Linux 内核提供的一种关键技术&#xff0c;允许系统‌在不经过完整硬件重启&#xff08;BIOS/UEFI 初始化&#xff09;的情况下&#xff0c;直接从当前正在运行的内核加载并启动另一个新内核‌。以下是其核心要点&#xff1a; ‌定义与核…

标题:2025金融护网行动实战指南:从合规防御到智能免疫的体系化进阶

引言 2025年&#xff0c;随着《中国人民银行业务领域网络安全事件报告管理办法》正式实施&#xff0c;金融护网行动已从“合规检查”升级为“能力对抗”。面对AI驱动的自适应攻击、勒索病毒与黑灰产协同威胁&#xff0c;金融机构需构建“技术-管理-人才”三位一体的智能防御体…

NEO4j的安装部署

windows neo4j新版本安装需要部署jdk17&#xff0c;下面这个版本是jdk8最新的支持版本 neo4j-community-3.5.9-windows.zipIndex of /doc/neo4j/3.5.9/ 启动 dos面板中启动 neo4j.bat console linux neo4j新版本安装需要部署jdk17&#xff0c;下面这个版本是jdk8最新的支…

八股文——JAVA基础:说一下C++与java的区别

首先&#xff0c;c与java都是面向对象编程&#xff0c;都包含封装、继承、多态的特性。但是c多继承&#xff0c;而java只能单继承与多实现。 其次&#xff0c;java无法直接访问内存&#xff0c;java通过引用对向&#xff0c;比如new一个对象&#xff0c;拿到的对象实例实际上是…

Vue3 Composition API 深度解析:告别Options API的局限性

目录 一、为什么需要Composition API&#xff1f; 二、核心概念&#xff1a;setup() 函数 三、响应式核心&#xff1a;ref() 和 reactive() 1. ref - 处理基本类型/对象 2. reactive - 处理对象 四、生命周期钩子新写法 五、强大的逻辑复用&#xff1a;组合式函数 六、响…

IoT/HCIP实验-5/基于NB-IoT的智慧农业实验(平台侧开发+端侧编码+基础调试分析)

文章目录 概述扩展板 E53_IA1智慧农业平台测开发功能定义/模型开发编解码插件开发-消息编解码插件开发-关联编解码插件开发-部署注册实际设备 智慧农业端侧编码工程配置数据结构定义数据收集任务数据上报任务设备接入过程正确设置接入参数命令响应任务 程序调试其他 概述 本实…

多网络环境vmware虚拟机配置

环境&#xff1a;一台台式机、一台笔记本、笔记本中安装虚拟机。台式机及笔记本都使用wifi连接。 实现效果&#xff1a;虚拟机采用固定ip方式&#xff0c;台式机可以直接连接虚拟机。 1、VMware环境配置 台式机ip&#xff1a;192.168.31.43 笔记本ip&#xff1a;192.168.31.…

ZArchiver×亚矩云手机:云端文件管理的“超维解压”革命

在数字化办公与移动应用生态中&#xff0c;文件压缩与解压是高频刚需场景&#xff0c;但传统本地工具受限于设备性能、存储空间及跨平台协作痛点。ZArchiver&#xff08;轻量级压缩工具&#xff09;与亚矩云手机的结合&#xff0c;通过“云端算力虚拟化环境”的创新模式&#x…