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 + (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);
};

View File

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

View File

@ -328,6 +328,12 @@ private:
template<typename L>
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();
task *curr = task::current();
curr->waiting_on = this;
@ -493,8 +499,8 @@ private:
task &c = *it;
l.unlock();
c();
l.lock();
if (c.dead()) {
l.lock();
p_running.erase(it);
/* we're dead, notify all threads so they can be joined
* we check all three, saves the other threads some re-waiting
@ -507,6 +513,7 @@ private:
}
} else if (!c.waiting_on) {
/* reschedule to the end of the queue */
l.lock();
p_available.splice(p_available.cend(), p_running, it);
l.unlock();
p_cond.notify_one();
@ -514,6 +521,8 @@ private:
p_waiting.splice(p_waiting.cbegin(), p_running, it);
c.next_waiting = c.waiting_on->p_waiting;
c.waiting_on->p_waiting = &c;
/* wait locks the mutex, so manually unlock it here */
p_lock.unlock();
}
}