由__futex_syscall3略微展开

本文介绍了Android系统中bionic库的__futex_syscall3函数。该函数用于线程管理,是__futex_wake的实现方式之一,支持多种操作码如FUTEX_WAIT和FUTEX_WAKE等。文章还探讨了该函数在ARM架构下的汇编实现细节。

1. __futex_syscall3 是啥

__futex_syscall3是android bionc库(一种libc库,为了不与开源组织冲撞,特地不采用glibc)。__futex_syscall3是android的一种线程管理函数。相当于wake。

该函数见于 /bionic/libc/bionic/pthread.c


int  __futex_wake_ex(volatile void *ftx, int pshared, int val)
{
    return __futex_syscall3(ftx, pshared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, val);
}

和 bionic/libc/arch-arm/bionic/futex_arm.S

// __futex_syscall3(*ftx, op, val)
ENTRY(__futex_syscall3)
    mov     ip, r7
    ldr     r7, =__NR_futex
    swi     #0
    mov     r7, ip
    bx      lr
END(__futex_syscall3)

2. 具体看看

extern int __futex_syscall3(volatile void *ftx, int op, int val);
extern int __futex_syscall4(volatile void *ftx, int op, int val,
const struct timespec *timeout);
__futex_syscall3()相当于__futex_wake(),而__futex_syscall4()相当于__futex_wait()。这两个函数与前面的区别是能指定操作码op做为参数。操作码可以是FUTEX_WAIT,FUTEX_WAKE或者它们和FUTEX_PRIVATE_FLAG的组合。

3. 实际中看

之所以注意到该点,是因为调试用IDA 调试android应用的时候,当加载so库的时候,会自动停在下面的arm汇编代码处。

这里写图片描述
经过查看android源码,发现这其实就是存在于bionic/libc/arch-arm/bionic/futex_arm.S 的过程。但是对比起来确实不同。
但是自系思考,源码中用的寄存器ip,也就是R12寄存器的别名,这个寄存器承担内部调用的作用。当函数返回时然后重新恢复R7寄存器。
我们在看看IDA中实际的汇编代码,我们看到我们的谷歌NEXUS手机中用的stmfd sp!,{r4,r7}通过栈来保存寄存器的值,然后用ldmfd sp!,{r4,r7}来恢复寄存器的值。实际效果一样。

### CPU选核调度栈中`select_task_rq_fair`函数的作用及调用链分析 #### 1. `select_task_rq_fair` 函数作用 `select_task_rq_fair` 是 Linux 内核公平调度类 (`fair_sched_class`) 的一部分,主要用于为即将运行的任务选择最适合的运行队列 (Run Queue, RQ)。该函数综合考虑了多种因素,例如任务的历史迁移成本、目标CPU的负载均衡状态以及能量效率等因素[^3]。 以下是 `select_task_rq_fair` 的主要功能分解: - **负载均衡**: 它会尝试将任务分配到负载较低的CPU上,从而提高整体系统的吞吐量。 - **亲和性约束**: 尊重任务的CPU亲和性设置 (`task_struct::cpus_ptr`),确保任务仅在允许的范围内运行。 - **节能策略**: 结合能耗模型,优先选择能效更高的CPU核心以降低功耗[^2]。 ```c int select_task_rq_fair(struct task_struct *p, int sd_flag, int wake_flags) { ... if (sched_feat(LB_BIAS)) new_cpu = cpumask_any_and(p->cpus_ptr, imbalance_mask); // 如果启用了节能策略,则尝试找到更高效的cpu if (sd && !(wake_flags & WF_TTWU)) { new_cpu = mtk_find_energy_efficient_cpu(p); } ... return new_cpu; } ``` --- #### 2. 调用链分析 ##### (1)`try_to_wake_up` 当一个任务被唤醒时,`try_to_wake_up` 函数会被调用。它是任务唤醒的核心入口之一,负责更新任务的状态并将任务放入适当的运行队列中。在此过程中,`try_to_wake_up` 会调用 `select_task_rq` 来确定目标任务应该运行在哪一个CPU上[^1]。 ```c int try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) { ... next_cpu = select_task_rq(p, SD_BALANCE_WAKE, wake_flags); set_task_cpu(p, next_cpu); enqueue_task(rq, p, ENQUEUE_WAKING | ENQUEUE_MIGRATED); ... } ``` ##### (2)`wake_up_new_task` 对于新建的任务,`wake_up_new_task` 函数会在初始化完成后将其加入到运行队列中。同样地,它也会调用 `select_task_rq` 来完成CPU的选择工作。 ```c void wake_up_new_task(struct task_struct *p) { ... cpu = select_task_rq(p, SD_BALANCE_FORK, 0); set_task_cpu(p, cpu); enqueue_task(rq_of(cpu), p, ENQUEUE_NOCLOCK); ... } ``` ##### (3)`futex_wake` Futex机制是Linux内核提供的一种轻量级同步工具,广泛应用于用户态线程库(如pthread)。当某个条件变量满足时,`futex_wake` 会唤醒等待的线程,并通过调用 `sys_futex` 系统调用间接触发 `try_to_wake_up` 和 `select_task_rq_fair` 的执行链条[^1]。 ```c long sys_futex(u32 __user *uaddr, int op, u32 val, ...) { ... ret = futex_wait_setup(...); if (!ret) { queue_me(...); if (!(flags & FLAGS_SHARED)) current->robust_list = NULL; schedule(); // 唤醒其他进程时发生的调度行为 unqueue_me_pi(...); } return ret; } ``` ##### (4)`__traceiter_sched_runnable_boost` 从日志信息来看,`__traceiter_sched_runnable_boost` 是跟踪可运行任务提升的关键点之一。它可以记录任务是否具备运行资格以及是否有足够的资源支持其运行。这一部分通常与性能监控和调试密切相关。 --- ### 总结说明 在整个CPU选核的过程中,`select_task_rq_fair` 扮演着至关重要的角色。它不仅决定了任务的初始放置位置,还直接影响了系统的负载分布和能源消耗状况。通过对上述调用链的分析可以看出,无论是任务创建、唤醒还是同步操作,都离不开这一核心函数的支持。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值