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  阅读(28)  评论(0)    收藏  举报