fix lockups when a condvar signals while a task is being blocked

master
Daniel Kolesa 2017-03-22 20:01:21 +01:00
parent 66758fa1df
commit 1351ac14f6
3 changed files with 13 additions and 2 deletions

View File

@ -18,7 +18,8 @@ int main() {
spawn(sched, f, c, arr.slice(0, arr.size() / 2)); spawn(sched, f, c, arr.slice(0, arr.size() / 2));
spawn(sched, f, c, arr + (arr.size() / 2)); spawn(sched, f, c, arr + (arr.size() / 2));
int a = c.get(), b = c.get(); int a = c.get();
int b = c.get();
writefln("%s + %s = %s", a, b, a + b); writefln("%s + %s = %s", a, b, a + b);
}; };

View File

@ -6,6 +6,7 @@
#ifndef OSTD_CHANNEL_HH #ifndef OSTD_CHANNEL_HH
#define OSTD_CHANNEL_HH #define OSTD_CHANNEL_HH
#include <stdio.h>
#include <list> #include <list>
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>

View File

@ -328,6 +328,12 @@ private:
template<typename L> template<typename L>
void wait(L &l) noexcept { void wait(L &l) noexcept {
/* lock until the task has been added to the wait queue,
* that ensures that any notify/notify_any has to wait
* until after the task has fully blocked... we can't
* use unique_lock or lock_guard because they're scoped
*/
p_sched.p_lock.lock();
l.unlock(); l.unlock();
task *curr = task::current(); task *curr = task::current();
curr->waiting_on = this; curr->waiting_on = this;
@ -493,8 +499,8 @@ private:
task &c = *it; task &c = *it;
l.unlock(); l.unlock();
c(); c();
l.lock();
if (c.dead()) { if (c.dead()) {
l.lock();
p_running.erase(it); p_running.erase(it);
/* we're dead, notify all threads so they can be joined /* we're dead, notify all threads so they can be joined
* we check all three, saves the other threads some re-waiting * we check all three, saves the other threads some re-waiting
@ -507,6 +513,7 @@ private:
} }
} else if (!c.waiting_on) { } else if (!c.waiting_on) {
/* reschedule to the end of the queue */ /* reschedule to the end of the queue */
l.lock();
p_available.splice(p_available.cend(), p_running, it); p_available.splice(p_available.cend(), p_running, it);
l.unlock(); l.unlock();
p_cond.notify_one(); p_cond.notify_one();
@ -514,6 +521,8 @@ private:
p_waiting.splice(p_waiting.cbegin(), p_running, it); p_waiting.splice(p_waiting.cbegin(), p_running, it);
c.next_waiting = c.waiting_on->p_waiting; c.next_waiting = c.waiting_on->p_waiting;
c.waiting_on->p_waiting = &c; c.waiting_on->p_waiting = &c;
/* wait locks the mutex, so manually unlock it here */
p_lock.unlock();
} }
} }