当前位置: 首页 > news >正文

Linux任务切换后清理所有资源函数finish_task_switch的实现

文章目录

  • 一、释放页全局目录`mm_free_pgd`
    • 1.函数结构分析
    • 2.PAE(物理地址扩展)情况处理
    • 3.非PAE情况处理
    • 4.内存缓存管理
  • 二、销毁进程 LDT上下文`destroy_context`
    • 1.函数整体分析
    • 2.检查并清理当前活动的LDT
    • 3.释放LDT内存
    • 4.重置上下文状态
  • 三、释放内存描述符`__mmdrop`
    • 1.函数定义和参数
    • 2.安全检查
    • 3.释放页全局目录(PGD)
    • 4.销毁架构特定上下文
    • 5.释放内存描述符本身
  • 四、验证和释放安全上下文`security_task_free`
    • 1.主要函数:task_free_security
    • 2.安全检查
    • 3.清理安全信息
    • 4.封装函数:security_task_free
  • 五、释放用户相关的所有资源`free_uid`
    • 1.辅助函数:uid_hash_remove
    • 2.主函数:free_uid
    • 3.清理用户结构
    • 4.最终释放
    • 5.使用场景:
  • 六、组信息释放`put_group_info`
    • 1.主函数:groups_free
    • 2.释放动态分配的块
    • 3.释放组信息结构本身
    • 4.引用计数封装宏
  • 七、通知链机制`notifier_call_chain`
    • 1.函数定义和初始化
    • 2.链表遍历循环
    • 3.停止条件检查
    • 4.移动到下一个节点
    • 5.最终返回
  • 八、任务释放通知分发给注册的分析器`profile_handoff_task`
    • 1.函数定义和参数
    • 2.加锁保护
    • 3.调用通知链
    • 4.解锁和返回
  • 九、释放任务结构`free_task`
    • 1.宏定义
    • 2.主函数:free_task
  • 十、释放任务相关所有资源`__put_task_struct`
    • 1.函数定义和参数
    • 2.安全检查阶段
    • 3.资源清理阶段
    • 4.任务移交和最终释放
  • 十一、任务切换完成时清理`finish_task_switch`
    • 1.宏定义和辅助函数
    • 2.主函数:finish_task_switch
    • 3.架构切换完成和资源清理
    • 4.内存管理特殊情况
      • 4.1.内核线程的内存管理
    • 5.并发安全考虑
      • 5.1.锁的保护范围

一、释放页全局目录mm_free_pgd

void pgd_free(pgd_t *pgd)
{int i;if (PTRS_PER_PMD > 1)for (i = 0; i < USER_PTRS_PER_PGD; ++i)kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));kmem_cache_free(pgd_cache, pgd);
}
static inline void mm_free_pgd(struct mm_struct * mm)
{pgd_free(mm->pgd);
}

这是一个用于释放页全局目录(Page Global Directory, PGD)的内核函数

1.函数结构分析

