一、概念
pi_futex有着两层含义:
pi表示优先级继承,即Priority inheritance;futex表示Fast Userspace Locking;
futex实现了 在没有锁冲突的情况下 从用户态利获取锁,而锁被其他人持有、需要挂起等待时再通过系统调用进入到内核睡眠与唤醒;
pi_futex就是在futex的基础上为了解决优先级反转问题,实现了优先级继承机制。
二、相关数据结构和成员
1. task_struct:
一个任务可以拥有多个锁资源,每个资源都可能阻塞n个其他的任务(n>=0),但一个任务只能被一个锁资源阻塞。
struct task_struct { /* Protection of the PI data structures: */ raw_spinlock_t pi_lock; //保护PI相关数据结构的锁
/* PI waiters blocked on a rt_mutex held by this task */ struct rb_root pi_waiters; //通过它可遍历本task持有每个rt_mutex上挂起的最高优先级的task struct rb_node *pi_waiters_leftmost; ////保存优先级最高的waiter,用于提高查询效率 /* Deadlock detection and priority inheritance handling */ struct rt_mutex_waiter *pi_blocked_on; //与此任务对应的rt_mutex_waiter结构
/* Top pi_waiters task */ struct task_struct *pi_top_task; struct list_head pi_state_list; //此任务所持有的所有的mutex相关的futex_pi_state结构链表,通过此链表 //可以遍历本task所持有的所有rt_mutex(通过pi_state.pi_mutex)
struct futex_pi_state *pi_state_cache; //挂起本task的锁的pi_state,如果已经有其他的任务先于自己阻塞 //在此lock上,pi_state_cache则不使用 }
2. rt_mutex_waiter
用于被锁阻塞的任务控制结构,可以看作是一个被阻塞任务的封装。
struct rt_mutex_waiter { struct rb_node tree_entry; //通过tree_entry链入到rt_mutex->waiters红黑树中 struct rb_node pi_tree_entry; //通过pi_tree_entry链入到task_struct 的pi_waiters RB树,只有此waiter是锁上优先级最高的任务才会被链入 struct task_struct *task; //指向被阻塞任务的task_struct
struct rt_mutex *lock; //阻塞自己的rt_mutex
bool savestate; int prio; };
3. rt_mutex
一把锁可以有n个任务阻塞,但只能被一个任务锁持有。
struct rt_mutex { raw_spinlock_t wait_lock; struct rb_root waiters; //等待此锁的任务,即rt_mutex_waiter。这些waiters通过tree_entry链入,用rb_root按照优先级高低顺序组织 struct rb_node *waiters_leftmost; //阻塞在此锁上的优先级最高的任务
struct task_struct *owner; //锁持有者 int save_state; };
4. futex_pi_state
futex_pi_state可以看成是对rt_mutex的包装,以及用户态uaddr到内核态的rt_mutex的桥梁。
struct futex_pi_state { struct list_head list; // 链入持有者task的 task_struct.pi_state_list 链表中 struct rt_mutex pi_mutex; // 锁本身 struct task_struct *owner; // 锁的持有者进程 atomic_t refcount; // 引用计数 union futex_key key; // 唯一标识uaddr的key值 };
5. futex_q
uaddr在内核中会对应(这个对应关系是通过hash来实现的)一个"等待队列"(其实是一个全局的队列)。挂起的进程在等待队列中对应一个futex_q结构。
struct futex_q { struct plist_node list; // 链入等待队列 struct task_struct *task; // 挂起的进程本身 spinlock_t *lock_ptr; // 保存等待队列的锁,便于操作 union futex_key key; // 唯一标识uaddr的key值 struct futex_pi_state *pi_state; // 进程正在等待的锁 struct rt_mutex_waiter *rt_waiter; // 进程对应的rt_waiter union futex_key *requeue_pi_key; // 等待被requeue的key u32 bitset; // futex_XXX_bitset时使用 };
struct rt_mutex {
raw_spinlock_t wait_lock;
struct rb_root waiters; //等待此锁的任务(即rt_mutex_waiter,(这些
//waiters通过tree_entry链入),用rb_root按
//照优先级高低顺序组织
struct rb_node *waiters_leftmost; //等待这个锁优先级最高的任务
struct task_struct *owner; //锁持有者
int save_state;
};