Changeset 5e0b6657 for libcfa/src


Ignore:
Timestamp:
Dec 8, 2025, 11:29:33 AM (2 months ago)
Author:
Michael Brooks <mlbrooks@…>
Branches:
master, stuck-waitfor-destruct
Children:
79ba50c
Parents:
8f448e0 (diff), 79ec8c3 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge remote-tracking branch 'refs/remotes/origin/master'

Location:
libcfa/src
Files:
15 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/bits/defs.hfa

    r8f448e0 r5e0b6657  
    1313// Created On       : Thu Nov  9 13:24:10 2017
    1414// Last Modified By : Peter A. Buhr
    15 // Last Modified On : Sat Oct 24 10:53:15 2020
    16 // Update Count     : 21
     15// Last Modified On : Mon Oct 27 22:40:05 2025
     16// Update Count     : 23
    1717//
    1818
     
    2525#define unlikely(x) __builtin_expect(!!(x), 0)
    2626
    27 typedef void (*fptr_t)();
     27typedef void (* fptr_t)();
    2828typedef int_fast16_t __lock_size_t;
    2929
  • libcfa/src/bits/weakso_locks.cfa

    r8f448e0 r5e0b6657  
    2828void on_wakeup( blocking_lock &, size_t ) {}
    2929size_t wait_count( blocking_lock & ) { return 0; }
    30 bool register_select( blocking_lock & this, select_node & node ) { return false; }
    31 bool unregister_select( blocking_lock & this, select_node & node ) { return false; }
    32 bool on_selected( blocking_lock & this, select_node & node ) { return true; }
     30bool register_select$( blocking_lock & this, select_node & node ) { return false; }
     31bool unregister_select$( blocking_lock & this, select_node & node ) { return false; }
     32bool on_selected$( blocking_lock & this, select_node & node ) { return true; }
    3333
  • libcfa/src/bits/weakso_locks.hfa

    r8f448e0 r5e0b6657  
    5959void on_wakeup( blocking_lock & this, size_t ) OPTIONAL_THREAD;
    6060size_t wait_count( blocking_lock & this ) OPTIONAL_THREAD;
    61 bool register_select( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
    62 bool unregister_select( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
    63 bool on_selected( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
     61bool register_select$( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
     62bool unregister_select$( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
     63bool on_selected$( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
    6464blocking_lock __CFA_select_get_type( blocking_lock this ) OPTIONAL_THREAD;
    6565
     
    7878static inline void   on_wakeup( multiple_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    7979static inline void   on_notify( multiple_acquisition_lock & this, struct thread$ * t ){ on_notify( (blocking_lock &)this, t ); }
    80 static inline bool   register_select( multiple_acquisition_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }
    81 static inline bool   unregister_select( multiple_acquisition_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }
    82 static inline bool   on_selected( multiple_acquisition_lock & this, select_node & node ) { return on_selected( (blocking_lock &)this, node ); }
     80static inline bool   register_select$( multiple_acquisition_lock & this, select_node & node ) { return register_select$( (blocking_lock &)this, node ); }
     81static inline bool   unregister_select$( multiple_acquisition_lock & this, select_node & node ) { return unregister_select$( (blocking_lock &)this, node ); }
     82static inline bool   on_selected$( multiple_acquisition_lock & this, select_node & node ) { return on_selected$( (blocking_lock &)this, node ); }
    8383multiple_acquisition_lock __CFA_select_get_type( multiple_acquisition_lock this );
  • libcfa/src/concurrency/barrier.hfa

    r8f448e0 r5e0b6657  
    1111// Created On       : Sun Nov 10 08:07:35 2024
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Thu Apr 24 22:41:11 2025
    14 // Update Count     : 12
     13// Last Modified On : Fri Oct 31 09:22:14 2025
     14// Update Count     : 69
    1515//
    1616
    1717#pragma once
    1818
     19#include <locks.hfa>
    1920#include <monitor.hfa>
    2021
    2122// Plan 9 inheritance does not work with monitors. Two monitor locks are created.
    2223
     24typedef void (* barrier_fptr_t)( ... );                                 // like C++, () => void and ... => C ()
     25
    2326monitor barrier {
    24         unsigned int group, arrivals;                                           // group size, arrival counter
    25         condition c;                                                                            // wait for group to form
     27        size_t group$, arrivals$;                                                       // group size, arrival counter (backward)
     28        condition c$;                                                                           // wait for group to form
     29        barrier_fptr_t callback$;                                                       // global callback
     30        void * arg$;                                                                            // global callback argument
    2631};
    2732
    28 static inline void ?{}( barrier & b, unsigned int group ) {
    29         b.group = b.arrivals = group;                                           // arrivals count backward
     33static inline void ?{}( barrier & b, ssize_t group, barrier_fptr_t callback, void * arg ) with ( b ) {
     34        [group$, arrivals$] = group;
     35        [callback$, arg$] = [callback, arg];
    3036}
    3137
    32 // Returns a value indicating the reverse order the threads arrived, i.e. last thread returns 0 (and does not block)
    33 // hook is an optional hook that is called by the Gth thread before unblocking the other threads.
    34 static inline unsigned int block( barrier & mutex b, fptr_t hook = (fptr_t)0 ) with( b ) {
    35         arrivals -= 1;                                                                          // prefix decrement so last is 0 not 1
    36         unsigned arrived = b.arrivals;                                          // note arrival order
    37         if ( arrivals != 0 ) {                                                          // wait for group to form
    38                 wait( b.c );
     38static inline void ?{}( barrier & b, ssize_t group ) { (b){ group, 0p, 0p }; }  // call base constructor
     39static inline ssize_t waiters( barrier & b ) with( b ) { return group$ - arrivals$; }
     40static inline ssize_t total( barrier & b ) with( b ) { return group$; }
     41
     42// Returns a value indicating the reverse order the threads arrived, i.e., the Gth thread returns 0 (and does not
     43// block).  olock is an optional mutex lock held by the called and atomically released and block. callback is an
     44// optional function that is called by the Gth thread before unblocking the other threads. arg is an optional (void *)
     45// argument passed to the callback.
     46
     47// Barrier is a monitor => implicit mutual exclusion.
     48static inline ssize_t block( barrier & mutex b, owner_lock & olock, barrier_fptr_t callback, void * arg ) with( b ) {
     49        arrivals$ -= 1;                                                                         // prefix decrement so last is 0 not 1
     50        typeof( arrivals$ ) arrived = arrivals$;                        // note arrival order
     51        if ( arrivals$ != 0 ) {                                                         // wait for group to form
     52                if ( &olock != 0p ) unlock( olock );                    // if lock specified, release it
     53                wait( c$ );
     54                // DO NOT REACQUIRE LOCK TO ALLOW BARGING PREVENTION
    3955        } else {                                                                                        // group formed
    40                 if ( hook ) hook();                                                             // safe to call
    41                 signal_all( c );                                                                // unblock group
    42                 arrivals = group;                                                               // reset
     56                if ( callback ) callback( arg );                                // if callback specified, safe to call with argument
     57                else if ( callback$ ) callback$( arg$ );                // if callback specified, safe to call with argument
     58                signal_all( c$ );                                                               // unblock group
     59                arrivals$ = group$;                                                             // reset
    4360        } // if
    4461        return arrived;                                                                         // return arrival order
    4562}
     63
     64static inline ssize_t block( barrier & b ) { return block( b, *0p, 0p, 0p ); }
     65static inline ssize_t block( barrier & b, owner_lock & olock ) { return block( b, olock, 0p, 0p ); }
     66static inline ssize_t block( barrier & b, barrier_fptr_t callback ) { return block( b, *0p, callback, 0p ); }
     67static inline ssize_t block( barrier & b, barrier_fptr_t callback, void * arg ) { return block( b, *0p, callback, arg ); }
     68static inline ssize_t block( barrier & b, owner_lock & olock, barrier_fptr_t callback ) { return block( b, olock, callback, 0p ); }
  • libcfa/src/concurrency/channel.hfa

    r8f448e0 r5e0b6657  
    411411        }
    412412
    413         bool register_select( chan_read(T) & this, select_node & node ) with(*this.chan, this) {
     413        bool register_select$( chan_read(T) & this, select_node & node ) with(*this.chan, this) {
    414414            lock( mutex_lock );
    415415            node.extra = ret; // set .extra so that if it == 0p later in on_selected it is due to channel close
     
    476476            return true;
    477477        }
    478         bool unregister_select( chan_read(T) & this, select_node & node ) { return unregister_chan( *this.chan, node ); }
    479         bool on_selected( chan_read(T) & this, select_node & node ) with(this) {
     478        bool unregister_select$( chan_read(T) & this, select_node & node ) { return unregister_chan( *this.chan, node ); }
     479        bool on_selected$( chan_read(T) & this, select_node & node ) with(this) {
    480480            if ( unlikely(node.extra == 0p) ) {
    481481                if ( ! exception_in_flight() ) __closed_remove( *chan, *ret ); // check if woken up due to closed channel
     
    491491
    492492        chan_read_no_ret(T) remove( channel(T) & chan ) { chan_read_no_ret(T) c_read{ chan }; return c_read; }
    493         bool register_select( chan_read_no_ret(T) & this, select_node & node ) {
     493        bool register_select$( chan_read_no_ret(T) & this, select_node & node ) {
    494494            this.c_read.ret = &this.retval;
    495             return register_select( this.c_read, node );
    496         }
    497         bool unregister_select( chan_read_no_ret(T) & this, select_node & node ) { return unregister_select( this.c_read, node ); }
    498         bool on_selected( chan_read_no_ret(T) & this, select_node & node ) { return on_selected( this.c_read, node ); }
     495            return register_select$( this.c_read, node );
     496        }
     497        bool unregister_select$( chan_read_no_ret(T) & this, select_node & node ) { return unregister_select$( this.c_read, node ); }
     498        bool on_selected$( chan_read_no_ret(T) & this, select_node & node ) { return on_selected$( this.c_read, node ); }
    499499
    500500        void ?{}( chan_write(T) & cw, channel(T) * chan, T elem ) {
     
    511511        }
    512512
    513         bool register_select( chan_write(T) & this, select_node & node ) with(*this.chan, this) {
     513        bool register_select$( chan_write(T) & this, select_node & node ) with(*this.chan, this) {
    514514            lock( mutex_lock );
    515515            node.extra = &elem; // set .extra so that if it == 0p later in on_selected it is due to channel close
     
    577577                return true;
    578578        }
    579         bool unregister_select( chan_write(T) & this, select_node & node ) { return unregister_chan( *this.chan, node ); }
    580 
    581         bool on_selected( chan_write(T) & this, select_node & node ) with(this) {
     579        bool unregister_select$( chan_write(T) & this, select_node & node ) { return unregister_chan( *this.chan, node ); }
     580
     581        bool on_selected$( chan_write(T) & this, select_node & node ) with(this) {
    582582                if ( unlikely(node.extra == 0p) ) {
    583583                        if ( ! exception_in_flight() ) __closed_insert( *chan, elem ); // check if woken up due to closed channel
  • libcfa/src/concurrency/future.hfa

    r8f448e0 r5e0b6657  
    77// concurrency/future.hfa --
    88//
    9 // Author           : Thierry Delisle & Peiran Hong & Colby Parsons
     9// Author           : Thierry Delisle & Peiran Hong & Colby Parsons & Peter Buhr
    1010// Created On       : Wed Jan 06 17:33:18 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 23 22:41:10 2025
    13 // Update Count     : 22
     12// Last Modified On : Mon Nov 24 16:08:52 2025
     13// Update Count     : 222
    1414//
    1515
     
    2121#include "locks.hfa"
    2222
    23 //----------------------------------------------------------------------------
    24 // future
    25 // I don't use future_t here as I need to use a lock for this future since it supports multiple consumers.
    26 // future_t is lockfree and uses atomics which aren't needed given we use locks here
     23//--------------------------------------------------------------------------------------------------------
     24// future does not use future_t as it needs a lock to support multiple consumers.  future_t is lockfree
     25// and uses atomics which are not needed.
     26//--------------------------------------------------------------------------------------------------------
     27
    2728forall( T ) {
    28         enum { FUTURE_EMPTY = 0, FUTURE_FULFILLED = 1 };
     29        // PRIVATE
     30
     31        struct future_node$ {
     32                inline select_node;
     33                T * my_result;
     34        };
     35
     36        static inline {
     37                // memcpy wrapper to help copy values
     38                void copy_T$( T & to, T & from ) { memcpy( (void *)&to, (void *)&from, sizeof(T) ); }
     39        } // distribution
     40
     41        enum { FUTURE_EMPTY$ = 0, FUTURE_FULFILLED$ = 1 };
     42
     43        // PUBLIC
    2944
    3045        struct future {
     
    3247                T result;
    3348                exception_t * except;
     49                futex_mutex lock;
    3450                dlist( select_node ) waiters;
    35                 futex_mutex lock;
    3651        };
    37         __CFA_SELECT_GET_TYPE( future(T) );
    38 
    39         struct future_node {
    40                 inline select_node;
    41                 T * my_result;
    42         };
    43 
    44         static inline {
    45 
    46                 void ?{}( future_node(T) & this, thread$ * blocked_thread, T * my_result ) {
    47                         ((select_node &)this){ blocked_thread };
    48                         this.my_result = my_result;
    49                 }
    50 
    51                 void ?{}( future(T) & this ) {
    52                         this.waiters{};
    53                         this.except = 0p;
    54                         this.state = FUTURE_EMPTY;
    55                         this.lock{};
    56                 }
    57 
    58                 void ^?{}( future(T) & this ) {
    59                         free( this.except );
    60                 }
    61 
    62                 // Reset future back to original state
    63                 void reset( future(T) & this ) with(this) {
    64                         lock( lock );
    65                         if ( ! isEmpty( waiters ) )
    66                                 abort("Attempting to reset a future with blocked waiters");
    67                         state = FUTURE_EMPTY;
     52        __CFA_SELECT_GET_TYPE( future(T) );                                     // magic
     53
     54        static inline {
     55                // PRIVATE
     56
     57                bool register_select$( future(T) & fut, select_node & s ) with( fut ) { // for waituntil statement
     58                        lock( lock );
     59
     60                        // check if we can complete operation. If so race to establish winner in special OR case
     61                        if ( !s.park_counter && state != FUTURE_EMPTY$ ) {
     62                                if ( !__make_select_node_available( s ) ) { // we didn't win the race so give up on registering
     63                                        unlock( lock );
     64                                        return false;
     65                                }
     66                        }
     67
     68                        // future not ready -> insert select node and return
     69                  if ( state == FUTURE_EMPTY$ ) {
     70                                insert_last( waiters, s );
     71                                unlock( lock );
     72                                return false;
     73                        }
     74
     75                        __make_select_node_available( s );
     76                        unlock( lock );
     77                        return true;
     78                }
     79
     80                bool unregister_select$( future(T) & fut, select_node & s ) with( fut ) { // for waituntil statement
     81                  if ( ! isListed( s ) ) return false;
     82                        lock( lock );
     83                        if ( isListed( s ) ) remove( s );
     84                        unlock( lock );
     85                        return false;
     86                }
     87
     88                bool on_selected$( future(T) &, select_node & ) { return true; } // for waituntil statement
     89
     90                // PUBLIC
     91
     92                // General
     93
     94                void ?{}( future_node$(T) & fut, thread$ * blocked_thread, T * my_result ) {
     95                        ((select_node &)fut){ blocked_thread };
     96                        fut.my_result = my_result;
     97                }
     98
     99                void ?{}( future(T) & fut ) with( fut ) {
     100                        except = 0p;
     101                        state = FUTURE_EMPTY$;
     102                }
     103
     104                void ^?{}( future(T) & fut ) with( fut ) {
    68105                        free( except );
    69                         except = 0p;
    70                         unlock( lock );
    71                 }
    72 
    73                 // check if the future is available
    74                 // currently no mutual exclusion because I can't see when you need this call to be synchronous or protected
    75                 bool available( future(T) & this ) { return __atomic_load_n( &this.state, __ATOMIC_RELAXED ); }
    76 
    77 
    78                 // memcpy wrapper to help copy values
    79                 void copy_T( T & from, T & to ) {
    80                         memcpy((void *)&to, (void *)&from, sizeof(T));
    81                 }
    82 
    83                 bool fulfil$( future(T) & this ) with(this) {   // helper
    84                         bool ret_val = ! isEmpty( waiters );
    85                         state = FUTURE_FULFILLED;
    86                         while ( ! isEmpty( waiters ) ) {
    87                                 if ( !__handle_waituntil_OR( waiters ) ) // handle special waituntil OR case
    88                                         break; // if handle_OR returns false then waiters is empty so break
    89                                 select_node &s = remove_first( waiters );
    90 
    91                                 if ( s.clause_status == 0p )                    // poke in result so that woken threads do not need to reacquire any locks
    92                                         copy_T( result, *(((future_node(T) &)s).my_result) );
    93 
    94                                 wake_one( waiters, s );
    95                         }
    96                         unlock( lock );
    97                         return ret_val;
    98                 }
    99 
    100                 // Fulfil the future, returns whether or not someone was unblocked
    101                 bool fulfil( future(T) & this, T val ) with(this) {
    102                         lock( lock );
    103                         if ( state != FUTURE_EMPTY )
    104                                 abort("Attempting to fulfil a future that has already been fulfilled");
    105 
    106                         copy_T( val, result );
    107                         return fulfil$( this );
    108                 }
    109 
    110                 bool ?()( future(T) & this, T val ) {                   // alternate interface
    111                         return fulfil( this, val );
    112                 }
    113 
    114                 // Load an exception to the future, returns whether or not someone was unblocked
    115                 bool fulfil( future(T) & this, exception_t * ex ) with(this) {
    116                         lock( lock );
    117                         if ( state != FUTURE_EMPTY )
    118                                 abort("Attempting to fulfil a future that has already been fulfilled");
    119 
    120                         except = ( exception_t * ) malloc( ex->virtual_table->size );
    121                         ex->virtual_table->copy( except, ex );
    122                         return fulfil$( this );
    123                 }
    124 
    125                 bool ?()( future(T) & this, exception_t * ex ) { // alternate interface
    126                         return fulfil( this, ex );
    127                 }
    128 
    129                 // Wait for the future to be fulfilled
    130                 // Also return whether the thread had to block or not
    131                 [T, bool] get( future(T) & this ) with( this ) {
     106                }
     107
     108                // Used by Client
     109
     110                // PRIVATE
     111
     112                // Return a value/exception from the future.
     113                T get$( future(T) & fut ) with( fut ) {                 // helper
    132114                        void exceptCheck() {                                            // helper
    133115                                if ( except ) {
     
    138120                                }
    139121                        }
    140 
    141                         lock( lock );
    142122                        T ret_val;
    143                         if ( state == FUTURE_FULFILLED ) {
     123
     124                        // LOCK ACQUIRED IN PUBLIC get
     125                        if ( state == FUTURE_FULFILLED$ ) {
    144126                                exceptCheck();
    145                                 copy_T( result, ret_val );
     127                                copy_T$( ret_val, result );
    146128                                unlock( lock );
    147                                 return [ret_val, false];
    148                         }
    149 
    150                         future_node(T) node = { active_thread(), &ret_val };
     129                                return ret_val;
     130                        }
     131
     132                        future_node$(T) node = { active_thread(), &ret_val };
    151133                        insert_last( waiters, ((select_node &)node) );
    152134                        unlock( lock );
    153135                        park( );
    154136                        exceptCheck();
    155 
    156                         return [ret_val, true];
    157                 }
    158 
    159                 // Wait for the future to be fulfilled
    160                 T get( future(T) & this ) {
    161                         [T, bool] tt;
    162                         tt = get(this);
    163                         return tt.0;
    164                 }
    165 
    166                 T ?()( future(T) & this ) {                                             // alternate interface
    167                         return get( this );
    168                 }
    169 
    170                 // Gets value if it is available and returns [ val, true ]
    171                 // otherwise returns [ default_val, false]
    172                 // will not block
    173                 [T, bool] try_get( future(T) & this ) with(this) {
     137                        return ret_val;
     138                }
     139
     140                // PUBLIC
     141
     142                bool available( future( T ) & fut ) { return __atomic_load_n( &fut.state, __ATOMIC_RELAXED ); } // future result available ?
     143
     144                // Return a value/exception from the future.
     145                [T, bool] get( future(T) & fut ) with( fut ) {
     146                        lock( lock );
     147                        bool ret = state == FUTURE_EMPTY$;
     148                        return [ get$( fut ), ret ];
     149                }
     150
     151                T get( future(T) & fut ) with( fut ) {
     152                        lock( lock );
     153                        return get$( fut );
     154                }
     155                T ?()( future(T) & fut ) { return get( fut ); } // alternate interface
     156
     157                // Non-blocking get: true => return defined value, false => value return undefined.
     158                [T, bool] try_get( future(T) & fut ) with( fut ) {
    174159                        lock( lock );
    175160                        T ret_val;
    176                         if ( state == FUTURE_FULFILLED ) {
    177                                 copy_T( result, ret_val );
     161                        if ( state == FUTURE_FULFILLED$ ) {
     162                                copy_T$( ret_val, result );
    178163                                unlock( lock );
    179164                                return [ret_val, true];
    180165                        }
    181166                        unlock( lock );
    182 
    183167                        return [ret_val, false];
    184168                }
    185169
    186                 bool register_select( future(T) & this, select_node & s ) with(this) {
    187                         lock( lock );
    188 
    189                         // check if we can complete operation. If so race to establish winner in special OR case
    190                         if ( !s.park_counter && state != FUTURE_EMPTY ) {
    191                                 if ( !__make_select_node_available( s ) ) { // we didn't win the race so give up on registering
    192                                         unlock( lock );
    193                                         return false;
    194                                 }
    195                         }
    196 
    197                         // future not ready -> insert select node and return
    198                         if ( state == FUTURE_EMPTY ) {
    199                                 insert_last( waiters, s );
    200                                 unlock( lock );
    201                                 return false;
    202                         }
    203 
    204                         __make_select_node_available( s );
    205                         unlock( lock );
    206                         return true;
    207                 }
    208 
    209                 bool unregister_select( future(T) & this, select_node & s ) with(this) {
    210                         if ( ! isListed( s ) ) return false;
    211                         lock( lock );
    212                         if ( isListed( s ) ) remove( s );
    213                         unlock( lock );
    214                         return false;
    215                 }
    216 
    217                 bool on_selected( future(T) &, select_node & ) { return true; }
    218         }
    219 }
    220 
    221 //--------------------------------------------------------------------------------------------------------
    222 // These futures below do not support select statements so they may not have as many features as 'future'
    223 //  however the 'single_future' is cheap and cheerful and is most likely more performant than 'future'
    224 //  since it uses raw atomics and no locks
    225 //
    226 // As far as 'multi_future' goes I can't see many use cases as it will be less performant than 'future'
    227 //  since it is monitor based and also is not compatible with select statements
     170                // Used by Server
     171
     172                // PRIVATE
     173
     174                bool fulfil$( future(T) & fut ) with( fut ) {   // helper
     175                        bool ret_val = ! isEmpty( waiters );
     176                        state = FUTURE_FULFILLED$;
     177                        while ( ! isEmpty( waiters ) ) {
     178                                if ( !__handle_waituntil_OR( waiters ) ) // handle special waituntil OR case
     179                                        break; // if handle_OR returns false then waiters is empty so break
     180                                select_node &s = remove_first( waiters );
     181
     182                                if ( s.clause_status == 0p )                    // poke in result so that woken threads do not need to reacquire any locks
     183                                        copy_T$( *(((future_node$(T) &)s).my_result), result );
     184
     185                                wake_one( waiters, s );
     186                        }
     187                        unlock( lock );
     188                        return ret_val;
     189                }
     190
     191                // PUBLIC
     192
     193                // Load a value/exception into the future, returns whether or not waiting threads.
     194                bool fulfil( future(T) & fut, T val ) with( fut ) {
     195                        lock( lock );
     196                  if ( state != FUTURE_EMPTY$ ) abort("Attempting to fulfil a future that has already been fulfilled");
     197                        copy_T$( result, val );
     198                        return fulfil$( fut );
     199                }
     200                bool ?()( future(T) & fut, T val ) { return fulfil( fut, val ); } // alternate interface
     201
     202                bool fulfil( future(T) & fut, exception_t * ex ) with( fut ) {
     203                        lock( lock );
     204                  if ( state != FUTURE_EMPTY$ ) abort( "Attempting to fulfil a future that has already been fulfilled" );
     205                        except = ( exception_t * ) malloc( ex->virtual_table->size );
     206                        ex->virtual_table->copy( except, ex );
     207                        return fulfil$( fut );
     208                }
     209                bool ?()( future(T) & fut, exception_t * ex ) { return fulfil( fut, ex ); } // alternate interface
     210
     211                void reset( future(T) & fut ) with( fut ) {             // mark future as empty (for reuse)
     212                        lock( lock );
     213                  if ( ! isEmpty( waiters ) ) abort( "Attempting to reset a future with blocked waiters" );
     214                        state = FUTURE_EMPTY$;
     215                        free( except );
     216                        except = 0p;
     217                        unlock( lock );
     218                }
     219        } // static inline
     220} // forall( T )
     221
     222//--------------------------------------------------------------------------------------------------------
     223// future_rc uses reference counting to eliminate explicit storage-management and support the waituntil
     224// statement.
    228225//--------------------------------------------------------------------------------------------------------
    229226
    230227forall( T ) {
     228        // PRIVATE
     229
     230        struct future_rc_impl$ {
     231                futex_mutex lock;                                                               // concurrent protection
     232                size_t refCnt;                                                                  // number of references to future
     233                future(T) fut;                                                                  // underlying future
     234        }; // future_rc_impl$
     235
     236        static inline {
     237                size_t incRef$( future_rc_impl$( T ) & impl ) with( impl ) {
     238                        return __atomic_fetch_add( &refCnt, 1, __ATOMIC_SEQ_CST );
     239                } // incRef$
     240
     241                size_t decRef$( future_rc_impl$( T ) & impl ) with( impl ) {
     242                        return __atomic_fetch_add( &refCnt, -1, __ATOMIC_SEQ_CST );
     243                } // decRef$
     244
     245                void ?{}( future_rc_impl$( T ) & frc ) with( frc ) {
     246                        refCnt = 1;                                                                     // count initial object
     247                } // ?{}
     248        } // static inline
     249       
     250        // PUBLIC
     251
     252        struct future_rc {
     253                future_rc_impl$(T) * impl;             
     254        }; // future_rc
     255        __CFA_SELECT_GET_TYPE( future_rc(T) );                          // magic
     256               
     257        static inline {
     258                // PRIVATE
     259
     260                bool register_select$( future_rc(T) & frc, select_node & s ) with( frc ) { // for waituntil statement
     261                        return register_select$( frc.impl->fut, s );
     262                }
     263
     264                bool unregister_select$( future_rc(T) & frc, select_node & s ) with( frc ) { // for waituntil statement
     265                        return unregister_select$( frc.impl->fut, s );
     266                }
     267
     268                bool on_selected$( future_rc(T) &, select_node & ) { return true; } // for waituntil statement
     269
     270                // PUBLIC
     271
     272                // General
     273
     274                void ?{}( future_rc( T ) & frc ) with( frc ) {  // default constructor
     275                        impl = new();
     276                } // ?{}
     277
     278                void ?{}( future_rc( T ) & to, future_rc( T ) & from ) with( to ) { // copy constructor
     279                        impl = from.impl;                                                       // point at new impl
     280                        incRef$( *impl );
     281                } // ?{}
     282
     283                void ^?{}( future_rc( T ) & frc ) with( frc ) {
     284                        if ( decRef$( *impl ) == 1 ) { delete( impl ); impl = 0p; }
     285                } // ^?{}
     286
     287                future_rc( T ) & ?=?( future_rc( T ) & lhs, future_rc( T ) & rhs ) with( lhs ) {
     288                  if ( impl == rhs.impl ) return lhs;                   // self assignment ?
     289                        if ( decRef$( *impl ) == 1 ) { delete( impl ); impl = 0p; } // no references ? => delete current impl
     290                        impl = rhs.impl;                                                        // point at new impl
     291                        incRef$( *impl );                                                       //   and increment reference count
     292                        return lhs;
     293                } // ?+?
     294
     295                // Used by Client
     296
     297                bool available( future_rc( T ) & frc ) { return available( frc.impl->fut ); } // future result available ?
     298
     299                // Return a value/exception from the future.
     300                [T, bool] get( future_rc(T) & frc ) with( frc ) { return get( impl->fut ); } // return future value
     301                T get( future_rc(T) & frc ) with( frc ) { return get( impl->fut ); } // return future value
     302                T ?()( future_rc(T) & frc ) with( frc ) { return get( frc ); } // alternate interface
     303                [T, bool] try_get( future_rc(T) & frc ) with( frc ) { return try_get( impl->fut ); }
     304
     305                int ?==?( future_rc( T ) & lhs, future_rc( T ) & rhs ) { return lhs.impl == rhs.impl; } // referential equality
     306
     307                // Used by Server
     308
     309                // Load a value/exception into the future, returns whether or not waiting threads.
     310                bool fulfil( future_rc(T) & frc, T val ) with( frc ) { return fulfil( impl->fut, val ); } // copy-in future value
     311                bool ?()( future_rc(T) & frc, T val ) { return fulfil( frc, val ); } // alternate interface
     312
     313                bool fulfil( future_rc(T) & frc, exception_t * ex ) with( frc ) { return fulfil( impl->fut, ex ); } // insert future exception
     314                bool ?()( future_rc(T) & frc, exception_t * ex ) { return fulfil( frc, ex ); } // alternate interface
     315
     316                void reset( future_rc(T) & frc ) with( frc ) { reset( impl->fut ); } // mark future as empty (for reuse)
     317        } // static inline
     318} // forall( T )
     319
     320//--------------------------------------------------------------------------------------------------------
     321// This future does not support waituntil statements so it does not have as many features as 'future'.
     322// However, it is cheap and cheerful and is more performant than 'future' since it uses raw atomics
     323// and no locks
     324//--------------------------------------------------------------------------------------------------------
     325
     326forall( T ) {
     327        // PUBLIC
     328
    231329        struct single_future {
    232330                inline future_t;
     
    235333
    236334        static inline {
    237                 // Reset future back to original state
    238                 void reset(single_future(T) & this) { reset( (future_t&)this ); }
    239 
    240                 // check if the future is available
    241                 bool available( single_future(T) & this ) { return available( (future_t&)this ); }
    242 
    243                 // Mark the future as abandoned, meaning it will be deleted by the server
    244                 // This doesn't work beause of the potential need for a destructor
    245                 // void abandon( single_future(T) & this );
    246 
    247                 // Fulfil the future, returns whether or not someone was unblocked
    248                 thread$ * fulfil( single_future(T) & this, T result ) {
    249                         this.result = result;
    250                         return fulfil( (future_t&)this );
    251                 }
    252 
    253                 // Wait for the future to be fulfilled
    254                 // Also return whether the thread had to block or not
    255                 [T, bool] wait( single_future(T) & this ) {
    256                         bool r = wait( (future_t&)this );
    257                         return [this.result, r];
    258                 }
    259 
    260                 // Wait for the future to be fulfilled
    261                 T wait( single_future(T) & this ) {
    262                         [T, bool] tt;
    263                         tt = wait(this);
    264                         return tt.0;
    265                 }
    266         }
    267 }
    268 
    269 forall( T ) {
    270         monitor multi_future {
    271                 inline future_t;
    272                 condition blocked;
    273                 bool has_first;
    274                 T result;
    275         };
    276 
    277         static inline {
    278                 void ?{}(multi_future(T) & this) {
    279                         this.has_first = false;
    280                 }
    281 
    282                 bool $first( multi_future(T) & mutex this ) {
    283                         if ( this.has_first ) {
    284                                 wait( this.blocked );
    285                                 return false;
    286                         }
    287 
    288                         this.has_first = true;
    289                         return true;
    290                 }
    291 
    292                 void $first_done( multi_future(T) & mutex this ) {
    293                         this.has_first = false;
    294                         signal_all( this.blocked );
    295                 }
    296 
    297                 // Reset future back to original state
    298                 void reset(multi_future(T) & mutex this) {
    299                         if ( this.has_first != false ) abort("Attempting to reset a multi_future with at least one blocked threads");
    300                         if ( !is_empty(this.blocked) ) abort("Attempting to reset a multi_future with multiple blocked threads");
    301                         reset( (future_t&)*(future_t*)((uintptr_t)&this + sizeof(monitor$)) );
    302                 }
    303 
    304                 // Fulfil the future, returns whether or not someone was unblocked
    305                 bool fulfil( multi_future(T) & this, T result ) {
    306                         this.result = result;
    307                         return fulfil( (future_t&)*(future_t*)((uintptr_t)&this + sizeof(monitor$)) ) != 0p;
    308                 }
    309 
    310                 // Wait for the future to be fulfilled
    311                 // Also return whether the thread had to block or not
    312                 [T, bool] wait( multi_future(T) & this ) {
    313                         bool sw = $first( this );
    314                         bool w = !sw;
    315                         if ( sw ) {
    316                                 w = wait( (future_t&)*(future_t*)((uintptr_t)&this + sizeof(monitor$)) );
    317                                 $first_done( this );
    318                         }
    319 
    320                         return [this.result, w];
    321                 }
    322 
    323                 // Wait for the future to be fulfilled
    324                 T wait( multi_future(T) & this ) {
    325                         return wait(this).0;
    326                 }
    327         }
    328 }
     335                // PUBLIC
     336
     337                bool available( single_future(T) & fut ) { return available( (future_t &)fut ); } // future result available ?
     338
     339                // Return a value/exception from the future.
     340                [T, bool] get( single_future(T) & fut ) { return [fut.result, wait( fut )]; }
     341                T get( single_future(T) & fut ) { wait( fut ); return fut.result; }
     342                T ?()( single_future(T) & fut ) { return get( fut ); }  // alternate interface
     343
     344                // Load a value into the future, returns whether or not waiting threads.
     345                bool fulfil( single_future(T) & fut, T result ) {
     346                        fut.result = result;
     347                        return fulfil( (future_t &)fut ) != 0p;
     348                }
     349                bool ?()( single_future(T) & fut, T val ) { return fulfil( fut, val ); } // alternate interface
     350
     351                void reset( single_future(T) & fut ) { reset( (future_t &)fut ); } // mark future as empty (for reuse)
     352        } // static inline
     353} // forall( T )
  • libcfa/src/concurrency/invoke.h

    r8f448e0 r5e0b6657  
    1010// Created On       : Tue Jan 17 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Wed Apr 23 15:27:18 2025
    13 // Update Count     : 61
     12// Last Modified On : Fri Oct 31 08:46:59 2025
     13// Update Count     : 67
    1414//
    1515
     
    236236        void * link_node;
    237237
     238                // extra fields supporting task related features
     239                uintptr_t shadow$;                                                              // user information for shadow queue
    238240                PRNG_STATE_T random_state;                                              // fast random numbers
    239241
  • libcfa/src/concurrency/locks.cfa

    r8f448e0 r5e0b6657  
    186186
    187187// waituntil() support
    188 bool register_select( blocking_lock & this, select_node & node ) with(this) {
     188bool register_select$( blocking_lock & this, select_node & node ) with(this) {
    189189        lock( lock __cfaabi_dbg_ctx2 );
    190190        thread$ * thrd = active_thread();
     
    218218}
    219219
    220 bool unregister_select( blocking_lock & this, select_node & node ) with(this) {
     220bool unregister_select$( blocking_lock & this, select_node & node ) with(this) {
    221221        lock( lock __cfaabi_dbg_ctx2 );
    222222        if ( isListed( node ) ) {
     
    239239}
    240240
    241 bool on_selected( blocking_lock & this, select_node & node ) { return true; }
     241bool on_selected$( blocking_lock & this, select_node & node ) { return true; }
    242242
    243243//-----------------------------------------------------------------------------
     
    583583        }
    584584}
     585
    585586//-----------------------------------------------------------------------------
    586 // Semaphore
    587 void ?{}( semaphore & this, int count = 1 ) {
    588         (this.lock){};
    589         this.count = count;
    590         (this.waiting){};
    591 }
    592 void ^?{}(semaphore & this) {}
    593 
    594 bool P(semaphore & this) with( this ){
    595         lock( lock __cfaabi_dbg_ctx2 );
    596         count -= 1;
    597         if ( count < 0 ) {
    598                 // queue current task
    599                 append( waiting, active_thread() );
    600 
    601                 // atomically release spin lock and block
    602                 unlock( lock );
     587// Semaphore, counting
     588
     589void ?{}( semaphore & sem, ssize_t count = 1 ) with( sem ) {
     590        count$ = count;
     591        (lock$){};
     592        (waiting$){};
     593}
     594
     595bool P( semaphore & sem ) with( sem ) {
     596        lock( lock$ __cfaabi_dbg_ctx2 );
     597        count$ -= 1;
     598        if ( count$ < 0 ) {                                                                     // in use ?
     599                append( waiting$, active_thread() );                    // queue current task
     600                unlock( lock$ );                                                                // atomically release spin lock and block
    603601                park();
    604                 return true;
     602                return false;
     603        } // if
     604        unlock( lock$ );
     605        return true;
     606}
     607
     608bool P( semaphore & sem, semaphore & lock ) with( sem ) {
     609        lock( lock$ __cfaabi_dbg_ctx2 );
     610        if ( &sem == &lock ) {                                                          // perform operation on self ?
     611                if ( count$ < 0 ) {                                                             // V my semaphore
     612                        unpark( pop_head( waiting$ ) );                         // unblock task at head of waiting list
     613                } // if
    605614        } else {
    606                 unlock( lock );
     615                V( lock );                                                                              // V mutex semaphore
     616                count$ -= 1;
     617        } // if
     618
     619        if ( count$ < 0 ) {                                                                     // in use ?
     620                append( waiting$, active_thread() );                    // queue current task
     621                unlock( lock$ );                                                                // atomically release spin lock and block
     622                park();
    607623                return false;
    608         }
    609 }
    610 
    611 thread$ * V (semaphore & this, const bool doUnpark ) with( this ) {
     624        } // if
     625        unlock( lock$ );
     626        return true;
     627}
     628
     629bool try_P( semaphore & sem ) with( sem ) {
     630        lock( lock$ __cfaabi_dbg_ctx2 );
     631        if ( count$ <= 0 ) {                                                            // in use ?
     632                unlock( lock$ );
     633                return false;
     634        } // if
     635        count$ -= 1;                                                                            // acquire
     636        unlock( lock$ );
     637        return true;
     638}
     639
     640bool V( semaphore & sem ) with( sem ) {
    612641        thread$ * thrd = 0p;
    613         lock( lock __cfaabi_dbg_ctx2 );
    614         count += 1;
    615         if ( count <= 0 ) {
    616                 // remove task at head of waiting list
    617                 thrd = pop_head( waiting );
    618         }
    619 
    620         unlock( lock );
    621 
    622         // make new owner
    623         if ( doUnpark ) unpark( thrd );
    624 
    625         return thrd;
    626 }
    627 
    628 bool V(semaphore & this) with( this ) {
    629         thread$ * thrd = V(this, true);
     642        lock( lock$ __cfaabi_dbg_ctx2 );
     643        count$ += 1;
     644        if ( count$ <= 0 ) {
     645                thrd = pop_head( waiting$ );                                    // remove task at head of waiting list
     646        }
     647        unlock( lock$ );
     648        if ( true ) unpark( thrd );                                             // make new owner
    630649        return thrd != 0p;
    631650}
    632651
    633 bool V(semaphore & this, unsigned diff) with( this ) {
    634         thread$ * thrd = 0p;
    635         lock( lock __cfaabi_dbg_ctx2 );
    636         int release = max(-count, (int)diff);
    637         count += diff;
    638         for(release) {
    639                 unpark( pop_head( waiting ) );
    640         }
    641 
    642         unlock( lock );
    643 
    644         return thrd != 0p;
    645 }
    646 
     652size_t V( semaphore & sem, size_t count ) with( sem ) {
     653        lock( lock$ __cfaabi_dbg_ctx2 );
     654        size_t release = max( (size_t)-count$, count );
     655        count$ += count;
     656        for ( release ) unpark( pop_head( waiting$ ) );
     657        unlock( lock$ );
     658        return release;
     659}
  • libcfa/src/concurrency/locks.hfa

    r8f448e0 r5e0b6657  
    1111// Created On       : Thu Jan 21 19:46:50 2021
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Thu Aug 21 22:36:44 2025
    14 // Update Count     : 23
     13// Last Modified On : Sun Nov 23 22:38:45 2025
     14// Update Count     : 67
    1515//
    1616
     
    8181
    8282
    83 
    84 //-----------------------------------------------------------------------------
    85 // Semaphore
     83//-----------------------------------------------------------------------------
     84// Semaphore, counting
     85
    8686struct semaphore {
    87         __spinlock_t lock;
    88         int count;
    89         __queue_t( thread$) waiting;
    90 };
    91 
    92 void ?{}( semaphore & this, int count = 1 );
    93 void ^?{}( semaphore & this );
    94 bool P( semaphore & this );
    95 bool V( semaphore & this );
    96 bool V( semaphore & this, unsigned count );
    97 thread$ * V( semaphore & this, bool );
     87        ssize_t count$;                                                                          // - => # waiting threads, 0 => block, + => acquire
     88        __spinlock_t lock$;                                                                      // protect blocking-lock critical sections
     89        __queue_t( thread$ ) waiting$;                                           // waiting threads
     90};
     91
     92void ?{}( semaphore & sem, ssize_t count = 1 );
     93// Return values are used for composition. Calling threads know if a thread is unblocked, which can be useful for
     94// debugging, performance instrumentation and other metadata tracking purposes.
     95bool P( semaphore & sem );
     96static inline bool P( semaphore & sem, uintptr_t shadow ) { active_thread()->shadow$ = shadow; return P( sem ); }
     97bool P( semaphore & sem, semaphore & lock );                    // atomic block and release
     98bool try_P( semaphore & sem );
     99static inline bool P( semaphore & sem, semaphore & lock, uintptr_t shadow ) { active_thread()->shadow$ = shadow; return P( sem, lock ); }
     100bool V( semaphore & sem );
     101size_t V( semaphore & sem, size_t count );
     102static inline uintptr_t front( semaphore & sem ) with( sem ) { // return shadow information for first waiting thread
     103        #ifdef __CFA_DEBUG__
     104        if ( waiting$ ) {                                                                       // condition queue must not be empty
     105                abort( "Attempt to access user data on an empty semaphore lock.\n"
     106                           "Possible cause is not checking if the condition lock is empty before reading stored data." );
     107        } // if
     108        #endif // __CFA_DEBUG__
     109        return waiting$.head->shadow$;                                          // return condition information stored with blocked task
     110}
     111static inline ssize_t counter( semaphore & sem ) with( sem ) { return count$; } // - => # waiting threads, 0 => block, + => acquire
     112//static inline int ?!=?( semaphore & sem, zero_t ) with( sem ) { return count$ != 0; } // empty waiting queue
     113static inline bool empty( semaphore & sem ) with( sem ) { return count$ == 0; } // empty waiting queue
     114
    98115
    99116//----------
     
    110127static inline void on_wakeup( single_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    111128static inline void on_notify( single_acquisition_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); }
    112 static inline bool register_select( single_acquisition_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }
    113 static inline bool unregister_select( single_acquisition_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }
    114 static inline bool on_selected( single_acquisition_lock & this, select_node & node ) { return on_selected( (blocking_lock &)this, node ); }
     129static inline bool register_select$( single_acquisition_lock & this, select_node & node ) { return register_select$( (blocking_lock &)this, node ); }
     130static inline bool unregister_select$( single_acquisition_lock & this, select_node & node ) { return unregister_select$( (blocking_lock &)this, node ); }
     131static inline bool on_selected$( single_acquisition_lock & this, select_node & node ) { return on_selected$( (blocking_lock &)this, node ); }
    115132__CFA_SELECT_GET_TYPE( single_acquisition_lock );
    116133
     
    128145static inline void on_wakeup( owner_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    129146static inline void on_notify( owner_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); }
    130 static inline bool register_select( owner_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }
    131 static inline bool unregister_select( owner_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }
    132 static inline bool on_selected( owner_lock & this, select_node & node ) { return on_selected( (blocking_lock &)this, node ); }
     147static inline bool register_select$( owner_lock & this, select_node & node ) { return register_select$( (blocking_lock &)this, node ); }
     148static inline bool unregister_select$( owner_lock & this, select_node & node ) { return unregister_select$( (blocking_lock &)this, node ); }
     149static inline bool on_selected$( owner_lock & this, select_node & node ) { return on_selected$( (blocking_lock &)this, node ); }
    133150__CFA_SELECT_GET_TYPE( owner_lock );
    134151
     
    594611
    595612// waituntil() support
    596 static inline bool register_select( simple_owner_lock & this, select_node & node ) with( this ) {
     613static inline bool register_select$( simple_owner_lock & this, select_node & node ) with( this ) {
    597614        lock( lock __cfaabi_dbg_ctx2 );
    598615
     
    626643}
    627644
    628 static inline bool unregister_select( simple_owner_lock & this, select_node & node ) with( this ) {
     645static inline bool unregister_select$( simple_owner_lock & this, select_node & node ) with( this ) {
    629646        lock( lock __cfaabi_dbg_ctx2 );
    630647        if ( isListed( node ) ) {
     
    644661}
    645662
    646 static inline bool on_selected( simple_owner_lock & /*this*/, select_node & /*node*/ ) { return true; }
     663static inline bool on_selected$( simple_owner_lock & /*this*/, select_node & /*node*/ ) { return true; }
    647664__CFA_SELECT_GET_TYPE( simple_owner_lock );
    648665
  • libcfa/src/concurrency/monitor.cfa

    r8f448e0 r5e0b6657  
    1010// Created On       : Thd Feb 23 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Fri Apr 25 07:20:22 2025
    13 // Update Count     : 80
     12// Last Modified On : Tue Nov  4 22:03:41 2025
     13// Update Count     : 82
    1414//
    1515
     
    494494
    495495bool signal( condition & this ) libcfa_public {
    496         if ( is_empty( this ) ) { return false; }
     496        if ( empty( this ) ) { return false; }
    497497
    498498        //Check that everything is as expected
     
    581581// Access the user_info of the thread waiting at the front of the queue
    582582uintptr_t front( condition & this ) libcfa_public {
    583         verifyf( ! is_empty(this),
     583        verifyf( ! empty( this ),
    584584                "Attempt to access user data on an empty condition.\n"
    585585                "Possible cause is not checking if the condition is empty before reading stored data."
  • libcfa/src/concurrency/monitor.hfa

    r8f448e0 r5e0b6657  
    1010// Created On       : Thd Feb 23 12:27:26 2017
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Thu Feb  2 11:29:21 2023
    13 // Update Count     : 12
     12// Last Modified On : Tue Nov  4 21:56:17 2025
     13// Update Count     : 16
    1414//
    1515
     
    146146}
    147147
    148               void wait        ( condition & this, uintptr_t user_info = 0 );
    149 static inline bool is_empty    ( condition & this ) { return this.blocked.head == 1p; }
    150               bool signal      ( condition & this );
    151               bool signal_block( condition & this );
    152 static inline bool signal_all  ( condition & this ) { bool ret = false; while(!is_empty(this)) { ret = signal(this) || ret; } return ret; }
    153          uintptr_t front       ( condition & this );
     148void wait( condition & this, uintptr_t user_info = 0 );
     149static inline bool empty( condition & this ) { return this.blocked.head == 1p; }
     150bool signal ( condition & this );
     151bool signal_block( condition & this );
     152static inline bool signal_all( condition & this ) {
     153        bool ret = false;
     154        while ( !empty( this ) ) {
     155                ret = signal(this) || ret;
     156        }
     157        return ret;
     158}
     159uintptr_t front( condition & this );
    154160
    155161//-----------------------------------------------------------------------------
  • libcfa/src/concurrency/select.cfa

    r8f448e0 r5e0b6657  
    1010// Author           : Colby Alexander Parsons
    1111// Created On       : Thu Apr 21 19:46:50 2023
    12 // Last Modified By : Kyoung Seo
    13 // Last Modified On : Wed Mar 19 12:00:00 2025
    14 // Update Count     : 1
     12// Last Modified By : Peter A. Buhr
     13// Last Modified On : Sun Nov 23 22:38:53 2025
     14// Update Count     : 4
    1515//
    1616
     
    3939
    4040// Selectable trait routines
    41 bool register_select( select_timeout_node & this, select_node & node ) {
     41bool register_select$( select_timeout_node & this, select_node & node ) {
    4242    this.s_node = &node;
    4343    node.extra = 0p;
     
    4545    return false;
    4646}
    47 bool unregister_select( select_timeout_node & this, select_node & node ) {
     47bool unregister_select$( select_timeout_node & this, select_node & node ) {
    4848    unregister_self( &this.a_node );
    4949    return false;
    5050}
    51 bool on_selected( select_timeout_node & this, select_node & node ) { return true; }
     51bool on_selected$( select_timeout_node & this, select_node & node ) { return true; }
    5252
  • libcfa/src/concurrency/select.hfa

    r8f448e0 r5e0b6657  
    1111// Created On       : Thu Jan 21 19:46:50 2023
    1212// Last Modified By : Peter A. Buhr
    13 // Last Modified On : Fri Apr 25 07:31:26 2025
    14 // Update Count     : 5
     13// Last Modified On : Sun Nov 23 22:38:36 2025
     14// Update Count     : 8
    1515//
    1616
     
    8787        // For registering a select stmt on a selectable concurrency primitive
    8888        // Returns bool that indicates if operation is already SAT
    89         bool register_select( T &, select_node & );
     89        bool register_select$( T &, select_node & );
    9090
    9191        // For unregistering a select stmt on a selectable concurrency primitive
    9292        // If true is returned then the corresponding code block is run (only in non-special OR case and only if node status is not RUN)
    93         bool unregister_select( T &, select_node & );
     93        bool unregister_select$( T &, select_node & );
    9494
    9595        // This routine is run on the selecting thread prior to executing the statement corresponding to the select_node
    9696        //      passed as an arg to this routine. If true is returned proceed as normal, if false is returned the statement is skipped
    97         bool on_selected( T &, select_node & );
     97        bool on_selected$( T &, select_node & );
    9898};
    9999// Used inside the compiler to allow for overloading on return type for operations such as '?<<?' for channels
     
    209209
    210210// Selectable trait routines
    211 bool register_select( select_timeout_node & this, select_node & node );
    212 bool unregister_select( select_timeout_node & this, select_node & node );
    213 bool on_selected( select_timeout_node & this, select_node & node );
     211bool register_select$( select_timeout_node & this, select_node & node );
     212bool unregister_select$( select_timeout_node & this, select_node & node );
     213bool on_selected$( select_timeout_node & this, select_node & node );
    214214select_timeout_node __CFA_select_get_type( select_timeout_node this );
    215215
  • libcfa/src/strstream.cfa

    r8f448e0 r5e0b6657  
    1010// Created On       : Thu Apr 22 22:24:35 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 14 20:45:00 2025
    13 // Update Count     : 116
     12// Last Modified On : Sat Oct 11 15:10:56 2025
     13// Update Count     : 119
    1414//
    1515
     
    148148                abort();
    149149        } // if
     150        os.cursor$ = 0;
    150151        return os;
    151152} // write
     
    155156} // write
    156157
     158void clear( ostrstream & os ) {
     159        os.cursor$ = 0;
     160} // clear
    157161
    158162// *********************************** istrstream ***********************************
  • libcfa/src/strstream.hfa

    r8f448e0 r5e0b6657  
    1010// Created On       : Thu Apr 22 22:20:59 2021
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Mon Apr 14 20:57:15 2025
    13 // Update Count     : 61
     12// Last Modified On : Sat Oct 11 15:11:06 2025
     13// Update Count     : 62
    1414//
    1515
     
    7575void ?{}( ostrstream &, char buf[], size_t size );
    7676
     77void clear( ostrstream & os );
     78
    7779
    7880// *********************************** istrstream ***********************************
Note: See TracChangeset for help on using the changeset viewer.