void pgd_free(pgd_t *pgd)
{int i;

参数说明:

  • pgd_t *pgd:指向要释放的PGD表的指针
  • PGD是x86架构中页表的顶级结构,指向进程的地址空间

2.PAE(物理地址扩展)情况处理

#define PGDIR_SHIFT	22   // 每个 PGD 条目覆盖 2^22 字节
#define PGDIR_SIZE	(1UL << PGDIR_SHIFT) 
#define __PAGE_OFFSET		(0xC0000000UL) // 内核空间起始地址
#define PAGE_OFFSET		((unsigned long)__PAGE_OFFSET)
#define TASK_SIZE	(PAGE_OFFSET) // 用户空间最大地址
#define USER_PTRS_PER_PGD	(TASK_SIZE/PGDIR_SIZE) // 用户空间占用的 PGD 条目数
#define __va(x)			((void *)((unsigned long)(x)+PAGE_OFFSET))
#define pgd_val(x)	((x).pgd)if (PTRS_PER_PMD > 1)for (i = 0; i < USER_PTRS_PER_PGD; ++i)kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));

PAE模式详解:

  • PTRS_PER_PMD > 1:检查是否启用PAE模式,二级页表=1,三级页表=512
  • PAE模式下,PGD包含指向PMD(Page Middle Directory)的指针,需要单独释放
  • USER_PTRS_PER_PGD:用户空间PGD条目数量,它的值取决于用户空间的虚拟地址范围(TASK_SIZE)和每个 PGD 条目覆盖的地址空间大小(PGDIR_SIZE

内存释放逻辑:

  • pgd_val(pgd[i]):获取PGD条目的物理地址
  • __va():将物理地址转换为虚拟地址
  • -1:PGD条目包含标志位,需要调整
  • kmem_cache_free(pmd_cache, ...):释放PMD缓存对象

3.非PAE情况处理

    /* in the non-PAE case, clear_page_tables() clears user pgd entries */// 在非PAE情况下,clear_page_tables()已经清理了用户PGD条目kmem_cache_free(pgd_cache, pgd);
}

非PAE模式:

  • 两级页表结构
  • 用户空间条目已被其他函数清理
  • 直接释放PGD缓存对象

4.内存缓存管理

使用的缓存:

  • pmd_cache:PMD页中间目录对象的SLAB缓存
  • pgd_cache:PGD页全局目录对象的SLAB缓存

SLAB分配器优势:

  • 快速分配/释放固定大小的内核对象
  • 减少内存碎片

二、销毁进程 LDT上下文destroy_context

void destroy_context(struct mm_struct *mm)
{if (mm->context.size) {if (mm == current->active_mm)clear_LDT();if (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE)vfree(mm->context.ldt);elsekfree(mm->context.ldt);mm->context.size = 0;}
}

这是一个用于销毁进程 LDT(局部描述符表)上下文的函数

1.函数整体分析

void destroy_context(struct mm_struct *mm)
{// 检查该内存描述符是否有LDT上下文if (mm->context.size) {

参数说明:

  • struct mm_struct *mm:进程的内存描述符指针
  • mm->context:包含架构特定的上下文信息(如LDT)

2.检查并清理当前活动的LDT

        // 如果这个内存描述符是当前运行进程的活动内存描述符if (mm == current->active_mm)clear_LDT();  // 清除当前CPU的LDT

关键点:

  • current->active_mm:当前运行进程使用的内存描述符
  • 如果正在销毁的是当前活动的LDT,需要立即清除CPU的LDTR寄存器
  • 这防止了使用已释放的LDT描述符

3.释放LDT内存

        // 根据LDT大小决定使用vfree还是kfreeif (mm->context.size*LDT_ENTRY_SIZE > PAGE_SIZE)vfree(mm->context.ldt);  // 大块内存使用vfreeelsekfree(mm->context.ldt);  // 小块内存使用kfree

内存分配策略:

  • LDT_ENTRY_SIZE:每个LDT条目的大小(通常是8字节)
  • PAGE_SIZE:页面大小(通常是4KB)
  • 超过一页:使用vfree()(虚拟连续内存)
  • 一页以内:使用kfree()(普通内核内存)

4.重置上下文状态

        // 将LDT大小设为0,标记LDT已释放mm->context.size = 0;}
}

状态清理:

  • 设置size = 0表示没有有效的LDT
  • 防止重复释放或其他误操作

三、释放内存描述符__mmdrop

#define free_mm(mm)	(kmem_cache_free(mm_cachep, (mm)))void fastcall __mmdrop(struct mm_struct *mm)
{BUG_ON(mm == &init_mm);mm_free_pgd(mm);destroy_context(mm);free_mm(mm);
}

这是一个用于彻底释放内存描述符(mm_struct)的核心函数

1.函数定义和参数

void fastcall __mmdrop(struct mm_struct *mm)
{

关键点:

  • fastcall:表示使用寄存器传递参数
  • struct mm_struct *mm:要释放的内存描述符指针
  • 这个函数完成内存描述符的最终释放

2.安全检查

    BUG_ON(mm == &init_mm);

作用:

  • 防止释放初始化内存描述符 init_mm
  • init_mm 是内核的全局内存描述符,用于内核线程和初始化过程
  • 如果尝试释放 init_mm,会触发内核 bug 检查(系统崩溃)

3.释放页全局目录(PGD)

    mm_free_pgd(mm);

作用: 释放进程的页表结构

调用链:

mm_free_pgd(mm)pgd_free(mm->pgd)  // 释放PGD及其下级页表

释放的内容:

  • PGD(页全局目录)
  • PMD(页中间目录)- 在PAE模式下

4.销毁架构特定上下文

    destroy_context(mm);

作用: 释放架构特定的资源,主要是 LDT

内部操作:

destroy_context(mm)if (mm == current->active_mm) clear_LDT()  // 清除当前LDT→ vfree/kfree(mm->context.ldt)  // 释放LDT内存→ mm->context.size = 0  // 重置上下文大小

5.释放内存描述符本身

    free_mm(mm);
}

宏展开:

#define free_mm(mm) (kmem_cache_free(mm_cachep, (mm)))

作用:mm_struct 对象返回给 SLAB 分配器

SLAB 缓存机制:

  • mm_cachep:专门用于分配 mm_struct 对象的缓存
  • kmem_cache_free():将对象返回缓存,供后续分配重用

四、验证和释放安全上下文security_task_free

static void task_free_security(struct task_struct *task)
{struct task_security_struct *tsec = task->security;if (!tsec || tsec->magic != SELINUX_MAGIC)return;task->security = NULL;kfree(tsec);
}static inline void security_task_free (struct task_struct *p)
{security_ops->task_free_security (p);
}

这是一个 SELinux 安全模块中的任务释放安全钩子函数

1.主要函数:task_free_security

static void task_free_security(struct task_struct *task)
{// 获取任务的安全结构指针struct task_security_struct *tsec = task->security;

参数说明:

  • struct task_struct *task:要释放安全信息的任务结构
  • task->security:指向任务安全相关数据的指针(SELinux 特定)

2.安全检查

    // 检查安全结构是否存在且魔数匹配if (!tsec || tsec->magic != SELINUX_MAGIC)return;

安全验证逻辑:

  • !tsec:如果任务没有安全结构,直接返回
  • tsec->magic != SELINUX_MAGIC:验证魔数是否匹配,防止内存损坏或错误指针
  • SELINUX_MAGIC:是一个预定义的魔数,用于验证结构完整性

3.清理安全信息

    // 清空任务的安全指针task->security = NULL;// 释放安全结构内存kfree(tsec);
}

资源清理步骤:

  1. 断开连接:将 task->security 设为 NULL,防止悬空指针
  2. 释放内存:使用 kfree() 释放安全结构占用的内存

4.封装函数:security_task_free

static inline void security_task_free(struct task_struct *p)
{security_ops->task_free_security(p);
}
  • static inline:内联函数,减少函数调用开销
  • security_ops:指向安全操作函数表的指针
  • 通过函数指针间接调用,支持不同的安全模块

五、释放用户相关的所有资源free_uid

static inline void uid_hash_remove(struct user_struct *up)
{list_del(&up->uidhash_list);
}void free_uid(struct user_struct *up)
{if (up && atomic_dec_and_lock(&up->__count, &uidhash_lock)) {uid_hash_remove(up);key_put(up->uid_keyring);key_put(up->session_keyring);kmem_cache_free(uid_cachep, up);spin_unlock(&uidhash_lock);}
}

这是一个用于管理用户结构(user_struct)引用计数和释放的函数

1.辅助函数:uid_hash_remove

static inline void uid_hash_remove(struct user_struct *up)
{list_del(&up->uidhash_list);
}

作用: 从用户哈希表中移除用户结构

关键点:

  • list_del(&up->uidhash_list):从内核链表中删除节点
  • uidhash_list:用户结构在全局哈希表中的链表节点

2.主函数:free_uid

void free_uid(struct user_struct *up)
{// 检查用户结构是否存在,并原子性地减少引用计数if (up && atomic_dec_and_lock(&up->__count, &uidhash_lock)) {

条件检查逻辑:

  • up:确保用户结构指针有效
  • atomic_dec_and_lock(&up->__count, &uidhash_lock)
    • 原子性地减少引用计数
    • 如果计数变为0,获取自旋锁并返回true
    • 如果计数不为0,返回false

3.清理用户结构

        // 从哈希表中移除用户结构uid_hash_remove(up);// 释放用户相关的密钥环key_put(up->uid_keyring);key_put(up->session_keyring);

资源释放:

  • uid_hash_remove(up):从全局用户哈希表中断开连接
  • key_put(up->uid_keyring):减少用户密钥环的引用计数
  • key_put(up->session_keyring):减少会话密钥环的引用计数

4.最终释放

        // 释放用户结构内存kmem_cache_free(uid_cachep, up);// 释放自旋锁spin_unlock(&uidhash_lock);}
}

内存管理:

  • kmem_cache_free(uid_cachep, up):将对象返回SLAB缓存
  • uid_cachep:专门用于分配user_struct的SLAB缓存
  • spin_unlock(&uidhash_lock):释放保护哈希表的锁

5.使用场景:

场景1:进程退出

  • 最后一个使用该user_struct的进程退出
  • 引用计数降为0,触发完全释放

场景2:用户会话结束

  • 所有属于该用户的进程都退出
  • 用户结构被彻底清理

场景3:凭证切换

  • 进程改变其用户身份
  • 减少旧用户结构的引用计数

六、组信息释放put_group_info

void groups_free(struct group_info *group_info)
{if (group_info->blocks[0] != group_info->small_block) {int i;for (i = 0; i < group_info->nblocks; i++)free_page((unsigned long)group_info->blocks[i]);}kfree(group_info);
}#define put_group_info(group_info) do { \if (atomic_dec_and_test(&(group_info)->usage)) \groups_free(group_info); \
} while (0)

