diff --git a/src/corelib/thread/qfutex_p.h b/src/corelib/thread/qfutex_p.h --- a/src/corelib/thread/qfutex_p.h +++ b/src/corelib/thread/qfutex_p.h @@ -41,6 +41,9 @@ #elif defined(Q_OS_LINUX) && !defined(QT_LINUXBASE) // use Linux mutexes everywhere except for LSB builds # include "qfutex_linux_p.h" +#elif defined(Q_OS_REDOX) +// Redox kernel implements the same futex syscall as Linux (SYS_FUTEX = 202) +# include "qfutex_redox_p.h" #elif defined(Q_OS_WIN) # include "qfutex_win_p.h" #else diff --git a/src/corelib/thread/qfutex_redox_p.h b/src/corelib/thread/qfutex_redox_p.h new file mode 100644 --- /dev/null +++ b/src/corelib/thread/qfutex_redox_p.h @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QFUTEX_REDOX_P_H +#define QFUTEX_REDOX_P_H + +#include +#include + +#include +#include +#include + +#define QT_ALWAYS_USE_FUTEX + +#ifndef __NR_futex +# define __NR_futex 202 +#endif + +QT_BEGIN_NAMESPACE + +namespace QtRedoxFutex { + +constexpr inline bool futexAvailable() { return true; } + +constexpr int RedoxFutexWait = 0; +constexpr int RedoxFutexWake = 1; + +inline long redox_syscall6(long nr, long a1, long a2, long a3, long a4, long a5, long a6) noexcept +{ + register long r10 __asm__("r10") = a4; + register long r8 __asm__("r8") = a5; + register long r9 __asm__("r9") = a6; + long ret; + __asm__ __volatile__( + "syscall" + : "=a"(ret) + : "a"(nr), "D"(a1), "S"(a2), "d"(a3), "r"(r10), "r"(r8), "r"(r9) + : "rcx", "r11", "memory" + ); + return ret; +} + +inline long _q_futex(int *addr, int op, int val, quintptr val2 = 0, + int *addr2 = nullptr, int val3 = 0) noexcept +{ + QtTsan::futexRelease(addr, addr2); + long result = redox_syscall6(__NR_futex, (long)addr, (long)op, (long)val, (long)val2, (long)addr2, (long)val3); + QtTsan::futexAcquire(addr, addr2); + return result; +} + +template int *addr(T *ptr) +{ + int *int_addr = reinterpret_cast(ptr); +#if Q_BYTE_ORDER == Q_BIG_ENDIAN + if (sizeof(T) > sizeof(int)) + int_addr++; +#endif + return int_addr; +} + +template +inline void futexWait(Atomic &futex, typename Atomic::Type expectedValue) +{ + _q_futex(addr(&futex), RedoxFutexWait, qintptr(expectedValue)); +} + +template +inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, QDeadlineTimer deadline) +{ + auto timeout = deadline.deadline().time_since_epoch(); + struct timespec ts; + ts.tv_sec = timeout.count() < 0 ? 0 : static_cast(std::chrono::duration_cast(timeout).count()); + auto ns_remainder = timeout - std::chrono::seconds(ts.tv_sec); + ts.tv_nsec = static_cast(std::chrono::duration_cast(ns_remainder).count()); + long r = _q_futex(addr(&futex), RedoxFutexWait, qintptr(expectedValue), quintptr(&ts), + nullptr, 0); + return r == 0 || errno != ETIMEDOUT; +} + +template inline void futexWakeOne(Atomic &futex) +{ + _q_futex(addr(&futex), RedoxFutexWake, 1); +} + +template inline void futexWakeAll(Atomic &futex) +{ + _q_futex(addr(&futex), RedoxFutexWake, INT_MAX); +} + +} // namespace QtRedoxFutex + +namespace QtFutex = QtRedoxFutex; + +QT_END_NAMESPACE + +#endif // QFUTEX_REDOX_P_H diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -26,6 +26,6 @@ protected: static constexpr bool FutexAlwaysAvailable = -#if defined(Q_OS_FREEBSD) || defined(Q_OS_LINUX) || defined(Q_OS_WIN) // these platforms use futex +#if defined(Q_OS_FREEBSD) || defined(Q_OS_LINUX) || defined(Q_OS_WIN) || defined(Q_OS_REDOX) // these platforms use futex true #else false