Skip to content

Commit

Permalink
Merge branch 'tip/futex/devel' of git://git.kernel.org/pub/scm/linux/…
Browse files Browse the repository at this point in the history
…kernel/git/rostedt/linux-2.6-rt into core/futexes

 futex,plist: Pass the real head of the priority list to plist_del()
 futex,plist: Remove debug lock assignment from plist_node
 plist: Shrink struct plist_head
 plist: Add priority list test
  • Loading branch information
KAGA-KOKO committed Mar 12, 2011
2 parents 8d7718a + 6d55da5 commit 9956121
Show file tree
Hide file tree
Showing 3 changed files with 162 additions and 60 deletions.
47 changes: 24 additions & 23 deletions include/linux/plist.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,17 @@
*
* Simple ASCII art explanation:
*
* |HEAD |
* | |
* |prio_list.prev|<------------------------------------|
* |prio_list.next|<->|pl|<->|pl|<--------------->|pl|<-|
* |10 | |10| |21| |21| |21| |40| (prio)
* | | | | | | | | | | | |
* | | | | | | | | | | | |
* |node_list.next|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-|
* |node_list.prev|<------------------------------------|
* pl:prio_list (only for plist_node)
* nl:node_list
* HEAD| NODE(S)
* |
* ||------------------------------------|
* ||->|pl|<->|pl|<--------------->|pl|<-|
* | |10| |21| |21| |21| |40| (prio)
* | | | | | | | | | | |
* | | | | | | | | | | |
* |->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-|
* |-------------------------------------------|
*
* The nodes on the prio_list list are sorted by priority to simplify
* the insertion of new nodes. There are no nodes with duplicate
Expand Down Expand Up @@ -78,7 +80,6 @@
#include <linux/spinlock_types.h>