这是一个用于管理组信息(group_info)引用计数和释放的函数

1.主函数:groups_free

void groups_free(struct group_info *group_info)
{// 检查是否使用了动态分配的大块内存if (group_info->blocks[0] != group_info->small_block) {

条件判断逻辑:

  • 比较第一个块指针是否指向内嵌的小块内存
  • group_info->small_block:是内嵌在group_info结构中的小内存块
  • 如果不相等,说明使用了动态分配的页面

2.释放动态分配的块

        // 需要释放动态分配的页面int i;for (i = 0; i < group_info->nblocks; i++)free_page((unsigned long)group_info->blocks[i]);}

内存释放细节:

  • group_info->nblocks:使用的内存块数量
  • free_page((unsigned long)group_info->blocks[i]):释放每个页面
  • free_page():用于释放单个页面(4KB)的内核函数

3.释放组信息结构本身

    // 释放组信息结构kfree(group_info);
}

最终清理: 使用kfree()释放group_info结构本身

4.引用计数封装宏

#define put_group_info(group_info) do { \if (atomic_dec_and_test(&(group_info)->usage)) \groups_free(group_info); \
} while (0)

宏设计分析:

  • atomic_dec_and_test(&(group_info)->usage):原子性地减少引用计数并测试是否为0
  • 只有当最后一个引用被释放时(计数为0),才调用groups_free
  • do { ... } while (0):确保宏在使用时像单个语句一样工作

