019.线程级接管eBPF内核志输出

函数bpf_get_current_pid_tgid得到的是进程id与线程id

image

前面的代码

存储日志是以pid为key

考虑到以后支持多线程

将存储日志的key改成进程id+线程id

具体操作,看视频


bpf_get_current_pid_tgid() 是 eBPF 里最常用、但也最容易被误解的 helper 之一。
我直接给你一个工程级、可上课用的解释。


一句话结论(标准答案)

bpf_get_current_pid_tgid()** 返回一个 u64
****高 32 位是 tgid(进程 ID),
**低 32 位是 pid(线程 ID / TID)。


精确定义(非常重要)

u64 id = bpf_get_current_pid_tgid();

位布局是:

63 ............... 32 | 31 ............... 0
        tgid (PID)     |        pid (TID)

也就是:

tgid = id >> 32;
pid  = (u32)id;

二、什么是 pid?什么是 tgid?(一定要讲清)

在 Linux 内核里:

名称 含义
pid 线程 ID(task_struct->pid)
tgid 线程组 ID(task_struct->tgid)

用户态常见的 getpid()

getpid() == tgid

用户态的 gettid()

gettid() == pid

三、典型正确用法(你现在课程里一定在用)

1️⃣ 只关心“哪个进程”

u64 id = bpf_get_current_pid_tgid();
u32 pid = id >> 32;   // tgid

👉 99% tracing 工具用这个


2️⃣ 区分同一进程里的不同线程

u64 id = bpf_get_current_pid_tgid();
u32 tgid = id >> 32;
u32 tid  = (u32)id;

👉 sched / lock / futex / pthread 场景必须这样


四、一个非常常见、也非常致命的坑 ❗

❌ 错误写法(你前面也问过)

u32 tid = pid_tgid >> 32;
u32 pid = (u32)pid_tgid;

👉 变量名和含义是反的


✅ 正确命名(强烈建议你在课里强调)

u64 pid_tgid = bpf_get_current_pid_tgid();

u32 tgid = pid_tgid >> 32;   // 进程 ID
u32 pid  = (u32)pid_tgid;    // 线程 ID

五、为什么要把 pid / tgid 塞在一个 u64 里?

这是 eBPF helper 设计的工程取舍

  1. 减少 helper 数量
  2. 一次读取,避免竞态
  3. map key 常用 u64
  4. 历史兼容(早期 BPF helper 设计)

六、和用户态看到的对照表(学生秒懂)

场景 eBPF 用户态
进程 ID tgid getpid()
线程 ID pid gettid()
单线程程序 pid == tgid 一样
多线程程序 pid ≠ tgid 不一样

七、一个真实例子(你可以直接贴)

假设某进程:

  • 进程号:1000
  • 某线程号:1003

那么:

u64 id = bpf_get_current_pid_tgid();
// id = 0x000003E8_000003EB

tgid = 1000
pid  = 1003

八、课堂级总结(非常推荐)

**bpf_get_current_pid_tgid()
****返回的不是“一个 pid”,
**而是“一个进程 + 一个线程”。

posted @ 2026-06-02 00:38  BlackSnow  阅读(11)  评论(0)    收藏  举报