C语言 了解一下回调函数(钩子函数)的使用

回忆下回调函数使用

cs 复制代码
 static int sugov_start(struct cpufreq_policy *policy)
871  {
872  	struct sugov_policy *sg_policy = policy->governor_data;
873  	void (*uu)(struct update_util_data *data, u64 time, unsigned int flags);
874  	unsigned int cpu;
875  
876  	sg_policy->freq_update_delay_ns	= sg_policy->tunables->rate_limit_us * NSEC_PER_USEC;
877  	sg_policy->last_freq_update_time	= 0;
878  	sg_policy->next_freq			= 0;
879  	sg_policy->work_in_progress		= false;
880  	sg_policy->limits_changed		= false;
881  	sg_policy->cached_raw_freq		= 0;
882  
883  	sg_policy->need_freq_update = cpufreq_driver_test_flags(CPUFREQ_NEED_UPDATE_LIMITS);
884  
885  	if (policy_is_shared(policy))
886  		uu = sugov_update_shared;
887  	else if (policy->fast_switch_enabled && cpufreq_driver_has_adjust_perf())
888  		uu = sugov_update_single_perf;
889  	else
890  		uu = sugov_update_single_freq;
891  
892  	for_each_cpu(cpu, policy->cpus) {
893  		struct sugov_cpu *sg_cpu = &per_cpu(sugov_cpu, cpu);
894  
895  		memset(sg_cpu, 0, sizeof(*sg_cpu));
896  		sg_cpu->cpu = cpu;
897  		sg_cpu->sg_policy = sg_policy;
898  		cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util, uu);
899  	}
900  	return 0;
901  }

cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util, uu) 是 Linux 内核中 连接调度器(scheduler)与 CPUFreq 调频子系统 的关键机制。

为指定 CPU 注册一个"利用率更新回调函数",使得每当调度器感知到任务负载变化时,能立即通知 CPUFreq governor(如 schedutil)进行频率调整。

函数原型

cs 复制代码
void cpufreq_add_update_util_hook(int cpu,
                                  struct update_util_data *data,
                                  void (*func)(struct update_util_data *, u64, unsigned int));

在你的调用中:

cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util, uu);

  • &sg_cpu->update_util:类型是 struct update_util_data *作为输出参数
  • uu:是一个 函数指针 ,类型为 void (*)(struct update_util_data *, u64, unsigned int),这才是真正的回调函数

🔍 一、函数参数解析

cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util, uu);