七、通知链机制notifier_call_chain

int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
{int ret=NOTIFY_DONE;struct notifier_block *nb = *n;while(nb){ret=nb->notifier_call(nb,val,v);if(ret&NOTIFY_STOP_MASK){return ret;}nb=nb->next;}return ret;
}

这是一个通知链(notifier chain)的核心遍历函数,用于依次调用所有注册的通知回调

1.函数定义和初始化

int notifier_call_chain(struct notifier_block **n, unsigned long val, void *v)
{int ret = NOTIFY_DONE;struct notifier_block *nb = *n;

参数说明:

  • struct notifier_block **n:指向通知链头指针的指针
  • unsigned long val:事件值或动作类型
  • void *v:传递给回调函数的通用数据指针

初始化:

  • ret = NOTIFY_DONE:默认返回值,表示没有处理程序关心该事件
  • nb = *n:获取链表的第一个节点

2.链表遍历循环

    while (nb){// 调用当前节点的回调函数ret = nb->notifier_call(nb, val, v);

遍历逻辑:

  • while (nb):循环遍历链表,直到 NULL 结束
  • nb->notifier_call(nb, val, v):调用当前通知块的回调函数

3.停止条件检查

        if (ret & NOTIFY_STOP_MASK){return ret;}

停止掩码检查:

  • NOTIFY_STOP_MASK:通常定义为 0x8000
  • 如果回调返回值包含停止掩码,立即终止遍历并返回
  • 这允许回调函数阻止后续处理程序被调用

4.移动到下一个节点

        nb = nb->next;}

链表前进:

  • nb = nb->next:移动到链表中的下一个通知块
  • 继续循环,直到所有通知块都被处理或遇到停止条件

5.最终返回

    return ret;
}

