diff options
Diffstat (limited to 'kernel/async.c')
-rw-r--r-- | kernel/async.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/kernel/async.c b/kernel/async.c index a1d585c351d6..6f34904a0b53 100644 --- a/kernel/async.c +++ b/kernel/async.c | |||
@@ -86,18 +86,27 @@ static atomic_t entry_count; | |||
86 | */ | 86 | */ |
87 | static async_cookie_t __lowest_in_progress(struct async_domain *running) | 87 | static async_cookie_t __lowest_in_progress(struct async_domain *running) |
88 | { | 88 | { |
89 | async_cookie_t first_running = next_cookie; /* infinity value */ | ||
90 | async_cookie_t first_pending = next_cookie; /* ditto */ | ||
89 | struct async_entry *entry; | 91 | struct async_entry *entry; |
90 | 92 | ||
93 | /* | ||
94 | * Both running and pending lists are sorted but not disjoint. | ||
95 | * Take the first cookies from both and return the min. | ||
96 | */ | ||
91 | if (!list_empty(&running->domain)) { | 97 | if (!list_empty(&running->domain)) { |
92 | entry = list_first_entry(&running->domain, typeof(*entry), list); | 98 | entry = list_first_entry(&running->domain, typeof(*entry), list); |
93 | return entry->cookie; | 99 | first_running = entry->cookie; |
94 | } | 100 | } |
95 | 101 | ||
96 | list_for_each_entry(entry, &async_pending, list) | 102 | list_for_each_entry(entry, &async_pending, list) { |
97 | if (entry->running == running) | 103 | if (entry->running == running) { |
98 | return entry->cookie; | 104 | first_pending = entry->cookie; |
105 | break; | ||
106 | } | ||
107 | } | ||
99 | 108 | ||
100 | return next_cookie; /* "infinity" value */ | 109 | return min(first_running, first_pending); |
101 | } | 110 | } |
102 | 111 | ||
103 | static async_cookie_t lowest_in_progress(struct async_domain *running) | 112 | static async_cookie_t lowest_in_progress(struct async_domain *running) |
@@ -118,13 +127,17 @@ static void async_run_entry_fn(struct work_struct *work) | |||
118 | { | 127 | { |
119 | struct async_entry *entry = | 128 | struct async_entry *entry = |
120 | container_of(work, struct async_entry, work); | 129 | container_of(work, struct async_entry, work); |
130 | struct async_entry *pos; | ||
121 | unsigned long flags; | 131 | unsigned long flags; |
122 | ktime_t uninitialized_var(calltime), delta, rettime; | 132 | ktime_t uninitialized_var(calltime), delta, rettime; |
123 | struct async_domain *running = entry->running; | 133 | struct async_domain *running = entry->running; |
124 | 134 | ||
125 | /* 1) move self to the running queue */ | 135 | /* 1) move self to the running queue, make sure it stays sorted */ |
126 | spin_lock_irqsave(&async_lock, flags); | 136 | spin_lock_irqsave(&async_lock, flags); |
127 | list_move_tail(&entry->list, &running->domain); | 137 | list_for_each_entry_reverse(pos, &running->domain, list) |
138 | if (entry->cookie < pos->cookie) | ||
139 | break; | ||
140 | list_move_tail(&entry->list, &pos->list); | ||
128 | spin_unlock_irqrestore(&async_lock, flags); | 141 | spin_unlock_irqrestore(&async_lock, flags); |
129 | 142 | ||
130 | /* 2) run (and print duration) */ | 143 | /* 2) run (and print duration) */ |