Changes in / [c083c3d:4daf79f]


Ignore:
Files:
5 added
12 deleted
34 edited

Legend:

Unmodified
Added
Removed
  • doc/theses/colby_parsons_MMAth/benchmarks/actors/data/nasus_CFA.txt

    rc083c3d r4daf79f  
    115
    221 2 4 8 16 24 32 48
    3 Longest-Victim No-Stealing Random
     3CFA-LV CFA-NS CFA-R
    44executor
    5 Longest-Victim:
     5CFA-LV:
    66proc    time (s)
    771       29.22
     
    454548      1.20
    464648      1.20
    47 No-Stealing:
     47CFA-NS:
    4848proc    time (s)
    49491       28.25
     
    878748      1.18
    888848      1.16
    89 Random:
     89CFA-R:
    9090proc    time (s)
    91911       28.58
     
    131131
    132132matrix
    133 Longest-Victim:
     133CFA-LV:
    134134proc    time (s)
    1351351       105.48
     
    17317348      2.75
    17417448      2.96
    175 No-Stealing:
     175CFA-NS:
    176176proc    time (s)
    1771771       106.01
     
    21521548      2.78
    21621648      2.92
    217 Random:
     217CFA-R:
    218218proc    time (s)
    2192191       105.91
     
    259259
    260260repeat
    261 Longest-Victim:
     261CFA-LV:
    262262proc    time (s)
    2632631       1.17
     
    30130148      13.73
    30230248      14.55
    303 No-Stealing:
     303CFA-NS:
    304304proc    time (s)
    3053051       1.15
     
    34334348      13.03
    34434448      12.83
    345 Random:
     345CFA-R:
    346346proc    time (s)
    3473471       1.15
     
    387387
    388388balance_one
    389 Longest-Victim:
     389CFA-LV:
    390390proc    time (s)
    3913911       20.06
     
    42942948      1.11
    43043048      1.12
    431 No-Stealing:
     431CFA-NS:
    432432proc    time (s)
    4334331       20.13
     
    47147148      19.95
    47247248      20.00
    473 Random:
     473CFA-R:
    474474proc    time (s)
    4754751       19.92
     
    515515
    516516balance_multi
    517 Longest-Victim:
     517CFA-LV:
    518518proc    time (s)
    5195191       8.17
     
    55755748      5.75
    55855848      5.68
    559 No-Stealing:
     559CFA-NS:
    560560proc    time (s)
    5615611       8.10
     
    59959948      9.28
    60060048      9.26
    601 Random:
     601CFA-R:
    602602proc    time (s)
    6036031       8.08
  • doc/theses/colby_parsons_MMAth/benchmarks/actors/data/pyke_CFA.txt

    rc083c3d r4daf79f  
    115
    221 2 4 8 16 24 32 48
    3 Longest-Victim No-Stealing Random
     3CFA-LV CFA-NS CFA-R
    44executor
    5 Longest-Victim:
     5CFA-LV:
    66proc    time (s)
    771       29.04
     
    454548      2.58
    464648      2.55
    47 No-Stealing:
     47CFA-NS:
    4848proc    time (s)
    49491       28.15
     
    878748      2.59
    888848      2.60
    89 Random:
     89CFA-R:
    9090proc    time (s)
    91911       29.06
     
    131131
    132132matrix
    133 Longest-Victim:
     133CFA-LV:
    134134proc    time (s)
    1351351       127.44
     
    17317348      6.83
    17417448      6.81
    175 No-Stealing:
     175CFA-NS:
    176176proc    time (s)
    1771771       127.64
     
    21521548      6.77
    21621648      6.74
    217 Random:
     217CFA-R:
    218218proc    time (s)
    2192191       127.26
     
    259259
    260260repeat
    261 Longest-Victim:
     261CFA-LV:
    262262proc    time (s)
    2632631       1.16
     
    30130148      19.75
    30230248      19.71
    303 No-Stealing:
     303CFA-NS:
    304304proc    time (s)
    3053051       1.18
     
    34334348      13.88
    34434448      13.71
    345 Random:
     345CFA-R:
    346346proc    time (s)
    3473471       1.18
     
    387387
    388388balance_one
    389 Longest-Victim:
     389CFA-LV:
    390390proc    time (s)
    3913911       19.46
     
    42942948      2.12
    43043048      2.17
    431 No-Stealing:
     431CFA-NS:
    432432proc    time (s)
    4334331       21.00
     
    47147148      47.50
    47247248      47.72
    473 Random:
     473CFA-R:
    474474proc    time (s)
    4754751       20.81
     
    515515
    516516balance_multi
    517 Longest-Victim:
     517CFA-LV:
    518518proc    time (s)
    5195191       7.94
     
    55755748      14.38
    55855848      14.50
    559 No-Stealing:
     559CFA-NS:
    560560proc    time (s)
    5615611       8.48
     
    59959948      21.50
    60060048      21.15
    601 Random:
     601CFA-R:
    602602proc    time (s)
    6036031       8.49
  • doc/theses/colby_parsons_MMAth/benchmarks/channels/plotData.py

    rc083c3d r4daf79f  
    7070    if currBench == Bench.Unset:
    7171        if line == "contend:":
    72             name = "Channel Contention"
     72            name = "Contend"
    7373            currBench = Bench.Contend
    7474        elif line == "zero:":
  • doc/theses/colby_parsons_MMAth/code/swap_queues.cfa

    rc083c3d r4daf79f  
    1 // sequential equivalent swap
    2 void swap( uint victim_idx, uint my_idx  ) {
    3     // Step 0:
     1// this is a code stub and will not compile
     2
     3// tries to atomically swap two queues and returns 0p if the swap failed
     4// returns ptr to newly owned queue if swap succeeds
     5static inline work_queue * try_swap_queues( worker & this, unsigned int victim_idx, unsigned int my_idx ) with(this) {
    46    work_queue * my_queue = request_queues[my_idx];
    5     work_queue * vic_queue = request_queues[victim_idx];
    6     // Step 2:
    7     request_queues[my_idx] = 0p;
    8     // Step 3:
    9     request_queues[victim_idx] = my_queue;
    10     // Step 4:
    11     request_queues[my_idx] = vic_queue;
     7    work_queue * other_queue = request_queues[victim_idx];
     8
     9    // if either queue is 0p then they are in the process of being stolen
     10    if ( other_queue == 0p || my_queue == 0p ) return 0p;
     11
     12    // try to set our queue ptr to be 0p. If it fails someone moved our queue so return false
     13    if ( !__atomic_compare_exchange_n( &request_queues[my_idx], &my_queue, 0p, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) )
     14        return 0p;
     15
     16    // try to set other queue ptr to be our queue ptr. If it fails someone moved the other queue so fix up then return false
     17    if ( !__atomic_compare_exchange_n( &request_queues[victim_idx], &other_queue, my_queue, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) {
     18        /* paranoid */ verify( request_queues[my_idx] == 0p );
     19        request_queues[my_idx] = my_queue; // reset my queue ptr back to appropriate val
     20        return 0p;
     21    }
     22
     23    // we have successfully swapped and since our queue is 0p no one will touch it so write back new queue ptr non atomically
     24    request_queues[my_idx] = other_queue; // last write does not need to be atomic
     25    return other_queue;
    1226}
    1327
     
    2135
    2236bool try_swap_queues( worker & this, uint victim_idx, uint my_idx ) with(this) {
    23     // Step 0:
    24     // request_queues is the shared array of all sharded queues
    2537    work_queue * my_queue = request_queues[my_idx];
    2638    work_queue * vic_queue = request_queues[victim_idx];
    2739
    28     // Step 1:
    2940    // If either queue is 0p then they are in the process of being stolen
    3041    // 0p is CForAll's equivalent of C++'s nullptr
    31     if ( vic_queue == 0p ) return false;
     42    if ( vic_queue == 0p || my_queue == 0p ) return false;
    3243
    33     // Step 2:
    34     // Try to set thief's queue ptr to be 0p.
    35     // If this CAS fails someone stole thief's queue so return false
     44    // Try to set our queue ptr to be 0p.
     45    // If this CAS fails someone moved our queue so return false
    3646    if ( !CAS( &request_queues[my_idx], &my_queue, 0p ) )
    3747        return false;
    38    
    39     // Step 3:
    40     // Try to set victim queue ptr to be thief's queue ptr.
    41     // If it fails someone stole the other queue, so fix up then return false
     48
     49    // Try to set other queue ptr to be our queue ptr.
     50    // If it fails someone moved the other queue, so fix up then return false
    4251    if ( !CAS( &request_queues[victim_idx], &vic_queue, my_queue ) ) {
    4352        request_queues[my_idx] = my_queue; // reset queue ptr back to prev val
     
    4554    }
    4655
    47     // Step 4:
    4856    // Successfully swapped.
    49     // Thief's ptr is 0p so no one will touch it
    50     // Write back without CAS is safe
     57    // Our queue is 0p so no one will touch it so write back without CAS is safe
    5158    request_queues[my_idx] = vic_queue;
    5259    return true;
  • doc/theses/colby_parsons_MMAth/version.sh

    • Property mode changed from 100644 to 100755
  • libcfa/src/bits/weakso_locks.cfa

    rc083c3d r4daf79f  
    1515// Update Count     :
    1616//
     17
    1718#include "bits/weakso_locks.hfa"
     19
    1820#pragma GCC visibility push(default)
    1921
     
    2830void on_wakeup( blocking_lock &, size_t ) {}
    2931size_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; }
    33 
  • libcfa/src/bits/weakso_locks.hfa

    rc083c3d r4daf79f  
    2323#include "containers/list.hfa"
    2424
    25 struct select_node;
     25struct thread$;
    2626
    2727//-----------------------------------------------------------------------------
     
    3232
    3333        // List of blocked threads
    34         dlist( select_node ) blocked_threads;
     34        dlist( thread$ ) blocked_threads;
    3535
    3636        // Count of current blocked threads
     
    6060void on_wakeup( blocking_lock & this, size_t ) OPTIONAL_THREAD;
    6161size_t wait_count( blocking_lock & this ) OPTIONAL_THREAD;
    62 bool register_select( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
    63 bool unregister_select( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
    64 bool on_selected( blocking_lock & this, select_node & node ) OPTIONAL_THREAD;
    6562
    6663//----------
     
    7875static inline void   on_wakeup( multiple_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    7976static 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 ); }
  • libcfa/src/concurrency/channel.hfa

    rc083c3d r4daf79f  
    44#include <list.hfa>
    55#include <mutex_stmt.hfa>
    6 #include "select.hfa"
     6
     7// link field used for threads waiting on channel
     8struct wait_link {
     9    // used to put wait_link on a dl queue
     10    inline dlink(wait_link);
     11
     12    // waiting thread
     13    struct thread$ * t;
     14
     15    // shadow field
     16    void * elem;
     17};
     18P9_EMBEDDED( wait_link, dlink(wait_link) )
     19
     20static inline void ?{}( wait_link & this, thread$ * t, void * elem ) {
     21    this.t = t;
     22    this.elem = elem;
     23}
     24
     25// wake one thread from the list
     26static inline void wake_one( dlist( wait_link ) & queue ) {
     27    wait_link & popped = try_pop_front( queue );
     28    unpark( popped.t );
     29}
    730
    831// returns true if woken due to shutdown
    932// blocks thread on list and releases passed lock
    10 static inline bool block( dlist( select_node ) & queue, void * elem_ptr, go_mutex & lock ) {
    11     select_node sn{ active_thread(), elem_ptr };
    12     insert_last( queue, sn );
     33static inline bool block( dlist( wait_link ) & queue, void * elem_ptr, go_mutex & lock ) {
     34    wait_link w{ active_thread(), elem_ptr };
     35    insert_last( queue, w );
    1336    unlock( lock );
    1437    park();
    15     return sn.extra == 0p;
    16 }
    17 
    18 // Waituntil support (un)register_select helper routine
    19 // Sets select node avail if not special OR case and then unlocks
    20 static inline void __set_avail_then_unlock( select_node & node, go_mutex & mutex_lock ) {
    21     if ( node.park_counter ) __make_select_node_available( node );
    22     unlock( mutex_lock );
     38    return w.elem == 0p;
    2339}
    2440
     
    4359    size_t size, front, back, count;
    4460    T * buffer;
    45     dlist( select_node ) prods, cons; // lists of blocked threads
     61    dlist( wait_link ) prods, cons; // lists of blocked threads
    4662    go_mutex mutex_lock;            // MX lock
    4763    bool closed;                    // indicates channel close/open
     
    5470    size = _size;
    5571    front = back = count = 0;
    56     if ( size != 0 ) buffer = aalloc( size );
     72    buffer = aalloc( size );
    5773    prods{};
    5874    cons{};
     
    7187    #endif
    7288    verifyf( cons`isEmpty && prods`isEmpty, "Attempted to delete channel with waiting threads (Deadlock).\n" );
    73     if ( size != 0 ) delete( buffer );
     89    delete( buffer );
    7490}
    7591static inline size_t get_count( channel(T) & chan ) with(chan) { return count; }
     
    86102    // flush waiting consumers and producers
    87103    while ( has_waiting_consumers( chan ) ) {
    88         if( !__handle_waituntil_OR( cons ) ) // ensure we only signal special OR case threads when they win the race
    89             break;  // if __handle_waituntil_OR returns false cons is empty so break
    90         cons`first.extra = 0p;
     104        cons`first.elem = 0p;
    91105        wake_one( cons );
    92106    }
    93107    while ( has_waiting_producers( chan ) ) {
    94         if( !__handle_waituntil_OR( prods ) ) // ensure we only signal special OR case threads when they win the race
    95             break;  // if __handle_waituntil_OR returns false prods is empty so break
    96         prods`first.extra = 0p;
     108        prods`first.elem = 0p;
    97109        wake_one( prods );
    98110    }
     
    102114static inline void is_closed( channel(T) & chan ) with(chan) { return closed; }
    103115
    104 // used to hand an element to a blocked consumer and signal it
    105 static inline void __cons_handoff( channel(T) & chan, T & elem ) with(chan) {
    106     memcpy( cons`first.extra, (void *)&elem, sizeof(T) ); // do waiting consumer work
    107     wake_one( cons );
    108 }
    109 
    110 // used to hand an element to a blocked producer and signal it
    111 static inline void __prods_handoff( channel(T) & chan, T & retval ) with(chan) {
    112     memcpy( (void *)&retval, prods`first.extra, sizeof(T) );
    113     wake_one( prods );
    114 }
    115 
    116116static inline void flush( channel(T) & chan, T elem ) with(chan) {
    117117    lock( mutex_lock );
    118118    while ( count == 0 && !cons`isEmpty ) {
    119         __cons_handoff( chan, elem );
     119        memcpy(cons`first.elem, (void *)&elem, sizeof(T)); // do waiting consumer work
     120        wake_one( cons );
    120121    }
    121122    unlock( mutex_lock );
     
    124125// handles buffer insert
    125126static inline void __buf_insert( channel(T) & chan, T & elem ) with(chan) {
    126     memcpy( (void *)&buffer[back], (void *)&elem, sizeof(T) );
     127    memcpy((void *)&buffer[back], (void *)&elem, sizeof(T));
    127128    count += 1;
    128129    back++;
     
    130131}
    131132
     133// does the buffer insert or hands elem directly to consumer if one is waiting
     134static inline void __do_insert( channel(T) & chan, T & elem ) with(chan) {
     135    if ( count == 0 && !cons`isEmpty ) {
     136        memcpy(cons`first.elem, (void *)&elem, sizeof(T)); // do waiting consumer work
     137        wake_one( cons );
     138    } else __buf_insert( chan, elem );
     139}
     140
    132141// needed to avoid an extra copy in closed case
    133142static inline bool __internal_try_insert( channel(T) & chan, T & elem ) with(chan) {
     
    136145    operations++;
    137146    #endif
    138 
    139     ConsEmpty: if ( !cons`isEmpty ) {
    140         if ( !__handle_waituntil_OR( cons ) ) break ConsEmpty;
    141         __cons_handoff( chan, elem );
    142         unlock( mutex_lock );
    143         return true;
    144     }
    145 
    146147    if ( count == size ) { unlock( mutex_lock ); return false; }
    147 
    148     __buf_insert( chan, elem );
     148    __do_insert( chan, elem );
    149149    unlock( mutex_lock );
    150150    return true;
     
    157157// handles closed case of insert routine
    158158static inline void __closed_insert( channel(T) & chan, T & elem ) with(chan) {
    159     channel_closed except{ &channel_closed_vt, &elem, &chan };
     159    channel_closed except{&channel_closed_vt, &elem, &chan };
    160160    throwResume except; // throw closed resumption
    161161    if ( !__internal_try_insert( chan, elem ) ) throw except; // if try to insert fails (would block), throw termination
     
    182182    }
    183183
    184     // buffer count must be zero if cons are blocked (also handles zero-size case)
    185     ConsEmpty: if ( !cons`isEmpty ) {
    186         if ( !__handle_waituntil_OR( cons ) ) break ConsEmpty;
    187         __cons_handoff( chan, elem );
     184    // have to check for the zero size channel case
     185    if ( size == 0 && !cons`isEmpty ) {
     186        memcpy(cons`first.elem, (void *)&elem, sizeof(T));
     187        wake_one( cons );
    188188        unlock( mutex_lock );
    189         return;
     189        return true;
    190190    }
    191191
     
    202202    } // if
    203203
    204     __buf_insert( chan, elem );
    205     unlock( mutex_lock );
     204    if ( count == 0 && !cons`isEmpty ) {
     205        memcpy(cons`first.elem, (void *)&elem, sizeof(T)); // do waiting consumer work
     206        wake_one( cons );
     207    } else __buf_insert( chan, elem );
     208   
     209    unlock( mutex_lock );
     210    return;
     211}
     212
     213// handles buffer remove
     214static inline void __buf_remove( channel(T) & chan, T & retval ) with(chan) {
     215    memcpy((void *)&retval, (void *)&buffer[front], sizeof(T));
     216    count -= 1;
     217    front = (front + 1) % size;
    206218}
    207219
    208220// does the buffer remove and potentially does waiting producer work
    209221static inline void __do_remove( channel(T) & chan, T & retval ) with(chan) {
    210     memcpy( (void *)&retval, (void *)&buffer[front], sizeof(T) );
    211     count -= 1;
    212     front = (front + 1) % size;
     222    __buf_remove( chan, retval );
    213223    if (count == size - 1 && !prods`isEmpty ) {
    214         if ( !__handle_waituntil_OR( prods ) ) return;
    215         __buf_insert( chan, *(T *)prods`first.extra );  // do waiting producer work
     224        __buf_insert( chan, *(T *)prods`first.elem );  // do waiting producer work
    216225        wake_one( prods );
    217226    }
     
    224233    operations++;
    225234    #endif
    226 
    227     ZeroSize: if ( size == 0 && !prods`isEmpty ) {
    228         if ( !__handle_waituntil_OR( prods ) ) break ZeroSize;
    229         __prods_handoff( chan, retval );
    230         unlock( mutex_lock );
    231         return true;
    232     }
    233 
    234235    if ( count == 0 ) { unlock( mutex_lock ); return false; }
    235 
    236236    __do_remove( chan, retval );
    237237    unlock( mutex_lock );
     
    244244static inline [T, bool] try_remove( channel(T) & chan ) {
    245245    T retval;
    246     bool success = __internal_try_remove( chan, retval );
    247     return [ retval, success ];
    248 }
    249 
    250 static inline T try_remove( channel(T) & chan ) {
     246    return [ retval, __internal_try_remove( chan, retval ) ];
     247}
     248
     249static inline T try_remove( channel(T) & chan, T elem ) {
    251250    T retval;
    252251    __internal_try_remove( chan, retval );
     
    256255// handles closed case of insert routine
    257256static inline void __closed_remove( channel(T) & chan, T & retval ) with(chan) {
    258     channel_closed except{ &channel_closed_vt, 0p, &chan };
     257    channel_closed except{&channel_closed_vt, 0p, &chan };
    259258    throwResume except; // throw resumption
    260259    if ( !__internal_try_remove( chan, retval ) ) throw except; // if try to remove fails (would block), throw termination
     
    280279
    281280    // have to check for the zero size channel case
    282     ZeroSize: if ( size == 0 && !prods`isEmpty ) {
    283         if ( !__handle_waituntil_OR( prods ) ) break ZeroSize;
    284         __prods_handoff( chan, retval );
     281    if ( size == 0 && !prods`isEmpty ) {
     282        memcpy((void *)&retval, (void *)prods`first.elem, sizeof(T));
     283        wake_one( prods );
    285284        unlock( mutex_lock );
    286285        return retval;
     
    288287
    289288    // wait if buffer is empty, work will be completed by someone else
    290     if ( count == 0 ) {
     289    if (count == 0) {
    291290        #ifdef CHAN_STATS
    292291        blocks++;
     
    300299    // Remove from buffer
    301300    __do_remove( chan, retval );
     301
    302302    unlock( mutex_lock );
    303303    return retval;
    304304}
    305 
    306 ///////////////////////////////////////////////////////////////////////////////////////////
    307 // The following is support for waituntil (select) statements
    308 ///////////////////////////////////////////////////////////////////////////////////////////
    309 static inline bool unregister_chan( channel(T) & chan, select_node & node ) with(chan) {
    310     if ( !node`isListed && !node.park_counter ) return false; // handle special OR case
    311     lock( mutex_lock );
    312     if ( node`isListed ) { // op wasn't performed
    313         #ifdef CHAN_STATS
    314         operations--;
    315         #endif
    316         remove( node );
    317         unlock( mutex_lock );
    318         return false;
    319     }
    320     unlock( mutex_lock );
    321 
    322     // only return true when not special OR case, not exceptional calse and status is SAT
    323     return ( node.extra == 0p || !node.park_counter ) ? false : *node.clause_status == __SELECT_SAT;
    324 }
    325 
    326 // type used by select statement to capture a chan read as the selected operation
    327 struct chan_read {
    328     channel(T) & chan;
    329     T & ret;
    330 };
    331 
    332 static inline void ?{}( chan_read(T) & cr, channel(T) & chan, T & ret ) {
    333     &cr.chan = &chan;
    334     &cr.ret = &ret;
    335 }
    336 static inline chan_read(T) ?<<?( T & ret, channel(T) & chan ) { chan_read(T) cr{ chan, ret }; return cr; }
    337 
    338 static inline void __handle_select_closed_read( chan_read(T) & this, select_node & node ) with(this.chan, this) {
    339     __closed_remove( chan, ret );
    340     // if we get here then the insert succeeded
    341     __make_select_node_available( node );
    342 }
    343 
    344 static inline bool register_select( chan_read(T) & this, select_node & node ) with(this.chan, this) {
    345     // mutex(sout) sout | "register_read";
    346     lock( mutex_lock );
    347     node.extra = &ret; // set .extra so that if it == 0p later in on_selected it is due to channel close
    348 
    349     #ifdef CHAN_STATS
    350     if ( !closed ) operations++;
    351     #endif
    352 
    353     // check if we can complete operation. If so race to establish winner in special OR case
    354     if ( !node.park_counter && ( count != 0 || !prods`isEmpty || unlikely(closed) ) ) {
    355         if ( !__make_select_node_available( node ) ) { // we didn't win the race so give up on registering
    356            unlock( mutex_lock );
    357            return false;
    358         }
    359     }
    360 
    361     if ( unlikely(closed) ) {
    362         unlock( mutex_lock );
    363         __handle_select_closed_read( this, node );
    364         return true;
    365     }
    366 
    367     // have to check for the zero size channel case
    368     ZeroSize: if ( size == 0 && !prods`isEmpty ) {
    369         if ( !__handle_waituntil_OR( prods ) ) break ZeroSize;
    370         __prods_handoff( chan, ret );
    371         __set_avail_then_unlock( node, mutex_lock );
    372         return true;
    373     }
    374 
    375     // wait if buffer is empty, work will be completed by someone else
    376     if ( count == 0 ) {
    377         #ifdef CHAN_STATS
    378         blocks++;
    379         #endif
    380        
    381         insert_last( cons, node );
    382         unlock( mutex_lock );
    383         return false;
    384     }
    385 
    386     // Remove from buffer
    387     __do_remove( chan, ret );
    388     __set_avail_then_unlock( node, mutex_lock );
    389     return true;
    390 }
    391 static inline bool unregister_select( chan_read(T) & this, select_node & node ) { return unregister_chan( this.chan, node ); }
    392 static inline bool on_selected( chan_read(T) & this, select_node & node ) with(this) {
    393     if ( node.extra == 0p ) // check if woken up due to closed channel
    394         __closed_remove( chan, ret );
    395     // This is only reachable if not closed or closed exception was handled
    396     return true;
    397 }
    398 
    399 // type used by select statement to capture a chan write as the selected operation
    400 struct chan_write {
    401     channel(T) & chan;
    402     T elem;
    403 };
    404 
    405 static inline void ?{}( chan_write(T) & cw, channel(T) & chan, T elem ) {
    406     &cw.chan = &chan;
    407     memcpy( (void *)&cw.elem, (void *)&elem, sizeof(T) );
    408 }
    409 static inline chan_write(T) ?>>?( T elem, channel(T) & chan ) { chan_write(T) cw{ chan, elem }; return cw; }
    410 
    411 static inline void __handle_select_closed_write( chan_write(T) & this, select_node & node ) with(this.chan, this) {
    412     __closed_insert( chan, elem );
    413     // if we get here then the insert succeeded
    414     __make_select_node_available( node );
    415 }
    416 
    417 static inline bool register_select( chan_write(T) & this, select_node & node ) with(this.chan, this) {
    418     // mutex(sout) sout | "register_write";
    419     lock( mutex_lock );
    420     node.extra = &elem; // set .extra so that if it == 0p later in on_selected it is due to channel close
    421 
    422     #ifdef CHAN_STATS
    423     if ( !closed ) operations++;
    424     #endif
    425 
    426     // check if we can complete operation. If so race to establish winner in special OR case
    427     if ( !node.park_counter && ( count != size || !cons`isEmpty || unlikely(closed) ) ) {
    428         if ( !__make_select_node_available( node ) ) { // we didn't win the race so give up on registering
    429            unlock( mutex_lock );
    430            return false;
    431         }
    432     }
    433 
    434     // if closed handle
    435     if ( unlikely(closed) ) {
    436         unlock( mutex_lock );
    437         __handle_select_closed_write( this, node );
    438         return true;
    439     }
    440 
    441     // handle blocked consumer case via handoff (buffer is implicitly empty)
    442     ConsEmpty: if ( !cons`isEmpty ) {
    443         if ( !__handle_waituntil_OR( cons ) ) {
    444             // mutex(sout) sout | "empty";
    445             break ConsEmpty;
    446         }
    447         // mutex(sout) sout | "signal";
    448         __cons_handoff( chan, elem );
    449         __set_avail_then_unlock( node, mutex_lock );
    450         return true;
    451     }
    452 
    453     // insert node in list if buffer is full, work will be completed by someone else
    454     if ( count == size ) {
    455         #ifdef CHAN_STATS
    456         blocks++;
    457         #endif
    458 
    459         insert_last( prods, node );
    460         unlock( mutex_lock );
    461         return false;
    462     } // if
    463 
    464     // otherwise carry out write either via normal insert
    465     __buf_insert( chan, elem );
    466     __set_avail_then_unlock( node, mutex_lock );
    467     return true;
    468 }
    469 static inline bool unregister_select( chan_write(T) & this, select_node & node ) { return unregister_chan( this.chan, node ); }
    470 
    471 static inline bool on_selected( chan_write(T) & this, select_node & node ) with(this) {
    472     if ( node.extra == 0p ) // check if woken up due to closed channel
    473         __closed_insert( chan, elem );
    474 
    475     // This is only reachable if not closed or closed exception was handled
    476     return true;
    477 }
    478 
    479 
    480305} // forall( T )
    481 
    482 
    483 
  • libcfa/src/concurrency/future.hfa

    rc083c3d r4daf79f  
    1919#include "monitor.hfa"
    2020#include "select.hfa"
    21 #include "locks.hfa"
    2221
    2322//----------------------------------------------------------------------------
     
    2726//  future_t is lockfree and uses atomics which aren't needed given we use locks here
    2827forall( T ) {
    29     // enum { FUTURE_EMPTY = 0, FUTURE_FULFILLED = 1 }; // Enums seem to be broken so feel free to add this back afterwards
     28    // enum(int) { FUTURE_EMPTY = 0, FUTURE_FULFILLED = 1 }; // Enums seem to be broken so feel free to add this back afterwards
    3029
    3130    // temporary enum replacement
     
    4544    };
    4645
     46    // C_TODO: perhaps allow exceptions to be inserted like uC++?
     47
    4748        static inline {
    4849
     
    8182        void _internal_flush( future(T) & this ) with(this) {
    8283            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
    8584                select_node &s = try_pop_front( waiters );
    8685
    87                 if ( s.clause_status == 0p )
     86                if ( s.race_flag == 0p )
    8887                    // 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 ( !__make_select_node_available( s ) ) continue;
     90                else if ( !install_select_winner( s, &this ) ) 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         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
     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
    167159            if( state == FUTURE_EMPTY ) {
    168160                insert_last( waiters, s );
    169161                unlock( lock );
    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;
     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) {
    180177            lock( lock );
    181178            if ( s`isListed ) remove( s );
    182179            unlock( lock );
    183             return false;
    184180        }
    185181               
    186         bool on_selected( future(T) & this, select_node & node ) { return true; }
    187182        }
    188183}
     
    191186// These futures below do not support select statements so they may not be as useful as 'future'
    192187//  however the 'single_future' is cheap and cheerful and is most likely more performant than 'future'
    193 //  since it uses raw atomics and no locks
     188//  since it uses raw atomics and no locks afaik
    194189//
    195190// As far as 'multi_future' goes I can't see many use cases as it will be less performant than 'future'
  • libcfa/src/concurrency/invoke.h

    rc083c3d r4daf79f  
    217217                struct __thread_user_link cltr_link;
    218218
     219                // used to point to this thd's current clh node
     220                volatile bool * clh_node;
     221
    219222                struct processor * last_proc;
    220 
    221         // ptr used during handover between blocking lists to allow for stack allocation of intrusive nodes
    222         // main use case is wait-morphing to allow a different node to be used to block on condvar vs lock
    223         void * link_node;
    224223
    225224                PRNG_STATE_T random_state;                                              // fast random numbers
  • libcfa/src/concurrency/locks.cfa

    rc083c3d r4daf79f  
    7979        // lock is held by some other thread
    8080        if ( owner != 0p && owner != thrd ) {
    81         select_node node;
    82                 insert_last( blocked_threads, node );
     81                insert_last( blocked_threads, *thrd );
    8382                wait_count++;
    8483                unlock( lock );
    8584                park( );
    86         return;
    87         } else if ( owner == thrd && multi_acquisition ) { // multi acquisition lock is held by current thread
     85        }
     86        // multi acquisition lock is held by current thread
     87        else if ( owner == thrd && multi_acquisition ) {
    8888                recursion_count++;
    89         } else {  // lock isn't held
     89                unlock( lock );
     90        }
     91        // lock isn't held
     92        else {
    9093                owner = thrd;
    9194                recursion_count = 1;
    92         }
    93     unlock( lock );
     95                unlock( lock );
     96        }
    9497}
    9598
     
    114117}
    115118
    116 // static void pop_and_set_new_owner( blocking_lock & this ) with( this ) {
    117 //      thread$ * t = &try_pop_front( blocked_threads );
    118 //      owner = t;
    119 //      recursion_count = ( t ? 1 : 0 );
    120 //      if ( t ) wait_count--;
    121 //      unpark( t );
    122 // }
    123 
    124 static inline void pop_node( blocking_lock & this ) with( this ) {
    125     __handle_waituntil_OR( blocked_threads );
    126     select_node * node = &try_pop_front( blocked_threads );
    127     if ( node ) {
    128         wait_count--;
    129         owner = node->blocked_thread;
    130         recursion_count = 1;
    131         // if ( !node->clause_status || __make_select_node_available( *node ) ) unpark( node->blocked_thread );
    132         wake_one( blocked_threads, *node );
    133     } else {
    134         owner = 0p;
    135         recursion_count = 0;
    136     }
     119static void pop_and_set_new_owner( blocking_lock & this ) with( this ) {
     120        thread$ * t = &try_pop_front( blocked_threads );
     121        owner = t;
     122        recursion_count = ( t ? 1 : 0 );
     123        if ( t ) wait_count--;
     124        unpark( t );
    137125}
    138126
     
    146134        recursion_count--;
    147135        if ( recursion_count == 0 ) {
    148                 pop_node( this );
     136                pop_and_set_new_owner( this );
    149137        }
    150138        unlock( lock );
     
    159147        // lock held
    160148        if ( owner != 0p ) {
    161                 insert_last( blocked_threads, *(select_node *)t->link_node );
     149                insert_last( blocked_threads, *t );
    162150                wait_count++;
     151                unlock( lock );
    163152        }
    164153        // lock not held
     
    167156                recursion_count = 1;
    168157                unpark( t );
    169         }
    170     unlock( lock );
     158                unlock( lock );
     159        }
    171160}
    172161
     
    178167        size_t ret = recursion_count;
    179168
    180         pop_node( this );
    181 
    182     select_node node;
    183     active_thread()->link_node = (void *)&node;
     169        pop_and_set_new_owner( this );
    184170        unlock( lock );
    185 
    186     park();
    187 
    188171        return ret;
    189172}
     
    192175        recursion_count = recursion;
    193176}
    194 
    195 // waituntil() support
    196 bool register_select( blocking_lock & this, select_node & node ) with(this) {
    197     lock( lock __cfaabi_dbg_ctx2 );
    198         thread$ * thrd = active_thread();
    199 
    200         // single acquisition lock is held by current thread
    201         /* paranoid */ verifyf( owner != thrd || multi_acquisition, "Single acquisition lock holder (%p) attempted to reacquire the lock %p resulting in a deadlock.", owner, &this );
    202 
    203     if ( !node.park_counter && ( (owner == thrd && multi_acquisition) || owner == 0p ) ) { // OR special case
    204         if ( !__make_select_node_available( node ) ) { // we didn't win the race so give up on registering
    205            unlock( lock );
    206            return false;
    207         }
    208     }
    209 
    210         // lock is held by some other thread
    211         if ( owner != 0p && owner != thrd ) {
    212                 insert_last( blocked_threads, node );
    213                 wait_count++;
    214                 unlock( lock );
    215         return false;
    216         } else if ( owner == thrd && multi_acquisition ) { // multi acquisition lock is held by current thread
    217                 recursion_count++;
    218         } else {  // lock isn't held
    219                 owner = thrd;
    220                 recursion_count = 1;
    221         }
    222 
    223     if ( node.park_counter ) __make_select_node_available( node );
    224     unlock( lock );
    225     return true;
    226 }
    227 
    228 bool unregister_select( blocking_lock & this, select_node & node ) with(this) {
    229     lock( lock __cfaabi_dbg_ctx2 );
    230     if ( node`isListed ) {
    231         remove( node );
    232         wait_count--;
    233         unlock( lock );
    234         return false;
    235     }
    236    
    237     if ( owner == active_thread() ) {
    238         /* paranoid */ verifyf( recursion_count == 1 || multi_acquisition, "Thread %p attempted to unlock owner lock %p in waituntil unregister, which is not recursive but has a recursive count of %zu", active_thread(), &this, recursion_count );
    239         // if recursion count is zero release lock and set new owner if one is waiting
    240         recursion_count--;
    241         if ( recursion_count == 0 ) {
    242             pop_node( this );
    243         }
    244     }
    245         unlock( lock );
    246     return false;
    247 }
    248 
    249 bool on_selected( blocking_lock & this, select_node & node ) { return true; }
    250177
    251178//-----------------------------------------------------------------------------
     
    384311        int counter( condition_variable(L) & this ) with(this) { return count; }
    385312
    386         static void enqueue_thread( condition_variable(L) & this, info_thread(L) * i ) with(this) {
     313        static size_t queue_and_get_recursion( condition_variable(L) & this, info_thread(L) * i ) with(this) {
    387314                // add info_thread to waiting queue
    388315                insert_last( blocked_threads, *i );
    389316                count++;
    390                 // size_t recursion_count = 0;
    391                 // if (i->lock) {
    392                 //      // if lock was passed get recursion count to reset to after waking thread
    393                 //      recursion_count = on_wait( *i->lock );
    394                 // }
    395                 // return recursion_count;
    396         }
    397 
    398     static size_t block_and_get_recursion( info_thread(L) & i ) {
    399         size_t recursion_count = 0;
    400                 if ( i.lock ) {
     317                size_t recursion_count = 0;
     318                if (i->lock) {
    401319                        // if lock was passed get recursion count to reset to after waking thread
    402                         recursion_count = on_wait( *i.lock ); // this call blocks
    403                 } else park( );
    404         return recursion_count;
    405     }
     320                        recursion_count = on_wait( *i->lock );
     321                }
     322                return recursion_count;
     323        }
    406324
    407325        // helper for wait()'s' with no timeout
    408326        static void queue_info_thread( condition_variable(L) & this, info_thread(L) & i ) with(this) {
    409327                lock( lock __cfaabi_dbg_ctx2 );
    410         enqueue_thread( this, &i );
    411                 // size_t recursion_count = queue_and_get_recursion( this, &i );
     328                size_t recursion_count = queue_and_get_recursion(this, &i);
    412329                unlock( lock );
    413330
    414331                // blocks here
    415         size_t recursion_count = block_and_get_recursion( i );
    416                 // park( );
     332                park( );
    417333
    418334                // resets recursion count here after waking
    419                 if ( i.lock ) on_wakeup( *i.lock, recursion_count );
     335                if (i.lock) on_wakeup(*i.lock, recursion_count);
    420336        }
    421337
     
    427343        static void queue_info_thread_timeout( condition_variable(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {
    428344                lock( lock __cfaabi_dbg_ctx2 );
    429         enqueue_thread( this, &info );
    430                 // size_t recursion_count = queue_and_get_recursion( this, &info );
     345                size_t recursion_count = queue_and_get_recursion(this, &info);
    431346                alarm_node_wrap(L) node_wrap = { t, 0`s, callback, &this, &info };
    432347                unlock( lock );
     
    436351
    437352                // blocks here
    438         size_t recursion_count = block_and_get_recursion( info );
    439                 // park();
     353                park();
    440354
    441355                // unregisters alarm so it doesn't go off if this happens first
     
    443357
    444358                // resets recursion count here after waking
    445                 if ( info.lock ) on_wakeup( *info.lock, recursion_count );
     359                if (info.lock) on_wakeup(*info.lock, recursion_count);
    446360        }
    447361
     
    503417                info_thread( L ) i = { active_thread(), info, &l };
    504418                insert_last( blocked_threads, i );
    505                 size_t recursion_count = on_wait( *i.lock ); // blocks here
    506                 // park( );
     419                size_t recursion_count = on_wait( *i.lock );
     420                park( );
    507421                on_wakeup(*i.lock, recursion_count);
    508422        }
     
    545459        bool empty ( pthread_cond_var(L) & this ) with(this) { return blocked_threads`isEmpty; }
    546460
    547         // static size_t queue_and_get_recursion( pthread_cond_var(L) & this, info_thread(L) * i ) with(this) {
    548         //      // add info_thread to waiting queue
    549         //      insert_last( blocked_threads, *i );
    550         //      size_t recursion_count = 0;
    551         //      recursion_count = on_wait( *i->lock );
    552         //      return recursion_count;
    553         // }
    554 
     461        static size_t queue_and_get_recursion( pthread_cond_var(L) & this, info_thread(L) * i ) with(this) {
     462                // add info_thread to waiting queue
     463                insert_last( blocked_threads, *i );
     464                size_t recursion_count = 0;
     465                recursion_count = on_wait( *i->lock );
     466                return recursion_count;
     467        }
    555468       
    556469        static void queue_info_thread_timeout( pthread_cond_var(L) & this, info_thread(L) & info, Duration t, Alarm_Callback callback ) with(this) {
    557470                lock( lock __cfaabi_dbg_ctx2 );
    558                 // size_t recursion_count = queue_and_get_recursion(this, &info);
    559         insert_last( blocked_threads, info );
     471                size_t recursion_count = queue_and_get_recursion(this, &info);
    560472                pthread_alarm_node_wrap(L) node_wrap = { t, 0`s, callback, &this, &info };
    561473                unlock( lock );
     
    565477
    566478                // blocks here
    567         size_t recursion_count = block_and_get_recursion( info );
    568                 // park();
     479                park();
    569480
    570481                // unregisters alarm so it doesn't go off if this happens first
     
    572483
    573484                // resets recursion count here after waking
    574                 if ( info.lock ) on_wakeup( *info.lock, recursion_count );
     485                if (info.lock) on_wakeup(*info.lock, recursion_count);
    575486        }
    576487
     
    582493                lock( lock __cfaabi_dbg_ctx2 );
    583494                info_thread( L ) i = { active_thread(), info, &l };
    584         insert_last( blocked_threads, i );
    585                 // size_t recursion_count = queue_and_get_recursion( this, &i );
    586                 unlock( lock );
    587 
    588         // blocks here
    589                 size_t recursion_count = block_and_get_recursion( i );
    590                 // park();
    591                 on_wakeup( *i.lock, recursion_count );
     495                size_t recursion_count = queue_and_get_recursion(this, &i);
     496                unlock( lock );
     497                park( );
     498                on_wakeup(*i.lock, recursion_count);
    592499        }
    593500
  • libcfa/src/concurrency/locks.hfa

    rc083c3d r4daf79f  
    3030#include "time.hfa"
    3131
    32 #include "select.hfa"
    33 
    3432#include <fstream.hfa>
    3533
     
    7270static inline void   on_wakeup( single_acquisition_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    7371static inline void   on_notify( single_acquisition_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); }
    74 static inline bool   register_select( single_acquisition_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }
    75 static inline bool   unregister_select( single_acquisition_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }
    76 static inline bool   on_selected( single_acquisition_lock & this, select_node & node ) { return on_selected( (blocking_lock &)this, node ); }
    7772
    7873//----------
     
    8984static inline void   on_wakeup( owner_lock & this, size_t v ) { on_wakeup ( (blocking_lock &)this, v ); }
    9085static inline void   on_notify( owner_lock & this, struct thread$ * t ) { on_notify( (blocking_lock &)this, t ); }
    91 static inline bool   register_select( owner_lock & this, select_node & node ) { return register_select( (blocking_lock &)this, node ); }
    92 static inline bool   unregister_select( owner_lock & this, select_node & node ) { return unregister_select( (blocking_lock &)this, node ); }
    93 static inline bool   on_selected( owner_lock & this, select_node & node ) { return on_selected( (blocking_lock &)this, node ); }
    9486
    9587//-----------------------------------------------------------------------------
     
    188180
    189181// if this is called recursively IT WILL DEADLOCK!!!!!
    190 static inline void lock( futex_mutex & this ) with(this) {
     182static inline void lock(futex_mutex & this) with(this) {
    191183        int state;
    192184
     
    198190                for (int i = 0; i < spin; i++) Pause();
    199191        }
     192
     193        // // no contention try to acquire
     194        // if (internal_try_lock(this, state)) return;
    200195       
    201196        // if not in contended state, set to be in contended state
     
    218213
    219214static inline void on_notify( futex_mutex & f, thread$ * t){ unpark(t); }
    220 static inline size_t on_wait( futex_mutex & f ) { unlock(f); park(); return 0; }
     215static inline size_t on_wait( futex_mutex & f ) {unlock(f); return 0;}
    221216
    222217// to set recursion count after getting signalled;
     
    249244
    250245// if this is called recursively IT WILL DEADLOCK!!!!!
    251 static inline void lock( go_mutex & this ) with( this ) {
     246static inline void lock(go_mutex & this) with(this) {
    252247        int state, init_state;
    253248
     
    260255            while( !val ) { // lock unlocked
    261256                state = 0;
    262                 if ( internal_try_lock( this, state, init_state ) ) return;
     257                if (internal_try_lock(this, state, init_state)) return;
    263258            }
    264259            for (int i = 0; i < 30; i++) Pause();
     
    267262        while( !val ) { // lock unlocked
    268263            state = 0;
    269             if ( internal_try_lock( this, state, init_state ) ) return;
     264            if (internal_try_lock(this, state, init_state)) return;
    270265        }
    271266        sched_yield();
    272267       
    273268        // if not in contended state, set to be in contended state
    274         state = internal_exchange( this, 2 );
     269        state = internal_exchange(this, 2);
    275270        if ( !state ) return; // state == 0
    276271        init_state = 2;
    277         futex( (int*)&val, FUTEX_WAIT, 2 ); // if val is not 2 this returns with EWOULDBLOCK
     272        futex((int*)&val, FUTEX_WAIT, 2); // if val is not 2 this returns with EWOULDBLOCK
    278273    }
    279274}
     
    281276static inline void unlock( go_mutex & this ) with(this) {
    282277        // if uncontended do atomic unlock and then return
    283     if ( __atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1 ) return;
     278    if (__atomic_exchange_n(&val, 0, __ATOMIC_RELEASE) == 1) return;
    284279       
    285280        // otherwise threads are blocked so we must wake one
    286         futex( (int *)&val, FUTEX_WAKE, 1 );
    287 }
    288 
    289 static inline void on_notify( go_mutex & f, thread$ * t){ unpark( t ); }
    290 static inline size_t on_wait( go_mutex & f ) { unlock( f ); park(); return 0; }
     281        futex((int *)&val, FUTEX_WAKE, 1);
     282}
     283
     284static inline void on_notify( go_mutex & f, thread$ * t){ unpark(t); }
     285static inline size_t on_wait( go_mutex & f ) {unlock(f); return 0;}
    291286static inline void on_wakeup( go_mutex & f, size_t recursion ) {}
     287
     288//-----------------------------------------------------------------------------
     289// CLH Spinlock
     290// - No recursive acquisition
     291// - Needs to be released by owner
     292
     293struct clh_lock {
     294        volatile bool * volatile tail;
     295    volatile bool * volatile head;
     296};
     297
     298static inline void  ?{}( clh_lock & this ) { this.tail = malloc(); *this.tail = true; }
     299static inline void ^?{}( clh_lock & this ) { free(this.tail); }
     300
     301static inline void lock(clh_lock & l) {
     302        thread$ * curr_thd = active_thread();
     303        *(curr_thd->clh_node) = false;
     304        volatile bool * prev = __atomic_exchange_n((bool **)(&l.tail), (bool *)(curr_thd->clh_node), __ATOMIC_SEQ_CST);
     305        while(!__atomic_load_n(prev, __ATOMIC_SEQ_CST)) Pause();
     306    __atomic_store_n((bool **)(&l.head), (bool *)curr_thd->clh_node, __ATOMIC_SEQ_CST);
     307    curr_thd->clh_node = prev;
     308}
     309
     310static inline void unlock(clh_lock & l) {
     311        __atomic_store_n((bool *)(l.head), true, __ATOMIC_SEQ_CST);
     312}
     313
     314static inline void on_notify(clh_lock & this, struct thread$ * t ) { unpark(t); }
     315static inline size_t on_wait(clh_lock & this) { unlock(this); return 0; }
     316static inline void on_wakeup(clh_lock & this, size_t recursion ) { lock(this); }
    292317
    293318//-----------------------------------------------------------------------------
     
    312337static inline void  ^?{}( exp_backoff_then_block_lock & this ){}
    313338
    314 static inline bool internal_try_lock( exp_backoff_then_block_lock & this, size_t & compare_val ) with(this) {
     339static inline bool internal_try_lock(exp_backoff_then_block_lock & this, size_t & compare_val) with(this) {
    315340        return __atomic_compare_exchange_n(&lock_value, &compare_val, 1, false, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
    316341}
    317342
    318 static inline bool try_lock( exp_backoff_then_block_lock & this ) { size_t compare_val = 0; return internal_try_lock( this, compare_val ); }
    319 
    320 static inline bool try_lock_contention( exp_backoff_then_block_lock & this ) with(this) {
    321         return !__atomic_exchange_n( &lock_value, 2, __ATOMIC_ACQUIRE );
    322 }
    323 
    324 static inline bool block( exp_backoff_then_block_lock & this ) with(this) {
     343static inline bool try_lock(exp_backoff_then_block_lock & this) { size_t compare_val = 0; return internal_try_lock(this, compare_val); }
     344
     345static inline bool try_lock_contention(exp_backoff_then_block_lock & this) with(this) {
     346        return !__atomic_exchange_n(&lock_value, 2, __ATOMIC_ACQUIRE);
     347}
     348
     349static inline bool block(exp_backoff_then_block_lock & this) with(this) {
    325350    lock( spinlock __cfaabi_dbg_ctx2 );
    326351    if (__atomic_load_n( &lock_value, __ATOMIC_SEQ_CST) != 2) {
     
    334359}
    335360
    336 static inline void lock( exp_backoff_then_block_lock & this ) with(this) {
     361static inline void lock(exp_backoff_then_block_lock & this) with(this) {
    337362        size_t compare_val = 0;
    338363        int spin = 4;
     
    353378}
    354379
    355 static inline void unlock( exp_backoff_then_block_lock & this ) with(this) {
     380static inline void unlock(exp_backoff_then_block_lock & this) with(this) {
    356381    if (__atomic_exchange_n(&lock_value, 0, __ATOMIC_RELEASE) == 1) return;
    357382    lock( spinlock __cfaabi_dbg_ctx2 );
     
    361386}
    362387
    363 static inline void on_notify( exp_backoff_then_block_lock & this, struct thread$ * t ) { unpark( t ); }
    364 static inline size_t on_wait( exp_backoff_then_block_lock & this ) { unlock( this ); park(); return 0; }
    365 static inline void on_wakeup( exp_backoff_then_block_lock & this, size_t recursion ) { lock( this ); }
     388static inline void on_notify(exp_backoff_then_block_lock & this, struct thread$ * t ) { unpark(t); }
     389static inline size_t on_wait(exp_backoff_then_block_lock & this) { unlock(this); return 0; }
     390static inline void on_wakeup(exp_backoff_then_block_lock & this, size_t recursion ) { lock(this); }
    366391
    367392//-----------------------------------------------------------------------------
     
    393418
    394419// if this is called recursively IT WILL DEADLOCK!!!!!
    395 static inline void lock( fast_block_lock & this ) with(this) {
     420static inline void lock(fast_block_lock & this) with(this) {
    396421        lock( lock __cfaabi_dbg_ctx2 );
    397422        if ( held ) {
     
    405430}
    406431
    407 static inline void unlock( fast_block_lock & this ) with(this) {
     432static inline void unlock(fast_block_lock & this) with(this) {
    408433        lock( lock __cfaabi_dbg_ctx2 );
    409434        /* paranoid */ verifyf( held != false, "Attempt to release lock %p that isn't held", &this );
     
    414439}
    415440
    416 static inline void on_notify( fast_block_lock & this, struct thread$ * t ) with(this) {
     441static inline void on_notify(fast_block_lock & this, struct thread$ * t ) with(this) {
    417442    lock( lock __cfaabi_dbg_ctx2 );
    418443    insert_last( blocked_threads, *t );
    419444    unlock( lock );
    420445}
    421 static inline size_t on_wait( fast_block_lock & this) { unlock(this); park(); return 0; }
    422 static inline void on_wakeup( fast_block_lock & this, size_t recursion ) { }
     446static inline size_t on_wait(fast_block_lock & this) { unlock(this); return 0; }
     447static inline void on_wakeup(fast_block_lock & this, size_t recursion ) { }
    423448
    424449//-----------------------------------------------------------------------------
     
    431456struct simple_owner_lock {
    432457        // List of blocked threads
    433         dlist( select_node ) blocked_threads;
     458        dlist( thread$ ) blocked_threads;
    434459
    435460        // Spin lock used for mutual exclusion
     
    452477static inline void ?=?( simple_owner_lock & this, simple_owner_lock this2 ) = void;
    453478
    454 static inline void lock( simple_owner_lock & this ) with(this) {
    455         if ( owner == active_thread() ) {
     479static inline void lock(simple_owner_lock & this) with(this) {
     480        if (owner == active_thread()) {
    456481                recursion_count++;
    457482                return;
     
    459484        lock( lock __cfaabi_dbg_ctx2 );
    460485
    461         if ( owner != 0p ) {
    462         select_node node;
    463                 insert_last( blocked_threads, node );
     486        if (owner != 0p) {
     487                insert_last( blocked_threads, *active_thread() );
    464488                unlock( lock );
    465489                park( );
     
    471495}
    472496
    473 static inline void pop_node( simple_owner_lock & this ) with(this) {
    474     __handle_waituntil_OR( blocked_threads );
    475     select_node * node = &try_pop_front( blocked_threads );
    476     if ( node ) {
    477         owner = node->blocked_thread;
    478         recursion_count = 1;
    479         // if ( !node->clause_status || __make_select_node_available( *node ) ) unpark( node->blocked_thread );
    480         wake_one( blocked_threads, *node );
    481     } else {
    482         owner = 0p;
    483         recursion_count = 0;
    484     }
    485 }
    486 
    487 static inline void unlock( simple_owner_lock & this ) with(this) {
     497// TODO: fix duplicate def issue and bring this back
     498// void pop_and_set_new_owner( simple_owner_lock & this ) with( this ) {
     499        // thread$ * t = &try_pop_front( blocked_threads );
     500        // owner = t;
     501        // recursion_count = ( t ? 1 : 0 );
     502        // unpark( t );
     503// }
     504
     505static inline void unlock(simple_owner_lock & this) with(this) {
    488506        lock( lock __cfaabi_dbg_ctx2 );
    489507        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
     
    492510        recursion_count--;
    493511        if ( recursion_count == 0 ) {
    494                 pop_node( this );
     512                // pop_and_set_new_owner( this );
     513                thread$ * t = &try_pop_front( blocked_threads );
     514                owner = t;
     515                recursion_count = ( t ? 1 : 0 );
     516                unpark( t );
    495517        }
    496518        unlock( lock );
    497519}
    498520
    499 static inline void on_notify(simple_owner_lock & this, thread$ * t ) with(this) {
     521static inline void on_notify(simple_owner_lock & this, struct thread$ * t ) with(this) {
    500522        lock( lock __cfaabi_dbg_ctx2 );
    501523        // lock held
    502524        if ( owner != 0p ) {
    503                 insert_last( blocked_threads, *(select_node *)t->link_node );
     525                insert_last( blocked_threads, *t );
    504526        }
    505527        // lock not held
     
    512534}
    513535
    514 static inline size_t on_wait( simple_owner_lock & this ) with(this) {
     536static inline size_t on_wait(simple_owner_lock & this) with(this) {
    515537        lock( lock __cfaabi_dbg_ctx2 );
    516538        /* paranoid */ verifyf( owner != 0p, "Attempt to release lock %p that isn't held", &this );
     
    519541        size_t ret = recursion_count;
    520542
    521         pop_node( this );
    522 
    523     select_node node;
    524     active_thread()->link_node = (void *)&node;
     543        // pop_and_set_new_owner( this );
     544
     545        thread$ * t = &try_pop_front( blocked_threads );
     546        owner = t;
     547        recursion_count = ( t ? 1 : 0 );
     548        unpark( t );
     549
    525550        unlock( lock );
    526     park();
    527 
    528551        return ret;
    529552}
    530553
    531 static inline void on_wakeup( simple_owner_lock & this, size_t recursion ) with(this) { recursion_count = recursion; }
    532 
    533 // waituntil() support
    534 static inline bool register_select( simple_owner_lock & this, select_node & node ) with(this) {
    535     lock( lock __cfaabi_dbg_ctx2 );
    536 
    537     // check if we can complete operation. If so race to establish winner in special OR case
    538     if ( !node.park_counter && ( owner == active_thread() || owner == 0p ) ) {
    539         if ( !__make_select_node_available( node ) ) { // we didn't win the race so give up on registering
    540            unlock( lock );
    541            return false;
    542         }
    543     }
    544 
    545     if ( owner == active_thread() ) {
    546                 recursion_count++;
    547         if ( node.park_counter ) __make_select_node_available( node );
    548         unlock( lock );
    549                 return true;
    550         }
    551 
    552     if ( owner != 0p ) {
    553                 insert_last( blocked_threads, node );
    554                 unlock( lock );
    555                 return false;
    556         }
    557    
    558         owner = active_thread();
    559         recursion_count = 1;
    560 
    561     if ( node.park_counter ) __make_select_node_available( node );
    562     unlock( lock );
    563     return true;
    564 }
    565 
    566 static inline bool unregister_select( simple_owner_lock & this, select_node & node ) with(this) {
    567     lock( lock __cfaabi_dbg_ctx2 );
    568     if ( node`isListed ) {
    569         remove( node );
    570         unlock( lock );
    571         return false;
    572     }
    573 
    574     if ( owner == active_thread() ) {
    575         recursion_count--;
    576         if ( recursion_count == 0 ) {
    577             pop_node( this );
    578         }
    579     }
    580     unlock( lock );
    581     return false;
    582 }
    583 
    584 static inline bool on_selected( simple_owner_lock & this, select_node & node ) { return true; }
    585 
     554static inline void on_wakeup(simple_owner_lock & this, size_t recursion ) with(this) { recursion_count = recursion; }
    586555
    587556//-----------------------------------------------------------------------------
     
    609578
    610579// if this is called recursively IT WILL DEADLOCK!
    611 static inline void lock( spin_queue_lock & this ) with(this) {
     580static inline void lock(spin_queue_lock & this) with(this) {
    612581        mcs_spin_node node;
    613582        lock( lock, node );
     
    617586}
    618587
    619 static inline void unlock( spin_queue_lock & this ) with(this) {
     588static inline void unlock(spin_queue_lock & this) with(this) {
    620589        __atomic_store_n(&held, false, __ATOMIC_RELEASE);
    621590}
    622591
    623 static inline void on_notify( spin_queue_lock & this, struct thread$ * t ) {
     592static inline void on_notify(spin_queue_lock & this, struct thread$ * t ) {
    624593        unpark(t);
    625594}
    626 static inline size_t on_wait( spin_queue_lock & this ) { unlock( this ); park(); return 0; }
    627 static inline void on_wakeup( spin_queue_lock & this, size_t recursion ) { lock( this ); }
     595static inline size_t on_wait(spin_queue_lock & this) { unlock(this); return 0; }
     596static inline void on_wakeup(spin_queue_lock & this, size_t recursion ) { lock(this); }
    628597
    629598
     
    652621
    653622// if this is called recursively IT WILL DEADLOCK!!!!!
    654 static inline void lock( mcs_block_spin_lock & this ) with(this) {
     623static inline void lock(mcs_block_spin_lock & this) with(this) {
    655624        mcs_node node;
    656625        lock( lock, node );
     
    664633}
    665634
    666 static inline void on_notify( mcs_block_spin_lock & this, struct thread$ * t ) { unpark( t ); }
    667 static inline size_t on_wait( mcs_block_spin_lock & this) { unlock( this ); park(); return 0; }
    668 static inline void on_wakeup( mcs_block_spin_lock & this, size_t recursion ) {lock( this ); }
     635static inline void on_notify(mcs_block_spin_lock & this, struct thread$ * t ) { unpark(t); }
     636static inline size_t on_wait(mcs_block_spin_lock & this) { unlock(this); return 0; }
     637static inline void on_wakeup(mcs_block_spin_lock & this, size_t recursion ) {lock(this); }
    669638
    670639//-----------------------------------------------------------------------------
     
    692661
    693662// if this is called recursively IT WILL DEADLOCK!!!!!
    694 static inline void lock( block_spin_lock & this ) with(this) {
     663static inline void lock(block_spin_lock & this) with(this) {
    695664        lock( lock );
    696665        while(__atomic_load_n(&held, __ATOMIC_SEQ_CST)) Pause();
     
    699668}
    700669
    701 static inline void unlock( block_spin_lock & this ) with(this) {
     670static inline void unlock(block_spin_lock & this) with(this) {
    702671        __atomic_store_n(&held, false, __ATOMIC_RELEASE);
    703672}
    704673
    705 static inline void on_notify( block_spin_lock & this, struct thread$ * t ) with(this.lock) {
     674static inline void on_notify(block_spin_lock & this, struct thread$ * t ) with(this.lock) {
    706675        // first we acquire internal fast_block_lock
    707676        lock( lock __cfaabi_dbg_ctx2 );
     
    717686        unpark(t);
    718687}
    719 static inline size_t on_wait( block_spin_lock & this ) { unlock( this ); park(); return 0; }
    720 static inline void on_wakeup( block_spin_lock & this, size_t recursion ) with(this) {
     688static inline size_t on_wait(block_spin_lock & this) { unlock(this); return 0; }
     689static inline void on_wakeup(block_spin_lock & this, size_t recursion ) with(this) {
    721690        // now we acquire the entire block_spin_lock upon waking up
    722691        while(__atomic_load_n(&held, __ATOMIC_SEQ_CST)) Pause();
     
    745714forall(L & | is_blocking_lock(L)) {
    746715        struct info_thread;
     716
     717        // // for use by sequence
     718        // info_thread(L) *& Back( info_thread(L) * this );
     719        // info_thread(L) *& Next( info_thread(L) * this );
    747720}
    748721
  • libcfa/src/concurrency/mutex_stmt.hfa

    rc083c3d r4daf79f  
    1515};
    1616
     17
    1718struct __mutex_stmt_lock_guard {
    1819    void ** lockarr;
     
    2930
    3031forall(L & | is_lock(L)) {
    31     static inline void * __get_mutexstmt_lock_ptr( L & this ) { return &this; }
    32     static inline L __get_mutexstmt_lock_type( L & this ) {}
    33     static inline L __get_mutexstmt_lock_type( L * this ) {}
     32
     33    struct scoped_lock {
     34        L * internal_lock;
     35    };
     36
     37    static inline void ?{}( scoped_lock(L) & this, L & internal_lock ) {
     38        this.internal_lock = &internal_lock;
     39        lock(internal_lock);
     40    }
     41   
     42    static inline void ^?{}( scoped_lock(L) & this ) with(this) {
     43        unlock(*internal_lock);
     44    }
     45
     46    static inline void * __get_mutexstmt_lock_ptr( L & this ) {
     47        return &this;
     48    }
     49
     50    static inline L __get_mutexstmt_lock_type( L & this );
     51
     52    static inline L __get_mutexstmt_lock_type( L * this );
    3453}
  • libcfa/src/concurrency/select.hfa

    rc083c3d r4daf79f  
    22
    33#include "containers/list.hfa"
    4 #include "stdint.h"
    5 #include "kernel.hfa"
     4#include <stdint.h>
     5#include <kernel.hfa>
     6#include <locks.hfa>
    67
    7 struct select_node;
    8 
    9 // node status
    10 static const unsigned long int __SELECT_UNSAT = 0;
    11 static const unsigned long int __SELECT_SAT = 1;
    12 static const unsigned long int __SELECT_RUN = 2;
    13 
    14 static inline bool __CFA_has_clause_run( unsigned long int status ) { return status == __SELECT_RUN; }
    15 static inline void __CFA_maybe_park( int * park_counter ) {
    16     if ( __atomic_sub_fetch( park_counter, 1, __ATOMIC_SEQ_CST) < 0 )
    17         park();
    18 }
    19 
    20 // node used for coordinating waituntil synchronization
    218struct select_node {
    22     int * park_counter;                 // If this is 0p then the node is in a special OR case waituntil
    23     unsigned long int * clause_status;  // needs to point at ptr sized location, if this is 0p then node is not part of a waituntil
    24 
    25     void * extra;                       // used to store arbitrary data needed by some primitives
    26 
    279    thread$ * blocked_thread;
     10    void ** race_flag;
    2811    inline dlink(select_node);
    2912};
    3013P9_EMBEDDED( select_node, dlink(select_node) )
    3114
    32 static inline void ?{}( select_node & this ) {
    33     this.blocked_thread = active_thread();
    34     this.clause_status = 0p;
    35     this.park_counter = 0p;
    36     this.extra = 0p;
     15void ?{}( select_node & this ) {
     16    this.blocked_thread = 0p;
     17    this.race_flag = 0p;
    3718}
    3819
    39 static inline void ?{}( select_node & this, thread$ * blocked_thread ) {
     20void ?{}( select_node & this, thread$ * blocked_thread ) {
    4021    this.blocked_thread = blocked_thread;
    41     this.clause_status = 0p;
    42     this.park_counter = 0p;
    43     this.extra = 0p;
     22    this.race_flag = 0p;
    4423}
    4524
    46 static inline void ?{}( select_node & this, thread$ * blocked_thread, void * extra ) {
     25void ?{}( select_node & this, thread$ * blocked_thread, void ** race_flag ) {
    4726    this.blocked_thread = blocked_thread;
    48     this.clause_status = 0p;
    49     this.park_counter = 0p;
    50     this.extra = extra;
     27    this.race_flag = race_flag;
    5128}
    5229
    53 static inline void ^?{}( select_node & this ) {}
     30void ^?{}( select_node & this ) {}
    5431
    55 static inline unsigned long int * __get_clause_status( select_node & s ) { return s.clause_status; }
    5632
    5733//-----------------------------------------------------------------------------
    5834// is_selectable
    59 forall(T & | sized(T))
    60 trait is_selectable {
    61     // For registering a select stmt on a selectable concurrency primitive
    62     // Returns bool that indicates if operation is already SAT
    63     bool register_select( T &, select_node & );
     35trait is_selectable(T & | sized(T)) {
     36    // For registering a select on a selectable concurrency primitive
     37    // return 0p if primitive not accessible yet
     38    // return 1p if primitive gets acquired
     39    // return 2p if primitive is accessible but some other primitive won the race
     40    // C_TODO: add enum for return values
     41    void * register_select( T &, select_node & );
    6442
    65     // For unregistering a select stmt on a selectable concurrency primitive
    66     // 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)
    67     bool unregister_select( T &, select_node &  );
    68 
    69     // This routine is run on the selecting thread prior to executing the statement corresponding to the select_node
    70     //    passed as an arg to this routine
    71     // If on_selected returns false, the statement is not run, if it returns true it is run.
    72     bool on_selected( T &, select_node & );
     43    void unregister_select( T &, select_node &  );
    7344};
    7445
    75 // this is used inside the compiler to attempt to establish an else clause as a winner in the OR special case race
    76 static inline bool __select_node_else_race( select_node & this ) with( this ) {
    77     unsigned long int cmp_status = __SELECT_UNSAT;
    78     return *clause_status == 0
    79             && __atomic_compare_exchange_n( clause_status, &cmp_status, 1, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST );
     46static inline bool install_select_winner( select_node & this, void * primitive_ptr ) with(this) {
     47    // temporary needed for atomic instruction
     48    void * cmp_flag = 0p;
     49   
     50    // if we dont win the selector race we need to potentially
     51    //   ignore this node and move to the next one so we return accordingly
     52    if ( *race_flag != 0p ||
     53        !__atomic_compare_exchange_n(
     54            race_flag,
     55            &cmp_flag,
     56            primitive_ptr,
     57            false,
     58            __ATOMIC_SEQ_CST,
     59            __ATOMIC_SEQ_CST
     60        )
     61    ) return false; // lost race and some other node triggered select
     62    return true; // won race so this node is what the select proceeds with
    8063}
    81 
    82 // when a primitive becomes available it calls the following routine on it's node to update the select state:
    83 // return true if we want to unpark the thd
    84 static inline bool __make_select_node_available( select_node & this ) with( this ) {
    85     unsigned long int cmp_status = __SELECT_UNSAT;
    86 
    87     if( !park_counter )
    88         return *clause_status == 0
    89             && __atomic_compare_exchange_n( clause_status, &cmp_status, (unsigned long int)&this, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ); // OR specific case where race was won
    90 
    91     return *clause_status == 0
    92         && __atomic_compare_exchange_n( clause_status, &cmp_status, __SELECT_SAT, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) // can maybe just use atomic write
    93         && !__atomic_add_fetch( park_counter, 1, __ATOMIC_SEQ_CST);
    94 }
    95 
    96 // Handles the special OR case of the waituntil statement
    97 // Since only one select node can win in the OR case, we need to race to set the node available BEFORE
    98 //    performing the operation since if we lose the race the operation should not be performed as it will be lost
    99 // Returns true if execution can continue normally and false if the queue has now been drained
    100 static inline bool __handle_waituntil_OR( dlist( select_node ) & queue ) {
    101     if ( queue`isEmpty ) return false;
    102     if ( queue`first.clause_status && !queue`first.park_counter ) {
    103         while ( !queue`isEmpty ) {
    104             // if node not a special OR case or if we win the special OR case race break
    105             if ( !queue`first.clause_status || queue`first.park_counter || __make_select_node_available( queue`first ) ) { return true; }
    106             // otherwise we lost the special OR race so discard node
    107             try_pop_front( queue );
    108         }
    109         return false;
    110     }
    111     return true;
    112 }
    113 
    114 // wake one thread from the list
    115 static inline void wake_one( dlist( select_node ) & queue, select_node & popped ) {
    116     if ( !popped.clause_status                              // normal case, node is not a select node
    117         || ( popped.clause_status && !popped.park_counter ) // If popped link is special case OR selecting unpark but don't call __make_select_node_available
    118         || __make_select_node_available( popped ) )         // check if popped link belongs to a selecting thread
    119         unpark( popped.blocked_thread );
    120 }
    121 
    122 static inline void wake_one( dlist( select_node ) & queue ) { wake_one( queue, try_pop_front( queue ) ); }
    123 
    124 static inline void setup_clause( select_node & this, unsigned long int * clause_status, int * park_counter ) {
    125     this.blocked_thread = active_thread();
    126     this.clause_status = clause_status;
    127     this.park_counter = park_counter;
    128 }
    129 
  • libcfa/src/concurrency/thread.cfa

    rc083c3d r4daf79f  
    5353        preferred = ready_queue_new_preferred();
    5454        last_proc = 0p;
    55     link_node = 0p;
    5655        PRNG_SET_SEED( random_state, __global_random_mask ? __global_random_prime : __global_random_prime ^ rdtscl() );
    5756        #if defined( __CFA_WITH_VERIFY__ )
     
    6059        #endif
    6160
     61        clh_node = malloc( );
     62        *clh_node = false;
     63
    6264        doregister(curr_cluster, this);
    6365        monitors{ &self_mon_p, 1, (fptr_t)0 };
     
    6870                canary = 0xDEADDEADDEADDEADp;
    6971        #endif
     72        free(clh_node);
    7073        unregister(curr_cluster, this);
    7174        ^self_cor{};
  • src/AST/Convert.cpp

    rc083c3d r4daf79f  
    567567        }
    568568
    569     const ast::WhenClause * visit( const ast::WhenClause * node ) override final {
    570                 // There is no old-AST WhenClause, so this should never be called.
    571                 assert( !node );
    572                 return nullptr;
    573         }
    574 
    575569        const ast::Stmt * visit( const ast::WaitForStmt * node ) override final {
    576570                if ( inCache( node ) ) return nullptr;
     
    579573                for ( auto clause : node->clauses ) {
    580574                        stmt->clauses.push_back({{
    581                                         get<Expression>().accept1( clause->target ),
     575                                        get<Expression>().accept1( clause->target_func ),
    582576                                        get<Expression>().acceptL( clause->target_args ),
    583577                                },
    584578                                get<Statement>().accept1( clause->stmt ),
    585                                 get<Expression>().accept1( clause->when_cond ),
     579                                get<Expression>().accept1( clause->cond ),
    586580                        });
    587581                }
     
    600594        const ast::WaitForClause * visit( const ast::WaitForClause * node ) override final {
    601595                // There is no old-AST WaitForClause, so this should never be called.
    602                 assert( !node );
    603                 return nullptr;
    604         }
    605 
    606     const ast::Stmt * visit( const ast::WaitUntilStmt * node ) override final {
    607         // There is no old-AST WaitUntilStmt, so this should never be called.
    608596                assert( !node );
    609597                return nullptr;
     
    21702158                        auto clause = new ast::WaitForClause( old->location );
    21712159
    2172                         clause->target = GET_ACCEPT_1(clauses[i].target.function, Expr);
     2160                        clause->target_func = GET_ACCEPT_1(clauses[i].target.function, Expr);
    21732161                        clause->target_args = GET_ACCEPT_V(clauses[i].target.arguments, Expr);
    21742162                        clause->stmt = GET_ACCEPT_1(clauses[i].statement, Stmt);
    2175                         clause->when_cond = GET_ACCEPT_1(clauses[i].condition, Expr);
     2163                        clause->cond = GET_ACCEPT_1(clauses[i].condition, Expr);
    21762164
    21772165                        stmt->clauses.push_back( clause );
  • src/AST/Fwd.hpp

    rc083c3d r4daf79f  
    5858class FinallyClause;
    5959class SuspendStmt;
    60 class WhenClause;
    6160class WaitForStmt;
    6261class WaitForClause;
    63 class WaitUntilStmt;
    6462class WithStmt;
    6563class DeclStmt;
  • src/AST/Node.cpp

    rc083c3d r4daf79f  
    174174template class ast::ptr_base< ast::FinallyClause, ast::Node::ref_type::weak >;
    175175template class ast::ptr_base< ast::FinallyClause, ast::Node::ref_type::strong >;
    176 template class ast::ptr_base< ast::WhenClause, ast::Node::ref_type::weak >;
    177 template class ast::ptr_base< ast::WhenClause, ast::Node::ref_type::strong >;
    178176template class ast::ptr_base< ast::WaitForStmt, ast::Node::ref_type::weak >;
    179177template class ast::ptr_base< ast::WaitForStmt, ast::Node::ref_type::strong >;
    180178template class ast::ptr_base< ast::WaitForClause, ast::Node::ref_type::weak >;
    181179template class ast::ptr_base< ast::WaitForClause, ast::Node::ref_type::strong >;
    182 template class ast::ptr_base< ast::WaitUntilStmt, ast::Node::ref_type::weak >;
    183 template class ast::ptr_base< ast::WaitUntilStmt, ast::Node::ref_type::strong >;
    184180template class ast::ptr_base< ast::WithStmt, ast::Node::ref_type::weak >;
    185181template class ast::ptr_base< ast::WithStmt, ast::Node::ref_type::strong >;
  • src/AST/Pass.hpp

    rc083c3d r4daf79f  
    162162        const ast::FinallyClause *    visit( const ast::FinallyClause        * ) override final;
    163163        const ast::Stmt *             visit( const ast::SuspendStmt          * ) override final;
    164     const ast::WhenClause *       visit( const ast::WhenClause           * ) override final;
    165164        const ast::Stmt *             visit( const ast::WaitForStmt          * ) override final;
    166165        const ast::WaitForClause *    visit( const ast::WaitForClause        * ) override final;
    167     const ast::Stmt *             visit( const ast::WaitUntilStmt        * ) override final;
    168166        const ast::Decl *             visit( const ast::WithStmt             * ) override final;
    169167        const ast::NullStmt *         visit( const ast::NullStmt             * ) override final;
  • src/AST/Pass.impl.hpp

    rc083c3d r4daf79f  
    10661066
    10671067//--------------------------------------------------------------------------
    1068 // WhenClause
    1069 template< typename core_t >
    1070 const ast::WhenClause * ast::Pass< core_t >::visit( const ast::WhenClause * node ) {
    1071         VISIT_START( node );
    1072 
    1073         if ( __visit_children() ) {
    1074                 maybe_accept( node, &WhenClause::target );
    1075                 maybe_accept( node, &WhenClause::stmt );
    1076                 maybe_accept( node, &WhenClause::when_cond );
    1077         }
    1078 
    1079         VISIT_END( WhenClause, node );
    1080 }
    1081 
    1082 //--------------------------------------------------------------------------
    10831068// WaitForStmt
    10841069template< typename core_t >
     
    11051090
    11061091        if ( __visit_children() ) {
    1107                 maybe_accept( node, &WaitForClause::target );
     1092                maybe_accept( node, &WaitForClause::target_func );
    11081093                maybe_accept( node, &WaitForClause::target_args );
    11091094                maybe_accept( node, &WaitForClause::stmt );
    1110                 maybe_accept( node, &WaitForClause::when_cond );
     1095                maybe_accept( node, &WaitForClause::cond );
    11111096        }
    11121097
    11131098        VISIT_END( WaitForClause, node );
    1114 }
    1115 
    1116 //--------------------------------------------------------------------------
    1117 // WaitUntilStmt
    1118 template< typename core_t >
    1119 const ast::Stmt * ast::Pass< core_t >::visit( const ast::WaitUntilStmt * node ) {
    1120         VISIT_START( node );
    1121 
    1122         if ( __visit_children() ) {
    1123                 maybe_accept( node, &WaitUntilStmt::clauses );
    1124                 maybe_accept( node, &WaitUntilStmt::timeout_time );
    1125                 maybe_accept( node, &WaitUntilStmt::timeout_stmt );
    1126                 maybe_accept( node, &WaitUntilStmt::timeout_cond );
    1127                 maybe_accept( node, &WaitUntilStmt::else_stmt );
    1128                 maybe_accept( node, &WaitUntilStmt::else_cond );
    1129         }
    1130 
    1131         VISIT_END( Stmt, node );
    11321099}
    11331100
  • src/AST/Print.cpp

    rc083c3d r4daf79f  
    208208        }
    209209
    210     void print( const ast::WaitStmt * node ) {
    211                 if ( node->timeout_time ) {
    212                         os << indent-1 << "timeout of:" << endl;
    213                         node->timeout_time->accept( *this );
    214 
    215                         if ( node->timeout_stmt ) {
    216                                 os << indent-1 << "... with statment:" << endl;
    217                                 node->timeout_stmt->accept( *this );
    218                         }
    219 
    220                         if ( node->timeout_cond ) {
    221                                 os << indent-1 << "... with condition:" << endl;
    222                                 node->timeout_cond->accept( *this );
    223                         }
    224                 }
    225 
    226                 if ( node->else_stmt ) {
    227                         os << indent-1 << "else:" << endl;
    228                         node->else_stmt->accept( *this );
    229 
    230                         if ( node->else_cond ) {
    231                                 os << indent-1 << "... with condition:" << endl;
    232                                 node->else_cond->accept( *this );
    233                         }
    234                 }
    235         }
    236 
    237210        void preprint( const ast::NamedTypeDecl * node ) {
    238211                if ( ! node->name.empty() ) {
     
    783756        }
    784757
    785         virtual const ast::WhenClause * visit( const ast::WhenClause * node ) override final {
    786                 os << indent-1 << "target: ";
    787                 safe_print( node->target );
    788 
    789                 if ( node->stmt ) {
    790                         os << indent-1 << "... with statment:" << endl;
    791                         node->stmt->accept( *this );
    792                 }
    793 
    794                 if ( node->when_cond ) {
    795                         os << indent-1 << "... with when condition:" << endl;
    796                         node->when_cond->accept( *this );
    797                 }
    798 
    799                 return node;
    800         }
    801 
    802758        virtual const ast::Stmt * visit( const ast::WaitForStmt * node ) override final {
    803759                os << "Waitfor Statement" << endl;
     
    837793        virtual const ast::WaitForClause * visit( const ast::WaitForClause * node ) override final {
    838794                os << indent-1 << "target function: ";
    839                 safe_print( node->target );
     795                safe_print( node->target_func );
    840796
    841797                if ( !node->target_args.empty() ) {
     
    851807                }
    852808
    853                 if ( node->when_cond ) {
     809                if ( node->cond ) {
    854810                        os << indent-1 << "... with condition:" << endl;
    855                         node->when_cond->accept( *this );
    856                 }
    857 
    858                 return node;
    859         }
    860 
    861     virtual const ast::Stmt * visit( const ast::WaitUntilStmt * node ) override final {
    862                 os << "Waituntil Statement" << endl;
    863                 indent += 2;
    864                 for( const auto & clause : node->clauses ) {
    865                         clause->accept( *this );
    866                 }
    867         print(node);    // calls print( const ast::WaitStmt * node )
     811                        node->cond->accept( *this );
     812                }
     813
    868814                return node;
    869815        }
  • src/AST/Stmt.hpp

    rc083c3d r4daf79f  
    378378};
    379379
    380 // Base class of WaitFor/WaitUntil statements
    381 // form: KEYWORD(...) ... timeout(...) ... else ...
    382 class WaitStmt : public Stmt {
    383   public:
    384     ptr<Expr> timeout_time;
     380// Waitfor statement: when (...) waitfor (... , ...) ... timeout(...) ... else ...
     381class WaitForStmt final : public Stmt {
     382  public:
     383        std::vector<ptr<WaitForClause>> clauses;
     384        ptr<Expr> timeout_time;
    385385        ptr<Stmt> timeout_stmt;
    386386        ptr<Expr> timeout_cond;
     
    388388        ptr<Expr> else_cond;
    389389
    390     WaitStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
     390        WaitForStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
    391391                : Stmt(loc, std::move(labels)) {}
    392392
    393   private:
    394     WaitStmt * clone() const override = 0;
    395         MUTATE_FRIEND
    396 };
    397 
    398 // Base class for WaitFor/WaitUntil clauses
    399 // form: when( when_cond ) KEYWORD( target ) stmt
    400 class WhenClause : public StmtClause {
    401   public:
    402         ptr<Expr> target;
     393        const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
     394  private:
     395        WaitForStmt * clone() const override { return new WaitForStmt{ *this }; }
     396        MUTATE_FRIEND
     397};
     398
     399// Clause in a waitfor statement: waitfor (..., ...) ...
     400class WaitForClause final : public StmtClause {
     401  public:
     402        ptr<Expr> target_func;
     403        std::vector<ptr<Expr>> target_args;
    403404        ptr<Stmt> stmt;
    404         ptr<Expr> when_cond;
    405 
    406         WhenClause( const CodeLocation & loc )
     405        ptr<Expr> cond;
     406
     407        WaitForClause( const CodeLocation & loc )
    407408                : StmtClause( loc ) {}
    408409
    409         const WhenClause * accept( Visitor & v ) const override { return v.visit( this ); }
    410   private:
    411         WhenClause * clone() const override { return new WhenClause{ *this }; }
    412         MUTATE_FRIEND
    413 };
    414 
    415 // Waitfor statement: when (...) waitfor (... , ...) ... timeout(...) ... else ...
    416 class WaitForStmt final : public WaitStmt {
    417   public:
    418         std::vector<ptr<WaitForClause>> clauses;
    419 
    420         WaitForStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
    421                 : WaitStmt(loc, std::move(labels)) {}
    422 
    423         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    424   private:
    425         WaitForStmt * clone() const override { return new WaitForStmt{ *this }; }
    426         MUTATE_FRIEND
    427 };
    428 
    429 // Clause in a waitfor statement: waitfor (..., ...) ...
    430 class WaitForClause final : public WhenClause {
    431   public:
    432         std::vector<ptr<Expr>> target_args;
    433 
    434         WaitForClause( const CodeLocation & loc )
    435                 : WhenClause( loc ) {}
    436 
    437410        const WaitForClause * accept( Visitor & v ) const override { return v.visit( this ); }
    438411  private:
    439412        WaitForClause * clone() const override { return new WaitForClause{ *this }; }
    440         MUTATE_FRIEND
    441 };
    442 
    443 // waituntil statement: when (...) waituntil (...) ... timeout(...) ... else ...
    444 class WaitUntilStmt final : public WaitStmt {
    445   public:
    446     // Non-ast node used during compilation to store data needed to generate predicates
    447     //    and set initial status values for clauses
    448     // Used to create a tree corresponding to the structure of the clauses in a WaitUntil
    449     struct ClauseNode {
    450         enum Op { AND, OR, LEFT_OR, LEAF, ELSE, TIMEOUT } op; // operation/type tag
    451         // LEFT_OR used with TIMEOUT/ELSE to indicate that we ignore right hand side after parsing
    452 
    453         ClauseNode * left;
    454         ClauseNode * right;
    455         WhenClause * leaf;  // only set if this node is a leaf (points into vector of clauses)
    456 
    457         bool ambiguousWhen; // used to paint nodes of predicate tree based on when() clauses
    458         bool whenState;     // used to track if when_cond is toggled on or off for generating init values
    459         bool childOfAnd;      // true on leaf nodes that are children of AND, false otherwise
    460 
    461         ClauseNode( Op op, ClauseNode * left, ClauseNode * right )
    462             : op(op), left(left), right(right), leaf(nullptr),
    463             ambiguousWhen(false), whenState(true), childOfAnd(false) {}
    464         ClauseNode( Op op, WhenClause * leaf )
    465             : op(op), left(nullptr), right(nullptr), leaf(leaf),
    466             ambiguousWhen(false), whenState(true), childOfAnd(false) {}
    467         ClauseNode( WhenClause * leaf ) : ClauseNode(LEAF, leaf) {}
    468        
    469         ~ClauseNode() {
    470             if ( left ) delete left;
    471             if ( right ) delete right;
    472         }
    473     };
    474 
    475         std::vector<ptr<WhenClause>> clauses;
    476     ClauseNode * predicateTree;
    477 
    478         WaitUntilStmt( const CodeLocation & loc, const std::vector<Label> && labels = {} )
    479                 : WaitStmt(loc, std::move(labels)) {}
    480 
    481     ~WaitUntilStmt() { delete predicateTree; }
    482 
    483         const Stmt * accept( Visitor & v ) const override { return v.visit( this ); }
    484   private:
    485         WaitUntilStmt * clone() const override { return new WaitUntilStmt{ *this }; }
    486413        MUTATE_FRIEND
    487414};
  • src/AST/Visitor.hpp

    rc083c3d r4daf79f  
    5050    virtual const ast::FinallyClause *    visit( const ast::FinallyClause        * ) = 0;
    5151    virtual const ast::Stmt *             visit( const ast::SuspendStmt          * ) = 0;
    52     virtual const ast::WhenClause *       visit( const ast::WhenClause           * ) = 0;
    5352    virtual const ast::Stmt *             visit( const ast::WaitForStmt          * ) = 0;
    5453    virtual const ast::WaitForClause *    visit( const ast::WaitForClause        * ) = 0;
    55     virtual const ast::Stmt *             visit( const ast::WaitUntilStmt        * ) = 0;
    5654    virtual const ast::Decl *             visit( const ast::WithStmt             * ) = 0;
    5755    virtual const ast::NullStmt *         visit( const ast::NullStmt             * ) = 0;
  • src/Common/CodeLocationTools.cpp

    rc083c3d r4daf79f  
    128128    macro(FinallyClause, FinallyClause) \
    129129    macro(SuspendStmt, Stmt) \
    130     macro(WhenClause, WhenClause) \
    131130    macro(WaitForStmt, Stmt) \
    132131    macro(WaitForClause, WaitForClause) \
    133     macro(WaitUntilStmt, Stmt) \
    134132    macro(WithStmt, Decl) \
    135133    macro(NullStmt, NullStmt) \
  • src/Concurrency/WaitforNew.cpp

    rc083c3d r4daf79f  
    305305
    306306        const ast::VariableExpr * variableExpr =
    307                 clause->target.as<ast::VariableExpr>();
     307                clause->target_func.as<ast::VariableExpr>();
    308308        ast::Expr * castExpr = new ast::CastExpr(
    309309                location,
    310310                new ast::CastExpr(
    311311                        location,
    312                         clause->target,
     312                        clause->target_func,
    313313                        ast::deepCopy( variableExpr->result.get() ),
    314314                        ast::GeneratedCast ),
     
    325325
    326326        ResolveContext context{ symtab, transUnit().global };
    327         out->push_back( maybeCond( location, clause->when_cond.get(), {
     327        out->push_back( maybeCond( location, clause->cond.get(), {
    328328                makeAccStmt( location, acceptables, index, "is_dtor",
    329                         detectIsDtor( location, clause->target ), context ),
     329                        detectIsDtor( location, clause->target_func ), context ),
    330330                makeAccStmt( location, acceptables, index, "func",
    331331                        funcExpr, context ),
  • src/Concurrency/module.mk

    rc083c3d r4daf79f  
    2323        Concurrency/WaitforNew.cpp \
    2424        Concurrency/Waitfor.cc \
    25         Concurrency/Waitfor.h \
    26         Concurrency/Waituntil.cpp \
    27         Concurrency/Waituntil.hpp
     25        Concurrency/Waitfor.h
  • src/Parser/StatementNode.cc

    rc083c3d r4daf79f  
    328328ast::WaitForStmt * build_waitfor( const CodeLocation & location, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
    329329        auto clause = new ast::WaitForClause( location );
    330         clause->target = maybeBuild( targetExpr );
     330        clause->target_func = maybeBuild( targetExpr );
    331331        clause->stmt = maybeMoveBuild( stmt );
    332         clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
     332        clause->cond = notZeroExpr( maybeMoveBuild( when ) );
    333333
    334334        ExpressionNode * next = dynamic_cast<ExpressionNode *>( targetExpr->get_next() );
     
    359359        return existing;
    360360} // build_waitfor_timeout
    361 
    362 ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt ) {
    363     ast::WhenClause * clause = new ast::WhenClause( loc );
    364     clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
    365     clause->stmt = maybeMoveBuild( stmt );
    366     clause->target = maybeMoveBuild( targetExpr );
    367     return new ast::WaitUntilStmt::ClauseNode( clause );
    368 }
    369 ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation & loc, ExpressionNode * when, StatementNode * stmt ) {
    370     ast::WhenClause * clause = new ast::WhenClause( loc );
    371     clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
    372     clause->stmt = maybeMoveBuild( stmt );
    373     return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::ELSE, clause );
    374 }
    375 ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation & loc, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt ) {
    376     ast::WhenClause * clause = new ast::WhenClause( loc );
    377     clause->when_cond = notZeroExpr( maybeMoveBuild( when ) );
    378     clause->stmt = maybeMoveBuild( stmt );
    379     clause->target = maybeMoveBuild( timeout );
    380     return new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::TIMEOUT, clause );
    381 }
    382 
    383 ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation & loc, ast::WaitUntilStmt::ClauseNode * root ) {
    384     ast::WaitUntilStmt * retStmt = new ast::WaitUntilStmt( loc );
    385     retStmt->predicateTree = root;
    386    
    387     // iterative tree traversal
    388     std::vector<ast::WaitUntilStmt::ClauseNode *> nodeStack; // stack needed for iterative traversal
    389     ast::WaitUntilStmt::ClauseNode * currNode = nullptr;
    390     ast::WaitUntilStmt::ClauseNode * lastInternalNode = nullptr;
    391     ast::WaitUntilStmt::ClauseNode * cleanup = nullptr; // used to cleanup removed else/timeout
    392     nodeStack.push_back(root);
    393 
    394     do {
    395         currNode = nodeStack.back();
    396         nodeStack.pop_back(); // remove node since it will be processed
    397 
    398         switch (currNode->op) {
    399             case ast::WaitUntilStmt::ClauseNode::LEAF:
    400                 retStmt->clauses.push_back(currNode->leaf);
    401                 break;
    402             case ast::WaitUntilStmt::ClauseNode::ELSE:
    403                 retStmt->else_stmt = currNode->leaf->stmt
    404                     ? ast::deepCopy( currNode->leaf->stmt )
    405                     : nullptr;
    406                
    407                 retStmt->else_cond = currNode->leaf->when_cond
    408                     ? ast::deepCopy( currNode->leaf->when_cond )
    409                     : nullptr;
    410 
    411                 delete currNode->leaf;
    412                 break;
    413             case ast::WaitUntilStmt::ClauseNode::TIMEOUT:
    414                 retStmt->timeout_time = currNode->leaf->target
    415                     ? ast::deepCopy( currNode->leaf->target )
    416                     : nullptr;
    417                 retStmt->timeout_stmt = currNode->leaf->stmt
    418                     ? ast::deepCopy( currNode->leaf->stmt )
    419                     : nullptr;
    420                 retStmt->timeout_cond = currNode->leaf->when_cond
    421                     ? ast::deepCopy( currNode->leaf->when_cond )
    422                     : nullptr;
    423 
    424                 delete currNode->leaf;
    425                 break;
    426             default:
    427                 nodeStack.push_back( currNode->right ); // process right after left
    428                 nodeStack.push_back( currNode->left );
    429 
    430                 // Cut else/timeout out of the tree
    431                 if ( currNode->op == ast::WaitUntilStmt::ClauseNode::LEFT_OR ) {
    432                     if ( lastInternalNode )
    433                         lastInternalNode->right = currNode->left;
    434                     else    // if not set then root is LEFT_OR
    435                         retStmt->predicateTree = currNode->left;
    436    
    437                     currNode->left = nullptr;
    438                     cleanup = currNode;
    439                 }
    440                
    441                 lastInternalNode = currNode;
    442                 break;
    443         }
    444     } while ( !nodeStack.empty() );
    445 
    446     if ( cleanup ) delete cleanup;
    447 
    448     return retStmt;
    449 }
    450361
    451362ast::Stmt * build_with( const CodeLocation & location, ExpressionNode * exprs, StatementNode * stmt ) {
  • src/Parser/StatementNode.h

    rc083c3d r4daf79f  
    100100ast::WaitForStmt * build_waitfor_else( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, StatementNode * stmt );
    101101ast::WaitForStmt * build_waitfor_timeout( const CodeLocation &, ast::WaitForStmt * existing, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );
    102 ast::WaitUntilStmt::ClauseNode * build_waituntil_clause( const CodeLocation &, ExpressionNode * when, ExpressionNode * targetExpr, StatementNode * stmt );
    103 ast::WaitUntilStmt::ClauseNode * build_waituntil_else( const CodeLocation &, ExpressionNode * when, StatementNode * stmt );
    104 ast::WaitUntilStmt::ClauseNode * build_waituntil_timeout( const CodeLocation &, ExpressionNode * when, ExpressionNode * timeout, StatementNode * stmt );
    105 ast::WaitUntilStmt * build_waituntil_stmt( const CodeLocation &, ast::WaitUntilStmt::ClauseNode * root );
    106102ast::Stmt * build_with( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
    107103ast::Stmt * build_mutex( const CodeLocation &, ExpressionNode * exprs, StatementNode * stmt );
  • src/Parser/parser.yy

    rc083c3d r4daf79f  
    307307        ClauseNode * clause;
    308308        ast::WaitForStmt * wfs;
    309     ast::WaitUntilStmt::ClauseNode * wucn;
    310309        CondCtl * ifctl;
    311310        ForCtrl * forctl;
     
    428427%type<expr> when_clause                                 when_clause_opt                         waitfor         waituntil               timeout
    429428%type<stmt> waitfor_statement                           waituntil_statement
    430 %type<wfs> wor_waitfor_clause
    431 %type<wucn> waituntil_clause                    wand_waituntil_clause       wor_waituntil_clause
     429%type<wfs> wor_waitfor_clause                   waituntil_clause                        wand_waituntil_clause   wor_waituntil_clause
    432430
    433431// declarations
     
    16871685waituntil_clause:
    16881686        when_clause_opt waituntil statement
    1689                 { $$ = build_waituntil_clause( yylloc, $1, $2, maybe_build_compound( yylloc, $3 ) ); }
     1687                { printf( "waituntil_clause 1\n" ); $$ = nullptr; }
    16901688        | '(' wor_waituntil_clause ')'
    1691                 { $$ = $2; }
     1689                { printf( "waituntil_clause 2\n" ); $$ = nullptr; }
    16921690        ;
    16931691
    16941692wand_waituntil_clause:
    16951693        waituntil_clause                                                                        %prec THEN
    1696                 { $$ = $1; }
     1694                { printf( "wand_waituntil_clause 1\n" ); $$ = nullptr; }
    16971695        | waituntil_clause wand wand_waituntil_clause
    1698                 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::AND, $1, $3 ); }
     1696                { printf( "wand_waituntil_clause 2\n" ); $$ = nullptr; }
    16991697        ;
    17001698
    17011699wor_waituntil_clause:
    17021700        wand_waituntil_clause
    1703                 { $$ = $1; }
     1701                { printf( "wor_waituntil_clause 1\n" ); $$ = nullptr; }
    17041702        | wor_waituntil_clause wor wand_waituntil_clause
    1705                 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::OR, $1, $3 ); }
     1703                { printf( "wor_waituntil_clause 2\n" ); $$ = nullptr; }
    17061704        | wor_waituntil_clause wor when_clause_opt ELSE statement
    1707                 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, build_waituntil_else( yylloc, $3, maybe_build_compound( yylloc, $5 ) ) ); }
     1705                { printf( "wor_waituntil_clause 3\n" ); $$ = nullptr; }
    17081706        | wor_waituntil_clause wor when_clause_opt timeout statement    %prec THEN
    1709                 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1, build_waituntil_timeout( yylloc, $3, $4, maybe_build_compound( yylloc, $5 ) ) ); }
     1707                { printf( "wor_waituntil_clause 4\n" ); $$ = nullptr; }
    17101708        // "else" must be conditional after timeout or timeout is never triggered (i.e., it is meaningless)
    17111709        | wor_waituntil_clause wor when_clause_opt timeout statement wor ELSE statement // syntax error
    17121710                { SemanticError( yylloc, "else clause must be conditional after timeout or timeout never triggered." ); $$ = nullptr; }
    17131711        | wor_waituntil_clause wor when_clause_opt timeout statement wor when_clause ELSE statement
    1714                 { $$ = new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::LEFT_OR, $1,
    1715                 new ast::WaitUntilStmt::ClauseNode( ast::WaitUntilStmt::ClauseNode::Op::OR,
    1716                     build_waituntil_timeout( yylloc, $3, $4, maybe_build_compound( yylloc, $5 ) ),
    1717                     build_waituntil_else( yylloc, $7, maybe_build_compound( yylloc, $9 ) ) ) ); }
     1712                { printf( "wor_waituntil_clause 6\n" ); $$ = nullptr; }
    17181713        ;
    17191714
     
    17211716        wor_waituntil_clause                                                            %prec THEN
    17221717                // SKULLDUGGERY: create an empty compound statement to test parsing of waituntil statement.
    1723                 {
    1724             $$ = new StatementNode( build_waituntil_stmt( yylloc, $1 ) );
    1725             // $$ = new StatementNode( build_compound( yylloc, nullptr ) );
    1726         }
     1718                { $$ = new StatementNode( build_compound( yylloc, nullptr ) ); }
    17271719        ;
    17281720
  • src/ResolvExpr/Resolver.cc

    rc083c3d r4daf79f  
    17301730
    17311731                        // Find all candidates for a function in canonical form
    1732                         funcFinder.find( clause.target, ResolvMode::withAdjustment() );
     1732                        funcFinder.find( clause.target_func, ResolvMode::withAdjustment() );
    17331733
    17341734                        if ( funcFinder.candidates.empty() ) {
    17351735                                stringstream ss;
    17361736                                ss << "Use of undeclared indentifier '";
    1737                                 ss << clause.target.strict_as< ast::NameExpr >()->name;
     1737                                ss << clause.target_func.strict_as< ast::NameExpr >()->name;
    17381738                                ss << "' in call to waitfor";
    17391739                                SemanticError( stmt->location, ss.str() );
     
    19221922                        auto clause2 = new ast::WaitForClause( clause.location );
    19231923
    1924                         clause2->target = funcCandidates.front()->expr;
     1924                        clause2->target_func = funcCandidates.front()->expr;
    19251925
    19261926                        clause2->target_args.reserve( clause.target_args.size() );
     
    19451945
    19461946                        // Resolve the conditions as if it were an IfStmt, statements normally
    1947                         clause2->when_cond = findSingleExpression( clause.when_cond, context );
     1947                        clause2->cond = findSingleExpression( clause.cond, context );
    19481948                        clause2->stmt = clause.stmt->accept( *visitor );
    19491949
  • src/main.cc

    rc083c3d r4daf79f  
    4848#include "Concurrency/Keywords.h"           // for implementMutex, implement...
    4949#include "Concurrency/Waitfor.h"            // for generateWaitfor
    50 #include "Concurrency/Waituntil.hpp"        // for generateWaitUntil
    5150#include "ControlStruct/ExceptDecl.h"       // for translateExcept
    5251#include "ControlStruct/ExceptTranslate.h"  // for translateThrows, translat...
     
    341340                PASS( "Implement Concurrent Keywords", Concurrency::implementKeywords, transUnit );
    342341                PASS( "Forall Pointer Decay", Validate::decayForallPointers, transUnit );
    343         PASS( "Implement Waituntil", Concurrency::generateWaitUntil, transUnit  );
    344342                PASS( "Hoist Control Declarations", ControlStruct::hoistControlDecls, transUnit );
    345343
  • tests/Makefile.am

    rc083c3d r4daf79f  
    1111## Created On       : Sun May 31 09:08:15 2015
    1212## Last Modified By : Peter A. Buhr
    13 ## Last Modified On : Mon May  1 17:25:24 2023
    14 ## Update Count     : 145
     13## Last Modified On : Mon May  1 16:45:07 2023
     14## Update Count     : 144
    1515###############################################################################
    1616
     
    116116#----------------------------------------------------------------------------------------------------------------
    117117
    118 all-local : # This name is important to automake and implies the default build target.
     118all-local :
    119119        @+$(TEST_PY) --debug=$(debug) --install=$(installed) --archive-errors=$(archiveerrors) $(concurrent) $(timeouts) $(ARCH) --all # '@' => do not echo command (SILENT), '+' => allows recursive make from within python program
    120120
  • tests/concurrent/futures/select_future.cfa

    rc083c3d r4daf79f  
    196196    delete( shared_future );
    197197        printf( "done 3\n" );
    198 }
     198
     199    // C_TODO: add test for select statement once it is implemented
     200}
Note: See TracChangeset for help on using the changeset viewer.