diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-25 15:47:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-25 15:47:56 -0400 |
commit | 0b79dada976198cb1a4c043068e3b44d5cab2a5a (patch) | |
tree | fde938c698545a7c8764a2eac4304dee002bb281 | |
parent | 50be4917ee70218f59e04dec029121b97fb9cb3d (diff) | |
parent | 3f5087a2bae5d1ce10a3d698dec8f879a96f5419 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched-fixes
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched-fixes:
sched: fix share (re)distribution
softlockup: fix NOHZ wakeup
seqlock: livelock fix
-rw-r--r-- | include/linux/seqlock.h | 46 | ||||
-rw-r--r-- | kernel/sched.c | 47 | ||||
-rw-r--r-- | kernel/time/tick-sched.c | 1 |
3 files changed, 32 insertions, 62 deletions
diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h index 26e4925bc35b..632205ccc25d 100644 --- a/include/linux/seqlock.h +++ b/include/linux/seqlock.h | |||
@@ -85,23 +85,29 @@ static inline int write_tryseqlock(seqlock_t *sl) | |||
85 | /* Start of read calculation -- fetch last complete writer token */ | 85 | /* Start of read calculation -- fetch last complete writer token */ |
86 | static __always_inline unsigned read_seqbegin(const seqlock_t *sl) | 86 | static __always_inline unsigned read_seqbegin(const seqlock_t *sl) |
87 | { | 87 | { |
88 | unsigned ret = sl->sequence; | 88 | unsigned ret; |
89 | |||
90 | repeat: | ||
91 | ret = sl->sequence; | ||
89 | smp_rmb(); | 92 | smp_rmb(); |
93 | if (unlikely(ret & 1)) { | ||
94 | cpu_relax(); | ||
95 | goto repeat; | ||
96 | } | ||
97 | |||
90 | return ret; | 98 | return ret; |
91 | } | 99 | } |
92 | 100 | ||
93 | /* Test if reader processed invalid data. | 101 | /* |
94 | * If initial values is odd, | 102 | * Test if reader processed invalid data. |
95 | * then writer had already started when section was entered | 103 | * |
96 | * If sequence value changed | 104 | * If sequence value changed then writer changed data while in section. |
97 | * then writer changed data while in section | ||
98 | * | ||
99 | * Using xor saves one conditional branch. | ||
100 | */ | 105 | */ |
101 | static __always_inline int read_seqretry(const seqlock_t *sl, unsigned iv) | 106 | static __always_inline int read_seqretry(const seqlock_t *sl, unsigned start) |
102 | { | 107 | { |
103 | smp_rmb(); | 108 | smp_rmb(); |
104 | return (iv & 1) | (sl->sequence ^ iv); | 109 | |
110 | return (sl->sequence != start); | ||
105 | } | 111 | } |
106 | 112 | ||
107 | 113 | ||
@@ -122,20 +128,26 @@ typedef struct seqcount { | |||
122 | /* Start of read using pointer to a sequence counter only. */ | 128 | /* Start of read using pointer to a sequence counter only. */ |
123 | static inline unsigned read_seqcount_begin(const seqcount_t *s) | 129 | static inline unsigned read_seqcount_begin(const seqcount_t *s) |
124 | { | 130 | { |
125 | unsigned ret = s->sequence; | 131 | unsigned ret; |
132 | |||
133 | repeat: | ||
134 | ret = s->sequence; | ||
126 | smp_rmb(); | 135 | smp_rmb(); |
136 | if (unlikely(ret & 1)) { | ||
137 | cpu_relax(); | ||
138 | goto repeat; | ||
139 | } | ||
127 | return ret; | 140 | return ret; |
128 | } | 141 | } |
129 | 142 | ||
130 | /* Test if reader processed invalid data. | 143 | /* |
131 | * Equivalent to: iv is odd or sequence number has changed. | 144 | * Test if reader processed invalid data because sequence number has changed. |
132 | * (iv & 1) || (*s != iv) | ||
133 | * Using xor saves one conditional branch. | ||
134 | */ | 145 | */ |
135 | static inline int read_seqcount_retry(const seqcount_t *s, unsigned iv) | 146 | static inline int read_seqcount_retry(const seqcount_t *s, unsigned start) |
136 | { | 147 | { |
137 | smp_rmb(); | 148 | smp_rmb(); |
138 | return (iv & 1) | (s->sequence ^ iv); | 149 | |
150 | return s->sequence != start; | ||
139 | } | 151 | } |
140 | 152 | ||
141 | 153 | ||
diff --git a/kernel/sched.c b/kernel/sched.c index 09ca69b2c17d..9e19287f3359 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -1657,42 +1657,6 @@ void aggregate_group_weight(struct task_group *tg, struct sched_domain *sd) | |||
1657 | } | 1657 | } |
1658 | 1658 | ||
1659 | /* | 1659 | /* |
1660 | * Redistribute tg->shares amongst all tg->cfs_rq[]s. | ||
1661 | */ | ||
1662 | static void __aggregate_redistribute_shares(struct task_group *tg) | ||
1663 | { | ||
1664 | int i, max_cpu = smp_processor_id(); | ||
1665 | unsigned long rq_weight = 0; | ||
1666 | unsigned long shares, max_shares = 0, shares_rem = tg->shares; | ||
1667 | |||
1668 | for_each_possible_cpu(i) | ||
1669 | rq_weight += tg->cfs_rq[i]->load.weight; | ||
1670 | |||
1671 | for_each_possible_cpu(i) { | ||
1672 | /* | ||
1673 | * divide shares proportional to the rq_weights. | ||
1674 | */ | ||
1675 | shares = tg->shares * tg->cfs_rq[i]->load.weight; | ||
1676 | shares /= rq_weight + 1; | ||
1677 | |||
1678 | tg->cfs_rq[i]->shares = shares; | ||
1679 | |||
1680 | if (shares > max_shares) { | ||
1681 | max_shares = shares; | ||
1682 | max_cpu = i; | ||
1683 | } | ||
1684 | shares_rem -= shares; | ||
1685 | } | ||
1686 | |||
1687 | /* | ||
1688 | * Ensure it all adds up to tg->shares; we can loose a few | ||
1689 | * due to rounding down when computing the per-cpu shares. | ||
1690 | */ | ||
1691 | if (shares_rem) | ||
1692 | tg->cfs_rq[max_cpu]->shares += shares_rem; | ||
1693 | } | ||
1694 | |||
1695 | /* | ||
1696 | * Compute the weight of this group on the given cpus. | 1660 | * Compute the weight of this group on the given cpus. |
1697 | */ | 1661 | */ |
1698 | static | 1662 | static |
@@ -1701,18 +1665,11 @@ void aggregate_group_shares(struct task_group *tg, struct sched_domain *sd) | |||
1701 | unsigned long shares = 0; | 1665 | unsigned long shares = 0; |
1702 | int i; | 1666 | int i; |
1703 | 1667 | ||
1704 | again: | ||
1705 | for_each_cpu_mask(i, sd->span) | 1668 | for_each_cpu_mask(i, sd->span) |
1706 | shares += tg->cfs_rq[i]->shares; | 1669 | shares += tg->cfs_rq[i]->shares; |
1707 | 1670 | ||
1708 | /* | 1671 | if ((!shares && aggregate(tg, sd)->rq_weight) || shares > tg->shares) |
1709 | * When the span doesn't have any shares assigned, but does have | 1672 | shares = tg->shares; |
1710 | * tasks to run do a machine wide rebalance (should be rare). | ||
1711 | */ | ||
1712 | if (unlikely(!shares && aggregate(tg, sd)->rq_weight)) { | ||
1713 | __aggregate_redistribute_shares(tg); | ||
1714 | goto again; | ||
1715 | } | ||
1716 | 1673 | ||
1717 | aggregate(tg, sd)->shares = shares; | 1674 | aggregate(tg, sd)->shares = shares; |
1718 | } | 1675 | } |
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index d358d4e3a958..b854a895591e 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c | |||
@@ -393,6 +393,7 @@ void tick_nohz_restart_sched_tick(void) | |||
393 | sub_preempt_count(HARDIRQ_OFFSET); | 393 | sub_preempt_count(HARDIRQ_OFFSET); |
394 | } | 394 | } |
395 | 395 | ||
396 | touch_softlockup_watchdog(); | ||
396 | /* | 397 | /* |
397 | * Cancel the scheduled timer and restore the tick | 398 | * Cancel the scheduled timer and restore the tick |
398 | */ | 399 | */ |