struct plist_head {
struct list_head prio_list;
struct list_head node_list;
#ifdef CONFIG_DEBUG_PI_LIST
raw_spinlock_t *rawlock;
Expand All @@ -88,7 +89,8 @@ struct plist_head {

struct plist_node {
int prio;
struct plist_head plist;
struct list_head prio_list;
struct list_head node_list;
};

#ifdef CONFIG_DEBUG_PI_LIST
Expand All @@ -100,7 +102,6 @@ struct plist_node {
#endif

#define _PLIST_HEAD_INIT(head) \
.prio_list = LIST_HEAD_INIT((head).prio_list), \
.node_list = LIST_HEAD_INIT((head).node_list)

/**
Expand Down Expand Up @@ -133,7 +134,8 @@ struct plist_node {
#define PLIST_NODE_INIT(node, __prio) \
{ \
.prio = (__prio), \
.plist = { _PLIST_HEAD_INIT((node).plist) }, \
.prio_list = LIST_HEAD_INIT((node).prio_list), \
.node_list = LIST_HEAD_INIT((node).node_list), \
}

/**
Expand All @@ -144,7 +146,6 @@ struct plist_node {
static inline void
plist_head_init(struct plist_head *head, spinlock_t *lock)
{
INIT_LIST_HEAD(&head->prio_list);
INIT_LIST_HEAD(&head->node_list);
#ifdef CONFIG_DEBUG_PI_LIST
head->spinlock = lock;
Expand All @@ -160,7 +161,6 @@ plist_head_init(struct plist_head *head, spinlock_t *lock)
static inline void
plist_head_init_raw(struct plist_head *head, raw_spinlock_t *lock)
{
INIT_LIST_HEAD(&head->prio_list);
INIT_LIST_HEAD(&head->node_list);
#ifdef CONFIG_DEBUG_PI_LIST
head->rawlock = lock;
Expand All @@ -176,7 +176,8 @@ plist_head_init_raw(struct plist_head *head, raw_spinlock_t *lock)
static inline void plist_node_init(struct plist_node *node, int prio)
{
node->prio = prio;
plist_head_init(&node->plist, NULL);
INIT_LIST_HEAD(&node->prio_list);
INIT_LIST_HEAD(&node->node_list);
}

extern void plist_add(struct plist_node *node, struct plist_head *head);
Expand All @@ -188,7 +189,7 @@ extern void plist_del(struct plist_node *node, struct plist_head *head);
* @head: the head for your list
*/
#define plist_for_each(pos, head) \
list_for_each_entry(pos, &(head)->node_list, plist.node_list)
list_for_each_entry(pos, &(head)->node_list, node_list)

/**
* plist_for_each_safe - iterate safely over a plist of given type
Expand All @@ -199,7 +200,7 @@ extern void plist_del(struct plist_node *node, struct plist_head *head);
* Iterate over a plist of given type, safe against removal of list entry.
*/
#define plist_for_each_safe(pos, n, head) \
list_for_each_entry_safe(pos, n, &(head)->node_list, plist.node_list)
list_for_each_entry_safe(pos, n, &(head)->node_list, node_list)

/**
* plist_for_each_entry - iterate over list of given type
Expand All @@ -208,7 +209,7 @@ extern void plist_del(struct plist_node *node, struct plist_head *head);
* @mem: the name of the list_struct within the struct
*/
#define plist_for_each_entry(pos, head, mem) \
list_for_each_entry(pos, &(head)->node_list, mem.plist.node_list)
list_for_each_entry(pos, &(head)->node_list, mem.node_list)

/**
* plist_for_each_entry_safe - iterate safely over list of given type
Expand All @@ -220,7 +221,7 @@ extern void plist_del(struct plist_node *node, struct plist_head *head);
* Iterate over list of given type, safe against removal of list entry.
*/
#define plist_for_each_entry_safe(pos, n, head, m) \
list_for_each_entry_safe(pos, n, &(head)->node_list, m.plist.node_list)
list_for_each_entry_safe(pos, n, &(head)->node_list, m.node_list)

/**
* plist_head_empty - return !0 if a plist_head is empty
Expand All @@ -237,7 +238,7 @@ static inline int plist_head_empty(const struct plist_head *head)
*/
static inline int plist_node_empty(const struct plist_node *node)
{
return plist_head_empty(&node->plist);
return list_empty(&node->node_list);
}

/* All functions below assume the plist_head is not empty. */
Expand Down Expand Up @@ -285,7 +286,7 @@ static inline int plist_node_empty(const struct plist_node *node)
static inline struct plist_node *plist_first(const struct plist_head *head)
{
return list_entry(head->node_list.next,
struct plist_node, plist.node_list);
struct plist_node, node_list);
}

/**
Expand All @@ -297,7 +298,7 @@ static inline struct plist_node *plist_first(const struct plist_head *head)
static inline struct plist_node *plist_last(const struct plist_head *head)
{
return list_entry(head->node_list.prev,
struct plist_node, plist.node_list);
struct plist_node, node_list);
}

#endif
40 changes: 23 additions & 17 deletions kernel/futex.c
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,24 @@ static int futex_lock_pi_atomic(u32 __user *uaddr, struct futex_hash_bucket *hb,
return ret;
}

/**
* __unqueue_futex() - Remove the futex_q from its futex_hash_bucket
* @q: The futex_q to unqueue
*
* The q->lock_ptr must not be NULL and must be held by the caller.
*/
static void __unqueue_futex(struct futex_q *q)
{
struct futex_hash_bucket *hb;

if (WARN_ON(!q->lock_ptr || !spin_is_locked(q->lock_ptr)
|| plist_node_empty(&q->list)))
return;

hb = container_of(q->lock_ptr, struct futex_hash_bucket, lock);
plist_del(&q->list, &hb->chain);
}

/*
* The hash bucket lock must be held when this is called.
* Afterwards, the futex_q must not be accessed.
Expand All @@ -789,7 +807,7 @@ static void wake_futex(struct futex_q *q)
*/
get_task_struct(p);

plist_del(&q->list, &q->list.plist);
__unqueue_futex(q);
/*
* The waiting task can free the futex_q as soon as
* q->lock_ptr = NULL is written, without taking any locks. A
Expand Down Expand Up @@ -1064,9 +1082,6 @@ void requeue_futex(struct futex_q *q, struct futex_hash_bucket *hb1,
plist_del(&q->list, &hb1->chain);
plist_add(&q->list, &hb2->chain);
q->lock_ptr = &hb2->lock;
#ifdef CONFIG_DEBUG_PI_LIST
q->list.plist.spinlock = &hb2->lock;
#endif
}
get_futex_key_refs(key2);
q->key = *key2;
Expand All @@ -1093,16 +1108,12 @@ void requeue_pi_wake_futex(struct futex_q *q, union futex_key *key,
get_futex_key_refs(key);
q->key = *key;

WARN_ON(plist_node_empty(&q->list));
plist_del(&q->list, &q->list.plist);
__unqueue_futex(q);

WARN_ON(!q->rt_waiter);
q->rt_waiter = NULL;

q->lock_ptr = &hb->lock;
#ifdef CONFIG_DEBUG_PI_LIST
q->list.plist.spinlock = &hb->lock;
#endif

wake_up_state(q->task, TASK_NORMAL);
}
Expand Down Expand Up @@ -1450,9 +1461,6 @@ static inline void queue_me(struct futex_q *q, struct futex_hash_bucket *hb)
prio = min(current->normal_prio, MAX_RT_PRIO);

plist_node_init(&q->list, prio);
#ifdef CONFIG_DEBUG_PI_LIST
q->list.plist.spinlock = &hb->lock;
#endif
plist_add(&q->list, &hb->chain);
q->task = current;
spin_unlock(&hb->lock);
Expand Down Expand Up @@ -1497,8 +1505,7 @@ static int unqueue_me(struct futex_q *q)
spin_unlock(lock_ptr);
goto retry;
}
WARN_ON(plist_node_empty(&q->list));
plist_del(&q->list, &q->list.plist);
__unqueue_futex(q);

BUG_ON(q->pi_state);

Expand All @@ -1518,8 +1525,7 @@ static int unqueue_me(struct futex_q *q)
static void unqueue_me_pi(struct futex_q *q)
__releases(q->lock_ptr)
{
WARN_ON(plist_node_empty(&q->list));
plist_del(&q->list, &q->list.plist);
__unqueue_futex(q);

BUG_ON(!q->pi_state);
free_pi_state(q->pi_state);
Expand Down Expand Up @@ -2156,7 +2162,7 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,
* We were woken prior to requeue by a timeout or a signal.
* Unqueue the futex_q and determine which it was.
*/
plist_del(&q->list, &q->list.plist);
plist_del(&q->list, &hb->chain);

/* Handle spurious wakeups gracefully */
ret = -EWOULDBLOCK;
Expand Down
Loading

0 comments on commit 9956121

Please sign in to comment.