Ignore:
Timestamp:
Jun 1, 2023, 11:58:50 AM (19 months ago)
Author:
caparson <caparson@…>
Branches:
ast-experimental, master
Children:
8421d3f
Parents:
8913de4
Message:

fixed bug where waituntil deadlock could occur

Location:
libcfa/src/concurrency
Files:
2 edited

Legend:

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

    r8913de4 r6f774be  
    341341}
    342342
     343// special case of __handle_waituntil_OR, that does some work to avoid starvation/deadlock case
     344static inline bool __handle_pending( dlist( select_node ) & queue, select_node & mine ) {
     345    while ( !queue`isEmpty ) {
     346        // if node not a special OR case or if we win the special OR case race break
     347        if ( !queue`first.clause_status || queue`first.park_counter || __pending_set_other( queue`first, mine, ((unsigned long int)(&(queue`first))) ) )
     348            return true;
     349       
     350        // our node lost the race when toggling in __pending_set_other
     351        if ( *mine.clause_status != __SELECT_PENDING )
     352            return false;
     353
     354        // otherwise we lost the special OR race so discard node
     355        try_pop_front( queue );
     356    }
     357    return false;
     358}
     359
    343360// type used by select statement to capture a chan read as the selected operation
    344361struct chan_read {
     
    374391                return false;
    375392            }
    376            
    377             if ( __handle_waituntil_OR( prods ) ) {
     393
     394            if ( __handle_pending( prods, node ) ) {
    378395                __prods_handoff( chan, ret );
    379396                __make_select_node_sat( node ); // need to to mark SAT now that we know operation is done or else threads could get stuck in __mark_select_node
     
    381398                return true;
    382399            }
    383             __make_select_node_unsat( node );
     400            if ( *node.clause_status == __SELECT_PENDING )
     401                __make_select_node_unsat( node );
    384402        }
    385403        // check if we can complete operation. If so race to establish winner in special OR case
     
    464482                return false;
    465483            }
    466            
    467             if ( __handle_waituntil_OR( cons ) ) {
     484
     485            if ( __handle_pending( cons, node ) ) {
    468486                __cons_handoff( chan, elem );
    469487                __make_select_node_sat( node ); // need to to mark SAT now that we know operation is done or else threads could get stuck in __mark_select_node
     
    471489                return true;
    472490            }
    473             __make_select_node_unsat( node );
     491            if ( *node.clause_status == __SELECT_PENDING )
     492                __make_select_node_unsat( node );
    474493        }
    475494        // check if we can complete operation. If so race to establish winner in special OR case
  • libcfa/src/concurrency/select.hfa

    r8913de4 r6f774be  
    103103//=============================================================================================
    104104
     105static inline void __make_select_node_unsat( select_node & this ) with( this ) {
     106    __atomic_store_n( clause_status, __SELECT_UNSAT, __ATOMIC_SEQ_CST );
     107}
     108static inline void __make_select_node_sat( select_node & this ) with( this ) {
     109    __atomic_store_n( clause_status, __SELECT_SAT, __ATOMIC_SEQ_CST );
     110}
     111
    105112// used for the 2-stage avail needed by the special OR case
    106113static inline bool __mark_select_node( select_node & this, unsigned long int val ) with( this ) {
     
    116123}
    117124
    118 static inline void __make_select_node_unsat( select_node & this ) with( this ) {
    119     __atomic_store_n( clause_status, __SELECT_UNSAT, __ATOMIC_SEQ_CST );
    120 }
    121 static inline void __make_select_node_sat( select_node & this ) with( this ) {
    122     __atomic_store_n( clause_status, __SELECT_SAT, __ATOMIC_SEQ_CST );
     125// used for the 2-stage avail by the thread who owns a pending node
     126static inline bool __pending_set_other( select_node & other, select_node & mine, unsigned long int val ) with( other ) {
     127    /* paranoid */ verify( park_counter == 0p );
     128    /* paranoid */ verify( clause_status != 0p );
     129
     130    unsigned long int cmp_status = __SELECT_UNSAT;
     131    while( !__atomic_compare_exchange_n( clause_status, &cmp_status, val, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) ) {
     132        if ( cmp_status != __SELECT_PENDING )
     133            return false;
     134
     135        // toggle current status flag to avoid starvation/deadlock
     136        __make_select_node_unsat( mine );
     137        cmp_status = __SELECT_UNSAT;
     138        if ( !__atomic_compare_exchange_n( mine.clause_status, &cmp_status, __SELECT_PENDING, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ) )
     139            return false;
     140        cmp_status = __SELECT_UNSAT;
     141    }
     142    return true;
    123143}
    124144
Note: See TracChangeset for help on using the changeset viewer.