回忆下回调函数使用
            
            
              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_H2.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 修改后就 会触发回调函数起作用