Changeset 549c006 for src/libcfa


Ignore:
Timestamp:
Sep 29, 2017, 12:18:51 PM (7 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, aaron-thesis, arm-eh, ast-experimental, cleanup-dtors, deferred_resn, demangler, enum, forall-pointer-decay, jacob/cs343-translation, jenkins-sandbox, master, new-ast, new-ast-unique-expr, new-env, no_list, persistent-indexer, pthread-emulation, qualifiedEnum, resolv-new, with_gc
Children:
b8116cd
Parents:
ea156ae
Message:

Implemented out of order waitfor for destructors

Location:
src/libcfa/concurrency
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • src/libcfa/concurrency/invoke.h

    rea156ae r549c006  
    9696            struct __condition_stack_t signal_stack;  // stack of conditions to run next once we exit the monitor
    9797            unsigned int recursion;                   // monitor routines can be called recursively, we need to keep track of that
    98             struct __waitfor_mask_t mask;               // mask used to know if some thread is waiting for something while holding the monitor
     98            struct __waitfor_mask_t mask;             // mask used to know if some thread is waiting for something while holding the monitor
     99            struct __condition_node_t * dtor_node;    // node used to signal the dtor in a waitfor dtor
    99100      };
    100101
  • src/libcfa/concurrency/monitor

    rea156ae r549c006  
    2929static inline void ?{}(monitor_desc & this) {
    3030        (this.lock){};
    31         this.owner = NULL;
    3231        (this.entry_queue){};
    3332        (this.signal_stack){};
    34         this.recursion = 0;
     33        this.owner         = NULL;
     34        this.recursion     = 0;
    3535        this.mask.accepted = NULL;
    3636        this.mask.clauses  = NULL;
    3737        this.mask.size     = 0;
     38        this.dtor_node     = NULL;
    3839}
     40
     41// static inline int ?<?(monitor_desc* lhs, monitor_desc* rhs) {
     42//      return ((intptr_t)lhs) < ((intptr_t)rhs);
     43// }
    3944
    4045struct monitor_guard_t {
     
    4651};
    4752
    48 static inline int ?<?(monitor_desc* lhs, monitor_desc* rhs) {
    49         return ((intptr_t)lhs) < ((intptr_t)rhs);
    50 }
    51 
    5253void ?{}( monitor_guard_t & this, monitor_desc ** m, int count, void (*func)() );
    5354void ^?{}( monitor_guard_t & this );
     55
     56
     57struct monitor_dtor_guard_t {
     58        monitor_desc * m;
     59        monitor_desc ** prev_mntrs;
     60        unsigned short  prev_count;
     61        fptr_t          prev_func;
     62};
     63
     64void ?{}( monitor_dtor_guard_t & this, monitor_desc ** m, void (*func)() );
     65void ^?{}( monitor_dtor_guard_t & this );
    5466
    5567//-----------------------------------------------------------------------------
  • src/libcfa/concurrency/monitor.c

    rea156ae r549c006  
    9494                }
    9595                else if( this->owner == thrd) {
    96                         // We already have the monitor, just not how many times we took it
     96                        // We already have the monitor, just note how many times we took it
    9797                        verify( this->recursion > 0 );
    9898                        this->recursion += 1;
     
    127127                unlock( &this->lock );
    128128                return;
     129        }
     130
     131        static void __enter_monitor_dtor( monitor_desc * this, fptr_t func ) {
     132                // Lock the monitor spinlock, lock_yield to reduce contention
     133                lock_yield( &this->lock DEBUG_CTX2 );
     134                thread_desc * thrd = this_thread;
     135
     136                LIB_DEBUG_PRINT_SAFE("Kernel : %10p Entering dtor for mon %p (%p)\n", thrd, this, this->owner);
     137
     138
     139                if( !this->owner ) {
     140                        LIB_DEBUG_PRINT_SAFE("Kernel : Destroying free mon %p\n", this);
     141
     142                        // No one has the monitor, just take it
     143                        set_owner( this, thrd );
     144
     145                        unlock( &this->lock );
     146                        return;
     147                }
     148                else if( this->owner == thrd) {
     149                        // We already have the monitor... but where about to destroy it so the nesting will fail
     150                        // Abort!
     151                        abortf("Attempt to destroy monitor %p by thread \"%.256s\" (%p) in nested mutex.");
     152                }
     153
     154                int count = 1;
     155                monitor_desc ** monitors = &this;
     156                __monitor_group_t group = { &this, 1, func };
     157                if( is_accepted( this, group) ) {
     158                        LIB_DEBUG_PRINT_SAFE("Kernel :  mon accepts dtor, block and signal it \n");
     159
     160                        // Reset mask
     161                        reset_mask( this );
     162
     163                        // Create the node specific to this wait operation
     164                        wait_ctx_primed( this_thread, 0 )
     165
     166                        // Some one else has the monitor, wait for him to finish and then run
     167                        BlockInternal( &this->lock );
     168
     169                        // Some one was waiting for us, enter
     170                        set_owner( this, thrd );
     171                }
     172                else {
     173                        LIB_DEBUG_PRINT_SAFE("Kernel :  blocking \n");
     174
     175                        wait_ctx( this_thread, 0 )
     176                        this->dtor_node = &waiter;
     177
     178                        // Some one else has the monitor, wait in line for it
     179                        append( &this->entry_queue, thrd );
     180                        BlockInternal( &this->lock );
     181
     182                        // BlockInternal will unlock spinlock, no need to unlock ourselves
     183                        return;
     184                }
     185
     186                LIB_DEBUG_PRINT_SAFE("Kernel : Destroying %p\n", this);
     187
    129188        }
    130189
     
    158217        }
    159218
     219        // Leave single monitor for the last time
     220        void __leave_dtor_monitor_desc( monitor_desc * this ) {
     221                LIB_DEBUG_DO(
     222                        if( this_thread != this->owner ) {
     223                                abortf("Destroyed monitor %p has inconsistent owner, expected %p got %p.\n", this, this_thread, this->owner);
     224                        }
     225                        if( this->recursion != 1 ) {
     226                                abortf("Destroyed monitor %p has %d outstanding nested calls.\n", this, this->recursion - 1);
     227                        }
     228                )
     229        }
     230
    160231        // Leave the thread monitor
    161232        // last routine called by a thread.
     
    210281// Ctor for monitor guard
    211282// Sorts monitors before entering
    212 void ?{}( monitor_guard_t & this, monitor_desc ** m, int count, void (*func)() ) {
     283void ?{}( monitor_guard_t & this, monitor_desc ** m, int count, fptr_t func ) {
    213284        // Store current array
    214285        this.m = m;
     
    246317
    247318        // LIB_DEBUG_PRINT_SAFE("MGUARD : left\n");
     319
     320        // Restore thread context
     321        this_thread->monitors.list = this.prev_mntrs;
     322        this_thread->monitors.size = this.prev_count;
     323        this_thread->monitors.func = this.prev_func;
     324}
     325
     326
     327// Ctor for monitor guard
     328// Sorts monitors before entering
     329void ?{}( monitor_dtor_guard_t & this, monitor_desc ** m, fptr_t func ) {
     330        // Store current array
     331        this.m = *m;
     332
     333        // Save previous thread context
     334        this.prev_mntrs = this_thread->monitors.list;
     335        this.prev_count = this_thread->monitors.size;
     336        this.prev_func  = this_thread->monitors.func;
     337
     338        // Update thread context (needed for conditions)
     339        this_thread->monitors.list = m;
     340        this_thread->monitors.size = 1;
     341        this_thread->monitors.func = func;
     342
     343        __enter_monitor_dtor( this.m, func );
     344}
     345
     346
     347// Dtor for monitor guard
     348void ^?{}( monitor_dtor_guard_t & this ) {
     349        // Leave the monitors in order
     350        __leave_dtor_monitor_desc( this.m );
    248351
    249352        // Restore thread context
     
    448551                        *mask.accepted = index;
    449552                        if( mask.clauses[index].is_dtor ) {
    450                                 #warning case not implemented
     553                                verifyf( mask.clauses[index].size == 1        , "ERROR: Accepted dtor has more than 1 mutex parameter." );
     554
     555                                monitor_desc * mon2dtor = mask.clauses[index].list[0];
     556                                verifyf( mon2dtor->dtor_node, "ERROR: Accepted monitor has no dtor_node." );
     557
     558                                __condition_criterion_t * dtor_crit = mon2dtor->dtor_node->criteria;
     559                                push( &mon2dtor->signal_stack, dtor_crit );
     560
     561                                unlock_all( locks, count );
    451562                        }
    452563                        else {
Note: See TracChangeset for help on using the changeset viewer.