返回值:

  • 返回最后一个回调函数的返回值
  • 如果没有回调被调用,返回 NOTIFY_DONE

八、任务释放通知分发给注册的分析器profile_handoff_task

int profile_handoff_task(struct task_struct * task)
{int ret;read_lock(&handoff_lock);ret = notifier_call_chain(&task_free_notifier, 0, task);read_unlock(&handoff_lock);return (ret == NOTIFY_OK) ? 1 : 0;
}

这是一个使用通知链(notifier chain)机制的任务移交分析函数

1.函数定义和参数

int profile_handoff_task(struct task_struct * task)
{int ret;

参数说明:

  • struct task_struct *task:要进行分析的任务指针
  • 返回:整数,表示分析结果(1=成功处理,0=未处理)

2.加锁保护

    read_lock(&handoff_lock);

锁机制:

  • handoff_lock:读写锁,保护通知链的并发访问
  • read_lock():获取读锁,允许多个读者同时访问
  • 确保在遍历通知链时链结构不会被修改

3.调用通知链

    ret = notifier_call_chain(&task_free_notifier, 0, task);

通知链调用详解:

  • &task_free_notifier:任务释放通知链头指针
  • 0:事件类型或标志
  • task:传递给所有通知回调函数的参数

4.解锁和返回

    read_unlock(&handoff_lock);return (ret == NOTIFY_OK) ? 1 : 0;
}

返回值逻辑:

  • ret == NOTIFY_OK:返回 1,表示有分析器成功处理了任务
  • 其他情况:返回 0,表示没有分析器处理或处理失败

九、释放任务结构free_task

#define free_thread_info(info)	kfree(info)
#define free_task_struct(tsk)	kmem_cache_free(task_struct_cachep, (tsk))
void free_task(struct task_struct *tsk)
{free_thread_info(tsk->thread_info);free_task_struct(tsk);
}

这是一个用于彻底释放任务结构(task_struct)及其相关资源的函数

1.宏定义

#define free_thread_info(info) kfree(info)
#define free_task_struct(tsk) kmem_cache_free(task_struct_cachep, (tsk))

宏定义详解:

  1. free_thread_info(info)

    • 使用 kfree() 释放线程信息结构
    • info:指向 thread_info 结构的指针
    • kfree():用于释放普通内核内存
  2. free_task_struct(tsk)

    • 使用 kmem_cache_free() 释放任务结构
    • task_struct_cachep:专门用于分配 task_struct 的 SLAB 缓存
    • kmem_cache_free():将对象返回给 SLAB 分配器

2.主函数:free_task

void free_task(struct task_struct *tsk)
{// 释放线程信息结构free_thread_info(tsk->thread_info);// 释放任务结构本身free_task_struct(tsk);
}

十、释放任务相关所有资源__put_task_struct

