Fix //aos/common:event

I discovered while using ipc_comparison that it didn't properly handle
spurious wakeups. We don't use it very widely, so it's not surprising
that this bug went unnoticed.

Change-Id: I6675fa2f54ce185d0c67965c2a780ad550978133
diff --git a/aos/common/event.cc b/aos/common/event.cc
index ae32d39..af9c9c5 100644
--- a/aos/common/event.cc
+++ b/aos/common/event.cc
@@ -11,25 +11,28 @@
 }
 
 void Event::Wait() {
-  int ret;
-  do {
-    ret = futex_wait(&impl_);
-  } while (ret == 1);
-  if (ret == 0) return;
-  CHECK_EQ(-1, ret);
-  PLOG(FATAL, "futex_wait(%p) failed", &impl_);
+  while (__atomic_load_n(&impl_, __ATOMIC_SEQ_CST) == 0) {
+    const int ret = futex_wait(&impl_);
+    if (ret != 0) {
+      CHECK_EQ(-1, ret);
+      PLOG(FATAL, "futex_wait(%p) failed", &impl_);
+    }
+  }
 }
 
 bool Event::WaitTimeout(const ::aos::time::Time &timeout) {
   const auto timeout_timespec = timeout.ToTimespec();
-  int ret;
-  do {
-    ret = futex_wait_timeout(&impl_, &timeout_timespec);
-  } while (ret == 1);
-  if (ret == 0) return true;
-  if (ret == 2) return false;
-  CHECK_EQ(-1, ret);
-  PLOG(FATAL, "futex_wait(%p) failed", &impl_);
+  while (true) {
+    if (__atomic_load_n(&impl_, __ATOMIC_SEQ_CST) != 0) {
+      return true;
+    }
+    const int ret = futex_wait_timeout(&impl_, &timeout_timespec);
+    if (ret != 0) {
+      if (ret == 2) return false;
+      CHECK_EQ(-1, ret);
+      PLOG(FATAL, "futex_wait(%p) failed", &impl_);
+    }
+  }
 }
 
 // We're not going to expose the number woken because that's not easily portable
diff --git a/aos/linux_code/ipc_lib/aos_sync.cc b/aos/linux_code/ipc_lib/aos_sync.cc
index 92eb1a1..b0b560e 100644
--- a/aos/linux_code/ipc_lib/aos_sync.cc
+++ b/aos/linux_code/ipc_lib/aos_sync.cc
@@ -954,9 +954,6 @@
 
 int futex_wait_timeout(aos_futex *m, const struct timespec *timeout) {
   RunObservers run_observers(m, false);
-  if (__atomic_load_n(m, __ATOMIC_SEQ_CST) != 0) {
-    return 0;
-  }
   const int ret = sys_futex_wait(FUTEX_WAIT, m, 0, timeout);
   if (ret != 0) {
     if (ret == -EINTR) {
diff --git a/aos/linux_code/ipc_lib/aos_sync.h b/aos/linux_code/ipc_lib/aos_sync.h
index 3495e73..5b7a865 100644
--- a/aos/linux_code/ipc_lib/aos_sync.h
+++ b/aos/linux_code/ipc_lib/aos_sync.h
@@ -111,9 +111,10 @@
 // example messages are available to read on a queue), use the condition_
 // functions or there will be race conditions.
 
-// Wait for the futex to be set. Will return immediately if it's already set.
+// Wait for the futex to be set. Will return immediately if it's already set
+// (after a syscall).
 // Returns 0 if successful or it was already set, 1 if interrupted by a signal,
-// or -1 with an error in errno.
+// or -1 with an error in errno. Can return 0 spuriously.
 int futex_wait(aos_futex *m) __attribute__((warn_unused_result));
 // The same as futex_wait except returns 2 if it times out.
 int futex_wait_timeout(aos_futex *m, const struct timespec *timeout)