温暖的电波  

一、概念

  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;            

};

posted on 2016-05-25 20:04  温暖的电波  阅读(647)  评论(0)    收藏  举报