Ignore:
Timestamp:
May 1, 2023, 4:00:06 PM (15 months ago)
Author:
caparsons <caparson@…>
Branches:
ADT, ast-experimental, master
Children:
73bf7ddc
Parents:
bb7422a
Message:

some cleanup and a bunch of changes to support waituntil statement

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/concurrency/future.hfa

    rbb7422a rbeeff61e  
    1919#include "monitor.hfa"
    2020#include "select.hfa"
     21#include "locks.hfa"
    2122
    2223//----------------------------------------------------------------------------
     
    2627//  future_t is lockfree and uses atomics which aren't needed given we use locks here
    2728forall( T ) {
    28     // enum(int) { FUTURE_EMPTY = 0, FUTURE_FULFILLED = 1 }; // Enums seem to be broken so feel free to add this back afterwards
     29    // enum { FUTURE_EMPTY = 0, FUTURE_FULFILLED = 1 }; // Enums seem to be broken so feel free to add this back afterwards
    2930
    3031    // temporary enum replacement
     
    4445    };
    4546
    46     // C_TODO: perhaps allow exceptions to be inserted like uC++?
    47 
    4847        static inline {
    4948
     
    8281        void _internal_flush( future(T) & this ) with(this) {
    8382            while( ! waiters`isEmpty ) {
     83                if ( !__handle_waituntil_OR( waiters ) ) // handle special waituntil OR case
     84                    break; // if handle_OR returns false then waiters is empty so break
    8485                select_node &s = try_pop_front( waiters );
    8586
    86                 if ( s.race_flag == 0p )
     87                if ( s.clause_status == 0p )
    8788                    // poke in result so that woken threads do not need to reacquire any locks
    88                     // *(((future_node(T) &)s).my_result) = result;
    8989                    copy_T( result, *(((future_node(T) &)s).my_result) );
    90                 else if ( !install_select_winner( s, &this ) ) continue;
     90                else if ( !__make_select_node_available( s ) ) continue;
    9191               
    9292                // only unpark if future is not selected
     
    9797
    9898                // Fulfil the future, returns whether or not someone was unblocked
    99                 bool fulfil( future(T) & this, T & val ) with(this) {
     99                bool fulfil( future(T) & this, T val ) with(this) {
    100100            lock( lock );
    101101            if( state != FUTURE_EMPTY )
     
    153153        }
    154154
    155         void * register_select( future(T) & this, select_node & s ) with(this) {
    156             lock( lock );
    157 
    158             // future not ready -> insert select node and return 0p
     155        bool register_select( future(T) & this, select_node & s ) with(this) {
     156            lock( lock );
     157
     158            // check if we can complete operation. If so race to establish winner in special OR case
     159            if ( !s.park_counter && state != FUTURE_EMPTY ) {
     160                if ( !__make_select_node_available( s ) ) { // we didn't win the race so give up on registering
     161                    unlock( lock );
     162                    return false;
     163                }
     164            }
     165
     166            // future not ready -> insert select node and return
    159167            if( state == FUTURE_EMPTY ) {
    160168                insert_last( waiters, s );
    161169                unlock( lock );
    162                 return 0p;
    163             }
    164 
    165             // future ready and we won race to install it as the select winner return 1p
    166             if ( install_select_winner( s, &this ) ) {
    167                 unlock( lock );
    168                 return 1p;
    169             }
    170 
    171             unlock( lock );
    172             // future ready and we lost race to install it as the select winner
    173             return 2p;
    174         }
    175 
    176         void unregister_select( future(T) & this, select_node & s ) with(this) {
     170                return false;
     171            }
     172
     173            __make_select_node_available( s );
     174            unlock( lock );
     175            return true;
     176        }
     177
     178        bool unregister_select( future(T) & this, select_node & s ) with(this) {
     179            if ( ! s`isListed ) return false;
    177180            lock( lock );
    178181            if ( s`isListed ) remove( s );
    179182            unlock( lock );
     183            return false;
    180184        }
    181185               
     186        bool on_selected( future(T) & this, select_node & node ) { return true; }
    182187        }
    183188}
     
    186191// These futures below do not support select statements so they may not be as useful as 'future'
    187192//  however the 'single_future' is cheap and cheerful and is most likely more performant than 'future'
    188 //  since it uses raw atomics and no locks afaik
     193//  since it uses raw atomics and no locks
    189194//
    190195// As far as 'multi_future' goes I can't see many use cases as it will be less performant than 'future'
Note: See TracChangeset for help on using the changeset viewer.