• Re: A futex'd once_flag that is failable

    From Bonita Montero@3:633/10 to All on Thu Dec 11 15:44:59 2025
    Sorry, should go here.

    Am 11.12.2025 um 15:43 schrieb Bonita Montero:
    Niche, isn't it ?


    #pragma once
    #include <atomic>
    #include <concepts>

    template<typename Callable>
    ÿ ÿ requires requires( Callable callable ) { { callable() } -> std::same_as<void>; }
    ÿ ÿ ÿ ÿ || requires( Callable callable ) { { callable() } -> std::convertible_to<bool>; }
    void xcall_once( std::atomic_int &flag, Callable callable )
    {
    ÿ ÿ using namespace std;
    ÿ ÿ for( int ref = flag.load( memory_order_acquire ); )
    ÿ ÿ {
    ÿ ÿ ÿ ÿ if( ref > 0 )
    ÿ ÿ ÿ ÿ ÿ ÿ return;
    ÿ ÿ ÿ ÿ if( ref < 0 )
    ÿ ÿ ÿ ÿ {
    ÿ ÿ ÿ ÿ ÿ ÿ flag.wait( ref, memory_order_relaxed );
    ÿ ÿ ÿ ÿ ÿ ÿ ref = flag.load( memory_order_acquire );
    ÿ ÿ ÿ ÿ ÿ ÿ continue;
    ÿ ÿ ÿ ÿ }
    ÿ ÿ ÿ ÿ if( flag.compare_exchange_strong( ref, -1,
    memory_order_relaxed, memory_order_relaxed ) )
    ÿ ÿ ÿ ÿ ÿ ÿ break;
    ÿ ÿ }
    ÿ ÿ bool succ = true;
    ÿ ÿ if constexpr( requires( Callable callable ) { { callable() } -> same_as<void>; } )
    ÿ ÿ ÿ ÿ callable();
    ÿ ÿ else
    ÿ ÿ ÿ ÿ succ = (bool)callable();
    ÿ ÿ flag.store( (int)succ, memory_order_release );
    ÿ ÿ flag.notify_all();
    }



    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)
  • From Bonita Montero@3:633/10 to All on Thu Dec 11 19:54:53 2025
    This is the final code:

    #pragma once
    #include <concepts>
    #include <atomic>

    struct xonce_flag
    {
    ÿ ÿ xonce_flag() noexcept = default;
    private:
    ÿ ÿ friend bool xcall_once( xonce_flag &, std::invocable auto );
    ÿ ÿ std::atomic<signed char> m_flag = 0;
    };

    bool xcall_once( xonce_flag &xflag, std::invocable auto callable )
    {
    ÿ ÿ using namespace std;
    ÿ ÿ atomic<signed char> &flag = xflag.m_flag;
    ÿ ÿ for( signed char ref = flag.load( memory_order_acquire ); ; )
    ÿ ÿ ÿ ÿ if( ref > 0 )
    ÿ ÿ ÿ ÿ ÿ ÿ return true;
    ÿ ÿ ÿ ÿ else if( ref < 0 )
    ÿ ÿ ÿ ÿ {
    ÿ ÿ ÿ ÿ ÿ ÿ flag.wait( ref, memory_order_relaxed );
    ÿ ÿ ÿ ÿ ÿ ÿ ref = flag.load( memory_order_acquire );
    ÿ ÿ ÿ ÿ ÿ ÿ continue;
    ÿ ÿ ÿ ÿ }
    ÿ ÿ ÿ ÿ else if( flag.compare_exchange_strong( ref, -1,
    memory_order_relaxed, memory_order_acquire ) )
    ÿ ÿ ÿ ÿ ÿ ÿ break;
    ÿ ÿ bool succ = true;
    ÿ ÿ try
    ÿ ÿ {
    ÿ ÿ ÿ ÿ if constexpr( requires { (bool)callable(); } )
    ÿ ÿ ÿ ÿ ÿ ÿ succ = (bool)callable();
    ÿ ÿ ÿ ÿ else
    ÿ ÿ ÿ ÿ ÿ ÿ callable();
    ÿ ÿ }
    ÿ ÿ catch( ... )
    ÿ ÿ {
    ÿ ÿ ÿ ÿ flag.store( 0, memory_order_release );
    ÿ ÿ ÿ ÿ flag.notify_all();
    ÿ ÿ ÿ ÿ throw;
    ÿ ÿ }
    ÿ ÿ flag.store( (signed char)succ, memory_order_release );
    ÿ ÿ flag.notify_all();
    ÿ ÿ return succ;
    }


    --- PyGate Linux v1.5.2
    * Origin: Dragon's Lair, PyGate NNTP<>Fido Gate (3:633/10)