fix issues with coroutine scheduler threads locking up
This commit is contained in:
parent
307123fd35
commit
c1a1c4a1ac
|
@ -257,17 +257,11 @@ private:
|
||||||
func();
|
func();
|
||||||
}
|
}
|
||||||
|
|
||||||
void yield(basic_coroutine_scheduler &sched) {
|
void yield() {
|
||||||
{
|
/* we'll yield back to the thread we were scheduled to, which
|
||||||
std::lock_guard<std::mutex> l{sched.p_lock};
|
* will appropriately notify one or all other waiting threads
|
||||||
sched.p_available.splice(
|
* so we either get re-scheduled or the whole scheduler dies
|
||||||
sched.p_available.cend(), sched.p_running, pos
|
*/
|
||||||
);
|
|
||||||
}
|
|
||||||
yield_raw();
|
|
||||||
}
|
|
||||||
|
|
||||||
void yield_raw() {
|
|
||||||
typename coro::yield_type{func}();
|
typename coro::yield_type{func}();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -299,7 +293,7 @@ private:
|
||||||
l.unlock();
|
l.unlock();
|
||||||
task *curr = task::current();
|
task *curr = task::current();
|
||||||
p_sched.wait(this, p_waiting, curr);
|
p_sched.wait(this, p_waiting, curr);
|
||||||
curr->yield_raw();
|
curr->yield();
|
||||||
l.lock();
|
l.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +372,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
void yield() {
|
void yield() {
|
||||||
task::current()->yield(*this);
|
task::current()->yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -403,10 +397,8 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void destroy() {
|
void destroy() {
|
||||||
p_cond.notify_all();
|
|
||||||
for (auto &tid: p_thrs) {
|
for (auto &tid: p_thrs) {
|
||||||
tid.join();
|
tid.join();
|
||||||
p_cond.notify_all();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -428,7 +420,7 @@ private:
|
||||||
wl = wl->next_waiting;
|
wl = wl->next_waiting;
|
||||||
l.unlock();
|
l.unlock();
|
||||||
p_cond.notify_one();
|
p_cond.notify_one();
|
||||||
task::current()->yield(*this);
|
task::current()->yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
void notify_all(task *&wl) {
|
void notify_all(task *&wl) {
|
||||||
|
@ -443,7 +435,7 @@ private:
|
||||||
l.lock();
|
l.lock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
task::current()->yield(*this);
|
task::current()->yield();
|
||||||
}
|
}
|
||||||
|
|
||||||
void thread_run() {
|
void thread_run() {
|
||||||
|
@ -470,8 +462,21 @@ private:
|
||||||
l.lock();
|
l.lock();
|
||||||
if (c.dead()) {
|
if (c.dead()) {
|
||||||
p_running.erase(it);
|
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
|
||||||
|
* when a task or tasks are already running, and those that do
|
||||||
|
* will do the final notify by themselves
|
||||||
|
*/
|
||||||
|
if (p_available.empty() && p_waiting.empty() && p_running.empty()) {
|
||||||
|
l.unlock();
|
||||||
|
p_cond.notify_all();
|
||||||
|
}
|
||||||
|
} else if (!c.waiting_on) {
|
||||||
|
/* reschedule to the end of the queue */
|
||||||
|
p_available.splice(p_available.cend(), p_running, it);
|
||||||
|
l.unlock();
|
||||||
|
p_cond.notify_one();
|
||||||
}
|
}
|
||||||
l.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::condition_variable p_cond;
|
std::condition_variable p_cond;
|
||||||
|
|
Loading…
Reference in a new issue