Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/libcfa/concurrency/monitor.c

    rd67cdb7 rb8116cd  
    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                        // Wake the thread that is waiting for this
     161                        __condition_criterion_t * urgent = pop( &this->signal_stack );
     162                        verify( urgent );
     163
     164                        // Reset mask
     165                        reset_mask( this );
     166
     167                        // Create the node specific to this wait operation
     168                        wait_ctx_primed( this_thread, 0 )
     169
     170                        // Some one else has the monitor, wait for him to finish and then run
     171                        BlockInternal( &this->lock, urgent->owner->waiting_thread );
     172
     173                        // Some one was waiting for us, enter
     174                        set_owner( this, thrd );
     175                }
     176                else {
     177                        LIB_DEBUG_PRINT_SAFE("Kernel :  blocking \n");
     178
     179                        wait_ctx( this_thread, 0 )
     180                        this->dtor_node = &waiter;
     181
     182                        // Some one else has the monitor, wait in line for it
     183                        append( &this->entry_queue, thrd );
     184                        BlockInternal( &this->lock );
     185
     186                        // BlockInternal will unlock spinlock, no need to unlock ourselves
     187                        return;
     188                }
     189
     190                LIB_DEBUG_PRINT_SAFE("Kernel : Destroying %p\n", this);
     191
    129192        }
    130193
     
    158221        }
    159222
     223        // Leave single monitor for the last time
     224        void __leave_dtor_monitor_desc( monitor_desc * this ) {
     225                LIB_DEBUG_DO(
     226                        if( this_thread != this->owner ) {
     227                                abortf("Destroyed monitor %p has inconsistent owner, expected %p got %p.\n", this, this_thread, this->owner);
     228                        }
     229                        if( this->recursion != 1 ) {
     230                                abortf("Destroyed monitor %p has %d outstanding nested calls.\n", this, this->recursion - 1);
     231                        }
     232                )
     233        }
     234
    160235        // Leave the thread monitor
    161236        // last routine called by a thread.
     
    210285// Ctor for monitor guard
    211286// Sorts monitors before entering
    212 void ?{}( monitor_guard_t & this, monitor_desc ** m, int count, void (*func)() ) {
     287void ?{}( monitor_guard_t & this, monitor_desc ** m, int count, fptr_t func ) {
    213288        // Store current array
    214289        this.m = m;
     
    246321
    247322        // LIB_DEBUG_PRINT_SAFE("MGUARD : left\n");
     323
     324        // Restore thread context
     325        this_thread->monitors.list = this.prev_mntrs;
     326        this_thread->monitors.size = this.prev_count;
     327        this_thread->monitors.func = this.prev_func;
     328}
     329
     330
     331// Ctor for monitor guard
     332// Sorts monitors before entering
     333void ?{}( monitor_dtor_guard_t & this, monitor_desc ** m, fptr_t func ) {
     334        // Store current array
     335        this.m = *m;
     336
     337        // Save previous thread context
     338        this.prev_mntrs = this_thread->monitors.list;
     339        this.prev_count = this_thread->monitors.size;
     340        this.prev_func  = this_thread->monitors.func;
     341
     342        // Update thread context (needed for conditions)
     343        this_thread->monitors.list = m;
     344        this_thread->monitors.size = 1;
     345        this_thread->monitors.func = func;
     346
     347        __enter_monitor_dtor( this.m, func );
     348}
     349
     350
     351// Dtor for monitor guard
     352void ^?{}( monitor_dtor_guard_t & this ) {
     353        // Leave the monitors in order
     354        __leave_dtor_monitor_desc( this.m );
    248355
    249356        // Restore thread context
     
    448555                        *mask.accepted = index;
    449556                        if( mask.clauses[index].is_dtor ) {
    450                                 #warning case not implemented
     557                                LIB_DEBUG_PRINT_SAFE("Kernel : dtor already there\n");
     558                                verifyf( mask.clauses[index].size == 1        , "ERROR: Accepted dtor has more than 1 mutex parameter." );
     559
     560                                monitor_desc * mon2dtor = mask.clauses[index].list[0];
     561                                verifyf( mon2dtor->dtor_node, "ERROR: Accepted monitor has no dtor_node." );
     562
     563                                __condition_criterion_t * dtor_crit = mon2dtor->dtor_node->criteria;
     564                                push( &mon2dtor->signal_stack, dtor_crit );
     565
     566                                unlock_all( locks, count );
    451567                        }
    452568                        else {
Note: See TracChangeset for help on using the changeset viewer.