/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2011 EfficiOS Inc.
* Copyright (C) 2011 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
*
* SPDX-License-Identifier: GPL-2.0-only
*/
#define _LGPL_SOURCE
+#include "futex.hpp"
+
+#include <common/common.hpp>
+
#include <limits.h>
#include <unistd.h>
#include <urcu.h>
#include <urcu/futex.h>
-#include <common/common.h>
-
-#include "futex.h"
-
/*
* This futex wait/wake scheme only works for N wakers / 1 waiters. Hence the
* "nto1" added to all function signature.
{
if (active) {
uatomic_set(futex, 1);
- if (futex_async(futex, FUTEX_WAKE,
- INT_MAX, NULL, NULL, 0) < 0) {
+ if (futex_async(futex, FUTEX_WAKE, INT_MAX, nullptr, nullptr, 0) < 0) {
PERROR("futex_async");
abort();
}
{
cmm_smp_mb();
- if (uatomic_read(futex) != -1)
- goto end;
- while (futex_async(futex, FUTEX_WAIT, -1, NULL, NULL, 0)) {
+ while (uatomic_read(futex) == -1) {
+ if (!futex_async(futex, FUTEX_WAIT, -1, nullptr, nullptr, 0)) {
+ /*
+ * Prior queued wakeups queued by unrelated code
+ * using the same address can cause futex wait to
+ * return 0 even through the futex value is still
+ * -1 (spurious wakeups). Check the value again
+ * in user-space to validate whether it really
+ * differs from -1.
+ */
+ continue;
+ }
switch (errno) {
- case EWOULDBLOCK:
+ case EAGAIN:
/* Value already changed. */
goto end;
case EINTR:
/* Retry if interrupted by signal. */
- break; /* Get out of switch. */
+ break; /* Get out of switch. Check again. */
default:
/* Unexpected error. */
PERROR("futex_async");
if (caa_unlikely(uatomic_read(futex) != -1))
goto end;
uatomic_set(futex, 0);
- if (futex_async(futex, FUTEX_WAKE, 1, NULL, NULL, 0) < 0) {
+ if (futex_async(futex, FUTEX_WAKE, 1, nullptr, nullptr, 0) < 0) {
PERROR("futex_async");
abort();
}