[libgee/wip/issue/34] Guard GLib.Cond.wait/wait_until calls against spurious or stolen wakeups



commit 35226d93e729bb98825eea4ab388c4045b838834
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Sat Oct 5 17:12:25 2019 +0200

    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

 gee/lazy.vala    | 16 ++++++++++------
 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:


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]