void __put_task_struct(struct task_struct *tsk)
{WARN_ON(!(tsk->exit_state & (EXIT_DEAD | EXIT_ZOMBIE)));WARN_ON(atomic_read(&tsk->usage));WARN_ON(tsk == current);if (unlikely(tsk->audit_context))audit_free(tsk);security_task_free(tsk);free_uid(tsk->user);put_group_info(tsk->group_info);if (!profile_handoff_task(tsk))free_task(tsk);
}

1.函数定义和参数

void __put_task_struct(struct task_struct *tsk)
{

参数说明:

  • struct task_struct *tsk:要释放的任务结构指针

2.安全检查阶段

    WARN_ON(!(tsk->exit_state & (EXIT_DEAD | EXIT_ZOMBIE)));WARN_ON(atomic_read(&tsk->usage));WARN_ON(tsk == current);

三个关键检查:

  1. 退出状态验证

    WARN_ON(!(tsk->exit_state & (EXIT_DEAD | EXIT_ZOMBIE)));
    
    • 确保任务处于正确的退出状态(EXIT_DEAD 或 EXIT_ZOMBIE)
  2. 引用计数验证

    WARN_ON(atomic_read(&tsk->usage));
    
    • 检查任务的引用计数是否为0
    • 确保没有其他地方仍在引用这个任务结构
  3. 当前任务检查

    WARN_ON(tsk == current);
    
    • 防止释放当前正在运行的任务

3.资源清理阶段

    if (unlikely(tsk->audit_context))audit_free(tsk);

审计上下文清理:

  • tsk->audit_context:任务的审计上下文指针
  • audit_free(tsk):释放审计相关的资源
  • unlikely():提示编译器审计上下文不常见,优化分支预测
    security_task_free(tsk);

安全子系统清理:

  • 调用安全框架的任务释放钩子函数
  • 释放SELinuxr等安全模块的任务安全上下文
  • 确保安全相关的资源被正确清理
    free_uid(tsk->user);

用户结构引用释放:

  • tsk->user:指向user_struct的指针
  • free_uid():减少用户结构的引用计数,如果为0则释放
  • 管理用户资源的共享和释放
    put_group_info(tsk->group_info);

组信息引用释放:

  • tsk->group_info:任务的组信息结构
  • put_group_info():减少组信息的引用计数,如果为0则释放

4.任务移交和最终释放

    if (!profile_handoff_task(tsk))free_task(tsk);
}

性能分析和最终释放:

  1. profile_handoff_task(tsk)

    • 返回1表示分析器接管了任务的释放,返回0表示没有分析器接管
  2. 条件释放

    • 如果没有分析器接管(返回0),立即释放任务
    • 如果有分析器接管(返回1),分析器会在完成分析后负责释放

十一、任务切换完成时清理finish_task_switch

# define finish_arch_switch(rq, next)   spin_unlock_irq(&(rq)->lock)
#define put_task_struct(tsk) \
do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0)
static inline void mmdrop(struct mm_struct * mm)
{if (atomic_dec_and_test(&mm->mm_count))__mmdrop(mm);
}
static void finish_task_switch(task_t *prev)__releases(rq->lock)
{runqueue_t *rq = this_rq();struct mm_struct *mm = rq->prev_mm;unsigned long prev_task_flags;rq->prev_mm = NULL;prev_task_flags = prev->flags;finish_arch_switch(rq, prev);if (mm)mmdrop(mm);if (unlikely(prev_task_flags & PF_DEAD))put_task_struct(prev);
}

这是一个任务切换完成时的清理函数

1.宏定义和辅助函数

# define finish_arch_switch(rq, next)   spin_unlock_irq(&(rq)->lock)
#define put_task_struct(tsk) \
do { if (atomic_dec_and_test(&(tsk)->usage)) __put_task_struct(tsk); } while(0)
static inline void mmdrop(struct mm_struct * mm)
{if (atomic_dec_and_test(&mm->mm_count))__mmdrop(mm);
}