cpu 目标 CPU 编号
&sg_cpu->update_util 输出参数 :用于存储注册后的回调函数指针(通常指向sugov_update_util()
uu 输入参数 :调度器提供的util update 回调函数 (如sugov_update_util()的地址)

✅ 调用后,sg_cpu->update_util 会被赋值为一个可调用的函数指针。

内核中 cpufreq_add_update_util_hook() 做了什么?

复制代码
void cpufreq_add_update_util_hook(int cpu, struct update_util_data *data,
31  			void (*func)(struct update_util_data *data, u64 time,
32  				     unsigned int flags))
33  {
34  	if (WARN_ON(!data || !func))
35  		return;
36  
37  	if (WARN_ON(per_cpu(cpufreq_update_util_data, cpu)))
38  		return;
39  
40  	data->func = func;   // ← 把 uu 赋值给 data->func
41  	rcu_assign_pointer(per_cpu(cpufreq_update_util_data, cpu), data);
42  }
43  EXPORT_SYMBOL_GPL(cpufreq_add_update_util_hook);

调度器如何触发回调?

// 在 kernel/sched/core.c 中
if (rq->update_util)
rq->update_util(rq->update_util_data, time, flags);

二. 自己写一个钩子函数看下具体使用

2.1 test.h

cs 复制代码
//
// Created by wyd on 2025/10/30.
//

#ifndef TEST1019_TEST_H
#define TEST1019_TEST_H

#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>


/* 利用率更新标志 */
#define UTIL_UPDATE_IOWAIT     (1U << 0)  // I/O 唤醒
#define UTIL_UPDATE_MIGRATION  (1U << 1)  // 任务迁移
#define UTIL_UPDATE_IDLE       (1U << 2)  // CPU 空闲

/* 钩子回调函数类型 */
typedef void (*util_update_fn_t)(void *data, uint64_t time, unsigned int flags);

/* 钩子数据结构(类似 struct update_util_data) */
struct util_update_data {
    util_update_fn_t func;  // 回调函数指针
    void *private;          // 私有数据(如 sugov_cpu*)
};

/* 每个 CPU 的运行队列模拟 */
struct runqueue {
    int cpu;
    struct util_update_data *update_util;  // 钩子指针
};

/* 全局 CPU 运行队列数组(简化版) */
extern struct runqueue rq_table[];

/* 注册钩子 */
void util_hook_add(int cpu, struct util_update_data *data,
                   util_update_fn_t fn, void *private);

/* 注销钩子 */
void util_hook_remove(int cpu);

/* 触发钩子(由调度器调用) */
void util_hook_trigger(int cpu, uint64_t time, unsigned int flags);


#endif //TEST1019_TEST_H

2.2 test.c

cs 复制代码
//
// Created by wyd on 2025/10/30.
//

#include "test.h"

#define NR_CPUS 4  // 假设 4 核 CPU

struct runqueue rq_table[NR_CPUS];

void util_hook_add(int cpu, struct util_update_data *data,
                   util_update_fn_t fn, void *private)
{
    if (cpu < 0 || cpu >= NR_CPUS) {
        fprintf(stderr, "Invalid CPU %d\n", cpu);
        return;
    }

    data->func = fn;
    data->private = private;

    rq_table[cpu].update_util = data;
    rq_table[cpu].cpu = cpu;

    printf("Hook registered on CPU %d\n", cpu);
}

void util_hook_trigger(int cpu, uint64_t time, unsigned int flags)
{
    struct runqueue *rq = &rq_table[cpu];
    if (rq->update_util && rq->update_util->func) {
        rq->update_util->func(rq->update_util->private, time, flags);
    }
}

void util_hook_remove(int cpu)
{
    if (cpu < 0 || cpu >= NR_CPUS) return;
    rq_table[cpu].update_util = NULL;
    printf("Hook removed from CPU %d\n", cpu);
}

2.3 main.c

cs 复制代码
#include "test.h"

/* 模拟一个 governor 的 per-CPU 数据 */
struct my_gov_cpu {
    int cpu;
    unsigned long util;
    bool iowait_pending;
};

/* 回调函数:当调度器通知利用率更新时调用 */
static void my_gov_update_util(void *data, uint64_t time, unsigned int flags)
{
    struct my_gov_cpu *gov_cpu = (struct my_gov_cpu *)data;

    printf("[CPU %d] Update at time %llu, flags=0x%x\n",
           gov_cpu->cpu, (unsigned long long)time, flags);

    if (flags & UTIL_UPDATE_IOWAIT) {
        printf("  → I/O wake-up detected! Boosting frequency.\n");
        gov_cpu->iowait_pending = true;
    }

    // 这里可以调用频率调整逻辑
    // set_cpu_frequency(gov_cpu->cpu, new_freq);
}


int main() {



    const int cpu = 0;

    struct my_gov_cpu gov_cpu = {.cpu = cpu};

    struct util_update_data hook_data;

    /* 1. 注册钩子 */
    util_hook_add(cpu, &hook_data, my_gov_update_util, &gov_cpu);

    /* 2. 模拟调度器事件 */
    uint64_t now = time(NULL) * 1000000000ULL; // 纳秒级时间

    // 普通任务唤醒
    util_hook_trigger(cpu, now, 0);

    // I/O 唤醒
    util_hook_trigger(cpu, now + 1000000, UTIL_UPDATE_IOWAIT);

    // 任务迁移
    util_hook_trigger(cpu, now + 2000000, UTIL_UPDATE_MIGRATION);

    /* 3. 注销钩子 */
    util_hook_remove(cpu);




    return 0;



}

2.4 输出结果


Hook registered on CPU 0

CPU 0\] Update at time 1761835217000000000, flags=0x0 \[CPU 0\] Update at time 1761835217001000000, flags=0x1 → I/O wake-up detected! Boosting frequency. \[CPU 0\] Update at time 1761835217002000000, flags=0x2 Hook removed from CPU 0

flag 修改后就 会触发回调函数起作用

相关推荐
Yupureki6 小时前
从零开始的C++学习生活 18:C语言复习课(期末速通)
c语言·数据结构·c++·学习·visual studio
java1234_小锋6 小时前
PyTorch2 Python深度学习 - 数据集与数据加载
开发语言·python·深度学习·pytorch2
千码君20166 小时前
Go语言:常量计数器iota的意义
开发语言·后端·golang·状态码·const·iota·常量
永远有缘7 小时前
四种编程语言常用函数对比表
java·开发语言·c++·python
Pocker_Spades_A7 小时前
Python快速入门专业版(五十三):Python程序调试进阶:PyCharm调试工具(可视化断点与变量监控)
开发语言·python·pycharm
C++_girl7 小时前
c++、java/python语言有什么区别?为什么c++更快?
java·开发语言·c++
彩妙不是菜喵7 小时前
基于C语言上,面向对象语言:C++基础(学完C语言后再看)
c语言·开发语言·c++
脸大是真的好~7 小时前
黑马JAVA+AI 加强07 Stream流-可变参数
java·开发语言