diff options
author | Rico Tzschichholz <ricotz@ubuntu.com> | 2019-10-05 17:12:25 +0200 |
---|---|---|
committer | Rico Tzschichholz <ricotz@ubuntu.com> | 2019-10-05 17:15:26 +0200 |
commit | 35226d93e729bb98825eea4ab388c4045b838834 (patch) | |
tree | d4dbac682eac9006b64812da37fb6dc27085a032 | |
parent | 505698ad479085ed969b355c243fe457d07fea4c (diff) | |
download | libgee-35226d93e729bb98825eea4ab388c4045b838834.tar.gz |
Guard GLib.Cond.wait/wait_until calls against spurious or stolen wakeups
It is possible that a spurious or stolen wakeup could occur. For that
reason, waiting on a condition variable should always be in a loop,
based on an explicitly-checked predicate.
Fixes https://gitlab.gnome.org/GNOME/libgee/issues/34
-rw-r--r-- | gee/lazy.vala | 16 | ||||
-rw-r--r-- | gee/promise.vala | 20 |
2 files changed, 22 insertions, 14 deletions
diff --git a/gee/lazy.vala b/gee/lazy.vala index 5e7bc36..4e09e8b 100644 --- a/gee/lazy.vala +++ b/gee/lazy.vala @@ -93,7 +93,9 @@ public class Gee.Lazy<G> { _mutex.lock (); if (_lazy._func != null) { if (_state == State.EVAL) { - _eval.wait (_mutex); + while (_state == State.EVAL) { + _eval.wait (_mutex); + } _mutex.unlock (); } else { do_eval (); @@ -108,12 +110,14 @@ public class Gee.Lazy<G> { _mutex.lock (); if (_lazy._func != null) { if (_state == State.EVAL) { - bool res = _eval.wait_until (_mutex, end_time); - _mutex.unlock (); - if (!res) { - value = null; - return false; + while (_state == State.EVAL) { + if (!_eval.wait_until (_mutex, end_time)) { + value = null; + _mutex.unlock (); + return false; + } } + _mutex.unlock (); } else { do_eval (); } diff --git a/gee/promise.vala b/gee/promise.vala index 401014d..020138e 100644 --- a/gee/promise.vala +++ b/gee/promise.vala @@ -93,10 +93,11 @@ public class Gee.Promise<G> { _mutex.lock (); State state = _state; if (_state == State.INIT) { - _set.wait (_mutex); - state = _state; + while (_state == State.INIT) { + _set.wait (_mutex); + state = _state; + } } - assert (state != State.INIT); _mutex.unlock (); switch (state) { case State.ABANDON: @@ -114,14 +115,17 @@ public class Gee.Promise<G> { _mutex.lock (); State state = _state; if (state == State.INIT) { - _set.wait_until (_mutex, end_time); - state = _state; + while (_state == State.INIT) { + if (!_set.wait_until (_mutex, end_time)) { + value = null; + _mutex.unlock (); + return false; + } + state = _state; + } } _mutex.unlock (); switch (state) { - case State.INIT: - value = null; - return false; case State.ABANDON: throw new FutureError.ABANDON_PROMISE ("Promise has been abandon"); case State.EXCEPTION: |