宏和辅助函数说明:

  • finish_arch_switch:完成架构特定的切换,释放运行队列锁
  • put_task_struct:安全释放任务结构的宏,使用引用计数
  • mmdrop:安全释放内存描述符的内联函数,使用引用计数

2.主函数:finish_task_switch

static void finish_task_switch(task_t *prev)__releases(rq->lock)
{runqueue_t *rq = this_rq();struct mm_struct *mm = rq->prev_mm;unsigned long prev_task_flags;rq->prev_mm = NULL;

参数和初始化:

  • task_t *prev:刚刚被切换出去的任务
  • __releases(rq->lock):函数注解,表示会释放运行队列锁
  • this_rq():获取当前CPU的运行队列
  • rq->prev_mm:保存的前一个内存描述符
  • 立即将 rq->prev_mm 设为 NULL,防止重复使用

3.架构切换完成和资源清理

    prev_task_flags = prev->flags;finish_arch_switch(rq, prev);

保存状态和完成切换:

  • 保存前一个任务的标志位
  • finish_arch_switch(rq, prev):释放运行队列锁,允许其他CPU调度
    if (mm)mmdrop(mm);

内存描述符清理:

  • 如果存在前一个内存描述符,释放它
  • mmdrop() 会检查引用计数,只在最后一个引用时真正释放
    if (unlikely(prev_task_flags & PF_DEAD))put_task_struct(prev);
}

任务结构释放:

  • 检查前一个任务是否标记为PF_DEAD(已死亡)
  • unlikely():提示编译器这种情况很少见
  • 如果任务已死亡,释放其任务结构

4.内存管理特殊情况

4.1.内核线程的内存管理

  • 内核线程没有自己的用户空间(mm = NULL)
  • 但会借用前一个任务的active_mm
  • 线程切换时会把内核线程借用的mm_struct保存在rq->prev_mm
  • 当内核线程退出时,需要清理借用的mm_struct,即rq->prev_mm

5.并发安全考虑

5.1.锁的保护范围

  • 在finish_arch_switch之前
    • 运行队列锁被持有
    • 可以安全检查prev->state和prev->flags
  • 在finish_arch_switch之后
    • 锁已释放,其他CPU可以调度prev任务
    • 因此必须在释放锁前保存状态prev->flags
http://www.dtcms.com/a/432101.html

相关文章:

  • Ubuntu 20.04升级python3.9后不能Update系统
  • 实战项目与工程化:端到端机器学习流程全解析
  • 阿里云做网站预装环境阿里巴巴做轮播网站
  • 做外贸要看哪些网站更换wordpress语言包
  • 天理维度与织死网解析
  • 为哈尔滨网页设计制作seo网站推广费用
  • eSIM技术的革新之路:SGP.32协议如何重塑智能设备连接未来
  • 网站建设备案不通过网站开发质量控制计划书
  • 网站建设纯免费官网企业网站怎样做外链方法
  • 手写数字识别 (卷积神经网络)
  • 建设银行永泰支行网站公司网站建设哪家比较好
  • 找外包网站 和自己做汕头网站优化哪家好
  • 深圳企业网站建设报价wordpress网站可以上传视频
  • Linux(线程库和线程封装)
  • 制作网站公司名称动漫制作专业在广西哪所院校最强
  • 网站后台cms南京的互联网公司
  • 西安工商注册网上平台株洲网站排名优化价格
  • 网站建设与运营 就业深夜的fm免费看
  • 汽车配件外贸网站爱企查商标查询
  • 诸城盟族网站建设做招牌的广告公司
  • 数字信号处理 第一章(离散时间信号与系统)【下】
  • 【星海出品】程序的存储访问 - Q-A解答
  • 怎么查网站服务器优化seo方案
  • 10.1 面向长序列建模的高效注意力机制
  • 怎么自己做网站挣钱网站cn和com有什么区别
  • java线上问题排查-OOM内存溢出
  • 阿里云国际站官网如何让网站不被收录
  • Notepad++下载安装图文教程(附安装包)
  • ProtoBuf使用手册(入门)
  • 网站服务器 电信推广码怎么填