Changeset 549c006


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

Implemented out of order waitfor for destructors

Location:
src
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • src/Concurrency/Keywords.cc

    rea156ae r549c006  
    196196                std::list<DeclarationWithType*> findMutexArgs( FunctionDecl* );
    197197                void validate( DeclarationWithType * );
     198                void addDtorStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
    198199                void addStatments( FunctionDecl* func, CompoundStmt *, const std::list<DeclarationWithType * > &);
    199200
     
    206207                StructDecl* monitor_decl = nullptr;
    207208                StructDecl* guard_decl = nullptr;
     209                StructDecl* dtor_guard_decl = nullptr;
    208210
    209211                static std::unique_ptr< Type > generic_func;
     
    229231
    230232                void postvisit( FunctionDecl * decl );
     233                void previsit ( StructDecl   * decl );
    231234
    232235                void addStartStatement( FunctionDecl * decl, DeclarationWithType * param );
     
    236239                        acceptAll( translationUnit, impl );
    237240                }
     241
     242          private :
     243                bool thread_ctor_seen = false;
     244                StructDecl * thread_decl = nullptr;
    238245        };
    239246
     
    403410                if( mutexArgs.empty() ) return;
    404411
     412                if( CodeGen::isConstructor(decl->name) ) throw SemanticError( "constructors cannot have mutex parameters", decl );
     413
     414                bool isDtor = CodeGen::isDestructor( decl->name );
     415
     416                if( isDtor && mutexArgs.size() != 1 ) throw SemanticError( "destructors can only have 1 mutex argument", decl );
     417
    405418                for(auto arg : mutexArgs) {
    406419                        validate( arg );
     
    412425                if( !monitor_decl ) throw SemanticError( "mutex keyword requires monitors to be in scope, add #include <monitor>", decl );
    413426                if( !guard_decl ) throw SemanticError( "mutex keyword requires monitors to be in scope, add #include <monitor>", decl );
    414 
    415                 addStatments( decl, body, mutexArgs );
     427                if( !dtor_guard_decl ) throw SemanticError( "mutex keyword requires monitors to be in scope, add #include <monitor>", decl );
     428
     429                if( isDtor ) {
     430                        addDtorStatments( decl, body, mutexArgs );
     431                }
     432                else {
     433                        addStatments( decl, body, mutexArgs );
     434                }
    416435        }
    417436
     
    425444                        assert( !guard_decl );
    426445                        guard_decl = decl;
     446                }
     447                else if( decl->name == "monitor_dtor_guard_t" ) {
     448                        assert( !dtor_guard_decl );
     449                        dtor_guard_decl = decl;
    427450                }
    428451        }
     
    457480                //Make sure that typed isn't mutex
    458481                if( base->get_mutex() ) throw SemanticError( "mutex keyword may only appear once per argument ", arg );
     482        }
     483
     484        void MutexKeyword::addDtorStatments( FunctionDecl* func, CompoundStmt * body, const std::list<DeclarationWithType * > & args ) {
     485                Type * arg_type = args.front()->get_type()->clone();
     486                arg_type->set_mutex( false );
     487
     488                ObjectDecl * monitors = new ObjectDecl(
     489                        "__monitor",
     490                        noStorage,
     491                        LinkageSpec::Cforall,
     492                        nullptr,
     493                        new PointerType(
     494                                noQualifiers,
     495                                new StructInstType(
     496                                        noQualifiers,
     497                                        monitor_decl
     498                                )
     499                        ),
     500                        new SingleInit( new UntypedExpr(
     501                                new NameExpr( "get_monitor" ),
     502                                {  new CastExpr( new VariableExpr( args.front() ), arg_type ) }
     503                        ))
     504                );
     505
     506                assert(generic_func);
     507
     508                //in reverse order :
     509                // monitor_guard_t __guard = { __monitors, #, func };
     510                body->push_front(
     511                        new DeclStmt( noLabels, new ObjectDecl(
     512                                "__guard",
     513                                noStorage,
     514                                LinkageSpec::Cforall,
     515                                nullptr,
     516                                new StructInstType(
     517                                        noQualifiers,
     518                                        dtor_guard_decl
     519                                ),
     520                                new ListInit(
     521                                        {
     522                                                new SingleInit( new AddressExpr( new VariableExpr( monitors ) ) ),
     523                                                new SingleInit( new CastExpr( new VariableExpr( func ), generic_func->clone() ) )
     524                                        },
     525                                        noDesignators,
     526                                        true
     527                                )
     528                        ))
     529                );
     530
     531                //monitor_desc * __monitors[] = { get_monitor(a), get_monitor(b) };
     532                body->push_front( new DeclStmt( noLabels, monitors) );
    459533        }
    460534
     
    523597        // General entry routine
    524598        //=============================================================================================
     599        void ThreadStarter::previsit( StructDecl * decl ) {
     600                if( decl->name == "thread_desc" && decl->body ) {
     601                        assert( !thread_decl );
     602                        thread_decl = decl;
     603                }
     604        }
     605
    525606        void ThreadStarter::postvisit(FunctionDecl * decl) {
    526607                if( ! CodeGen::isConstructor(decl->name) ) return;
     608
     609                Type * typeof_this = InitTweak::getTypeofThis(decl->type);
     610                StructInstType * ctored_type = dynamic_cast< StructInstType * >( typeof_this );
     611                if( ctored_type && ctored_type->baseStruct == thread_decl ) {
     612                        thread_ctor_seen = true;
     613                }
    527614
    528615                DeclarationWithType * param = decl->get_functionType()->get_parameters().front();
    529616                auto type  = dynamic_cast< StructInstType * >( InitTweak::getPointerBase( param->get_type() ) );
    530617                if( type && type->get_baseStruct()->is_thread() ) {
     618                        if( !thread_decl || !thread_ctor_seen ) {
     619                                throw SemanticError("thread keyword requires threads to be in scope, add #include <thread>");
     620                        }
     621
    531622                        addStartStatement( decl, param );
    532623                }
  • src/InitTweak/InitTweak.cc

    rea156ae r549c006  
    270270        }
    271271
    272         Type * getThisType( FunctionType * ftype ) {
    273                 assertf( ftype, "getThisType: nullptr ftype" );
    274                 ObjectDecl * thisParam = getThisParam( ftype );
     272        Type * getTypeofThis( FunctionType * ftype ) {
     273                assertf( ftype, "getTypeofThis: nullptr ftype" );
     274                ObjectDecl * thisParam = getParamThis( ftype );
    275275                ReferenceType * refType = strict_dynamic_cast< ReferenceType * >( thisParam->type );
    276276                return refType->base;
    277277        }
    278278
    279         ObjectDecl * getThisParam( FunctionType * ftype ) {
    280                 assertf( ftype, "getThisParam: nullptr ftype" );
     279        ObjectDecl * getParamThis( FunctionType * ftype ) {
     280                assertf( ftype, "getParamThis: nullptr ftype" );
    281281                auto & params = ftype->parameters;
    282                 assertf( ! params.empty(), "getThisParam: ftype with 0 parameters: %s", toString( ftype ).c_str() );
     282                assertf( ! params.empty(), "getParamThis: ftype with 0 parameters: %s", toString( ftype ).c_str() );
    283283                return strict_dynamic_cast< ObjectDecl * >( params.front() );
    284284        }
  • src/InitTweak/InitTweak.h

    rea156ae r549c006  
    3131
    3232        /// returns the base type of the first parameter to a constructor/destructor/assignment function
    33         Type * getThisType( FunctionType * ftype );
     33        Type * getTypeofThis( FunctionType * ftype );
    3434
    3535        /// returns the first parameter of a constructor/destructor/assignment function
    36         ObjectDecl * getThisParam( FunctionType * ftype );
     36        ObjectDecl * getParamThis( FunctionType * ftype );
    3737
    3838        /// transform Initializer into an argument list that can be passed to a call expression
  • 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.