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

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

回忆下回调函数使用

 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)进行频率调整。

函数原型

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

//
// 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

//
// Created by wyd on 2025/10/30.
//#include "test.h"#define NR_CPUS 4  // 假设 4 核 CPUstruct 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

#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 修改后就 会触发回调函数起作用

http://www.dtcms.com/a/550274.html

相关文章:

  • 网站制作内容在线网站制作系统源码
  • 校园微网站建设方案ppt模板下载文本编辑器 网站
  • 长沙便宜做网站帝国cms网站地图生成
  • 软件测试大赛赛前培训【Web测试】
  • 解决Docker Buildx导致镜像拉取失败的问题
  • 网站建设对电子商务中的作用网上销售哪些平台免费
  • 信贷员在哪个网站做推广陕西城乡住房建设厅网站
  • 从哪看出网站的建站公司php网站开发工程
  • zabbix 模板 监控项 图形
  • 不联网环境docker安装及python示例镜像
  • 10.30 MySQL数据库基础
  • 网站流量到底怎样赚钱的住建部2022年执行的新规范
  • 做番号网站犯法吗利州区住房和城乡建设部网站
  • Spring Boot Web开发篇:构建RESTful API
  • 跨越时间的鸿沟:解构 Rust 异步编程中的生命周期挑战
  • 网站的建设及维护报告2018年网站建设发言
  • 珠海网站开发排名江苏南京今天的新消息
  • 免费模型网站信息公司网站建设方案 游戏
  • 北京做冷冻牛羊肉的网站平邑县住房和城乡建设局网站
  • 一条SQL如何实现insertOrUpdate
  • 结构优化过程可视化的两种方法
  • 做网站建站点seo的描述正确
  • 百度站长seo搭建网站需要学什么
  • 旅游网站 系统江阴百度推广公司
  • Spring Al学习9:模型上下文协议(MCP)
  • 浙江省大成建设集团有限公司网站wordpress 插件有后门
  • linux 网站开发网络营销员岗位的职责与要求
  • 网站首页置顶是怎么做电商系统服务好的商家
  • 做网站没有数据家庭网做网站
  • 陕西高速公路建设网站有专门做辩论的网站吗