Changeset 1c01c58


Ignore:
Timestamp:
Sep 9, 2020, 5:03:40 PM (4 years ago)
Author:
Andrew Beach <ajbeach@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
b9fa85b, c402739f
Parents:
2b7f6f0
Message:

Rather large commit to get coroutine cancellation working.

This includes what you would expect, like new code in exceptions and a new
test, but it also includes a bunch of other things.

New coroutine state, currently just marks that the stack was cancelled. New
helpers for checking code structure and generating vtables. Changes to the
coroutine interface so resume may throw exceptions on cancellation, plus the
exception type that is thrown. Changes to the coroutine keyword generation to
generate exception code for each type of coroutine.

Files:
6 added
10 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/concurrency/coroutine.cfa

    r2b7f6f0 r1c01c58  
    4747
    4848//-----------------------------------------------------------------------------
     49FORALL_DATA_INSTANCE(CoroutineCancelled,
     50                (dtype coroutine_t | sized(coroutine_t)), (coroutine_t))
     51
     52struct __cfaehm_node {
     53        struct _Unwind_Exception unwind_exception;
     54        struct __cfaehm_node * next;
     55        int handler_index;
     56};
     57
     58forall(dtype T)
     59void mark_exception(CoroutineCancelled(T) *) {}
     60
     61forall(dtype T | sized(T))
     62void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src) {
     63        dst->the_coroutine = src->the_coroutine;
     64        dst->the_exception = src->the_exception;
     65}
     66
     67forall(dtype T)
     68const char * msg(CoroutineCancelled(T) *) {
     69        return "CoroutineCancelled(...)";
     70}
     71
     72// This code should not be inlined. It is the error path on resume.
     73forall(dtype T | is_coroutine(T))
     74void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc ) {
     75        verify( desc->cancellation );
     76        desc->state = Cancelled;
     77        exception_t * except = (exception_t *)(1 + (__cfaehm_node *)desc->cancellation);
     78
     79        CoroutineCancelled(T) except;
     80        except.the_coroutine = &cor;
     81        except.the_exception = except;
     82        throwResume except;
     83
     84        except->virtual_table->free( except );
     85        free( desc->cancellation );
     86        desc->cancellation = 0p;
     87}
     88
     89//-----------------------------------------------------------------------------
    4990// Global state variables
    5091
     
    180221        this->storage->limit = storage;
    181222        this->storage->base  = (void*)((intptr_t)storage + size);
     223        this->storage->exception_context.top_resume = 0p;
     224        this->storage->exception_context.current_exception = 0p;
    182225        __attribute__((may_alias)) intptr_t * istorage = (intptr_t*)&this->storage;
    183226        *istorage |= userStack ? 0x1 : 0x0;
  • libcfa/src/concurrency/coroutine.hfa

    r2b7f6f0 r1c01c58  
    1818#include <assert.h>
    1919#include "invoke.h"
     20#include "../exception.hfa"
     21
     22//-----------------------------------------------------------------------------
     23// Exception thrown from resume when a coroutine stack is cancelled.
     24// Should not have to be be sized (see trac #196).
     25FORALL_DATA_EXCEPTION(CoroutineCancelled,
     26                (dtype coroutine_t | sized(coroutine_t)), (coroutine_t)) (
     27        coroutine_t * the_coroutine;
     28        exception_t * the_exception;
     29);
     30
     31forall(dtype T)
     32void mark_exception(CoroutineCancelled(T) *);
     33
     34forall(dtype T | sized(T))
     35void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src);
     36
     37forall(dtype T)
     38const char * msg(CoroutineCancelled(T) *);
    2039
    2140//-----------------------------------------------------------------------------
     
    2342// Anything that implements this trait can be resumed.
    2443// Anything that is resumed is a coroutine.
    25 trait is_coroutine(dtype T) {
    26       void main(T & this);
    27       $coroutine * get_coroutine(T & this);
     44trait is_coroutine(dtype T | sized(T)
     45                | is_resumption_exception(CoroutineCancelled(T))
     46                | VTABLE_ASSERTION(CoroutineCancelled, (T))) {
     47        void main(T & this);
     48        $coroutine * get_coroutine(T & this);
    2849};
    2950
     
    112133        }
    113134}
     135
     136forall(dtype T | is_coroutine(T))
     137void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc );
    114138
    115139// Resume implementation inlined for performance
     
    145169        // always done for performance testing
    146170        $ctx_switch( src, dst );
     171        if ( unlikely(dst->cancellation) ) {
     172                __cfaehm_cancelled_coroutine( cor, dst );
     173        }
    147174
    148175        return cor;
  • libcfa/src/concurrency/exception.cfa

    r2b7f6f0 r1c01c58  
    5757
    5858STOP_AT_END_FUNCTION(coroutine_cancelstop,
    59         // TODO: Instead pass information to the last resumer.
     59        struct $coroutine * src = ($coroutine *)stop_param;
     60        struct $coroutine * dst = src->last;
     61
     62        $ctx_switch( src, dst );
    6063        abort();
    6164)
  • libcfa/src/concurrency/exception.hfa

    r2b7f6f0 r1c01c58  
    1818#include "bits/defs.hfa"
    1919#include "invoke.h"
    20 struct _Unwind_Exception;
    21 
    22 // It must also be usable as a C header file.
    2320
    2421#ifdef __cforall
    2522extern "C" {
     23
     24#define HIDE_EXPORTS
    2625#endif
     26#include "unwind.h"
    2727
    2828struct exception_context_t * this_exception_context(void) OPTIONAL_THREAD;
     
    3232
    3333#ifdef __cforall
     34#undef HIDE_EXPORTS
    3435}
    3536#endif
  • libcfa/src/concurrency/invoke.h

    r2b7f6f0 r1c01c58  
    6868        };
    6969
    70         enum __Coroutine_State { Halted, Start, Primed, Blocked, Ready, Active };
     70        enum __Coroutine_State { Halted, Start, Primed, Blocked, Ready, Active, Cancelled };
    7171
    7272        struct $coroutine {
  • libcfa/src/exception.h

    r2b7f6f0 r1c01c58  
    7676// implemented in the .c file either so they all have to be inline.
    7777
    78 trait is_exception(dtype T) {
     78trait is_exception(dtype exceptT) {
    7979        /* The first field must be a pointer to a virtual table.
    8080         * That virtual table must be a decendent of the base exception virtual tab$
    8181         */
    82         void mark_exception(T *);
     82        void mark_exception(exceptT *);
    8383        // This is never used and should be a no-op.
    8484};
    8585
    86 trait is_termination_exception(dtype T | is_exception(T)) {
    87         void defaultTerminationHandler(T &);
     86trait is_termination_exception(dtype exceptT | is_exception(exceptT)) {
     87        void defaultTerminationHandler(exceptT &);
    8888};
    8989
    90 trait is_resumption_exception(dtype T | is_exception(T)) {
    91         void defaultResumptionHandler(T &);
     90trait is_resumption_exception(dtype exceptT | is_exception(exceptT)) {
     91        void defaultResumptionHandler(exceptT &);
    9292};
    9393
    94 forall(dtype T | is_termination_exception(T))
    95 static inline void $throw(T & except) {
     94forall(dtype exceptT | is_termination_exception(exceptT))
     95static inline void $throw(exceptT & except) {
    9696        __cfaehm_throw_terminate(
    9797                (exception_t *)&except,
     
    100100}
    101101
    102 forall(dtype T | is_resumption_exception(T))
    103 static inline void $throwResume(T & except) {
     102forall(dtype exceptT | is_resumption_exception(exceptT))
     103static inline void $throwResume(exceptT & except) {
    104104        __cfaehm_throw_resume(
    105105                (exception_t *)&except,
     
    108108}
    109109
    110 forall(dtype T | is_exception(T))
    111 static inline void cancel_stack(T & except) __attribute__((noreturn)) {
     110forall(dtype exceptT | is_exception(exceptT))
     111static inline void cancel_stack(exceptT & except) __attribute__((noreturn)) {
    112112        __cfaehm_cancel_stack( (exception_t *)&except );
    113113}
    114114
    115 forall(dtype T | is_exception(T))
    116 static inline void defaultTerminationHandler(T & except) {
     115forall(dtype exceptT | is_exception(exceptT))
     116static inline void defaultTerminationHandler(exceptT & except) {
    117117        return cancel_stack( except );
    118118}
    119119
    120 forall(dtype T | is_exception(T))
    121 static inline void defaultResumptionHandler(T & except) {
     120forall(dtype exceptT | is_exception(exceptT))
     121static inline void defaultResumptionHandler(exceptT & except) {
    122122        throw except;
    123123}
  • libcfa/src/exception.hfa

    r2b7f6f0 r1c01c58  
    192192                size_t size; \
    193193                void (*copy)(exception_name * this, exception_name * other); \
    194                 void (*free)(exception_name & this); \
     194                void (*^?{})(exception_name & this); \
    195195                const char * (*msg)(exception_name * this); \
    196196                _CLOSE
     
    213213                size_t size; \
    214214                void (*copy)(exception_name parameters * this, exception_name parameters * other); \
    215                 void (*free)(exception_name parameters & this); \
     215                void (*^?{})(exception_name parameters & this); \
    216216                const char * (*msg)(exception_name parameters * this); \
    217217                _CLOSE
  • src/Common/module.mk

    r2b7f6f0 r1c01c58  
    2222      Common/ErrorObjects.h \
    2323      Common/Eval.cc \
     24      Common/Examine.cc \
     25      Common/Examine.h \
    2426      Common/FilterCombos.h \
    2527      Common/Indenter.h \
  • src/Concurrency/Keywords.cc

    r2b7f6f0 r1c01c58  
    1919#include <string>                         // for string, operator==
    2020
     21#include <iostream>
     22
     23#include "Common/Examine.h"               // for isMainFor
    2124#include "Common/PassVisitor.h"           // for PassVisitor
    2225#include "Common/SemanticError.h"         // for SemanticError
     
    3437#include "SynTree/Type.h"                 // for StructInstType, Type, PointerType
    3538#include "SynTree/Visitor.h"              // for Visitor, acceptAll
     39#include "Virtual/Tables.h"
    3640
    3741class Attribute;
    3842
    3943namespace Concurrency {
     44        inline static std::string getVTableName( std::string const & exception_name ) {
     45                return exception_name.empty() ? std::string() : Virtual::vtableTypeName(exception_name);
     46        }
     47
    4048        //=============================================================================================
    4149        // Pass declarations
     
    5462          public:
    5563
    56                 ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name, std::string&& getter_name, std::string&& context_error, bool needs_main, AggregateDecl::Aggregate cast_target ) :
    57                   type_name( type_name ), field_name( field_name ), getter_name( getter_name ), context_error( context_error ), needs_main( needs_main ), cast_target( cast_target ) {}
     64                ConcurrentSueKeyword( std::string&& type_name, std::string&& field_name,
     65                        std::string&& getter_name, std::string&& context_error, std::string&& exception_name,
     66                        bool needs_main, AggregateDecl::Aggregate cast_target ) :
     67                  type_name( type_name ), field_name( field_name ), getter_name( getter_name ),
     68                  context_error( context_error ), vtable_name( getVTableName( exception_name ) ),
     69                  needs_main( needs_main ), cast_target( cast_target ) {}
    5870
    5971                virtual ~ConcurrentSueKeyword() {}
     
    6375
    6476                void handle( StructDecl * );
     77                void addVtableForward( StructDecl * );
    6578                FunctionDecl * forwardDeclare( StructDecl * );
    6679                ObjectDecl * addField( StructDecl * );
     
    7689                const std::string getter_name;
    7790                const std::string context_error;
     91                const std::string vtable_name;
    7892                bool needs_main;
    7993                AggregateDecl::Aggregate cast_target;
     
    8195                StructDecl   * type_decl = nullptr;
    8296                FunctionDecl * dtor_decl = nullptr;
     97                StructDecl * vtable_decl = nullptr;
    8398        };
    8499
     
    101116                        "get_thread",
    102117                        "thread keyword requires threads to be in scope, add #include <thread.hfa>\n",
     118                        "",
    103119                        true,
    104120                        AggregateDecl::Thread
     
    133149                        "get_coroutine",
    134150                        "coroutine keyword requires coroutines to be in scope, add #include <coroutine.hfa>\n",
     151                        "CoroutineCancelled",
    135152                        true,
    136153                        AggregateDecl::Coroutine
     
    167184                        "get_monitor",
    168185                        "monitor keyword requires monitors to be in scope, add #include <monitor.hfa>\n",
     186                        "",
    169187                        false,
    170188                        AggregateDecl::Monitor
     
    198216                        "get_generator",
    199217                        "Unable to find builtin type $generator\n",
     218                        "",
    200219                        true,
    201220                        AggregateDecl::Generator
     
    231250
    232251        private:
    233                 DeclarationWithType * is_main( FunctionDecl * );
    234252                bool is_real_suspend( FunctionDecl * );
    235253
     
    359377                        handle( decl );
    360378                }
     379                else if ( !vtable_decl && vtable_name == decl->name && decl->body ) {
     380                        vtable_decl = decl;
     381                }
     382                // Might be able to get ride of is target.
     383                assert( is_target(decl) == (cast_target == decl->kind) );
    361384                return decl;
    362385        }
    363386
    364387        DeclarationWithType * ConcurrentSueKeyword::postmutate( FunctionDecl * decl ) {
    365                 if( !type_decl ) return decl;
    366                 if( !CodeGen::isDestructor( decl->name ) ) return decl;
    367 
    368                 auto params = decl->type->parameters;
    369                 if( params.size() != 1 ) return decl;
    370 
    371                 auto type = dynamic_cast<ReferenceType*>( params.front()->get_type() );
    372                 if( !type ) return decl;
    373 
    374                 auto stype = dynamic_cast<StructInstType*>( type->base );
    375                 if( !stype ) return decl;
    376                 if( stype->baseStruct != type_decl ) return decl;
    377 
    378                 if( !dtor_decl ) dtor_decl = decl;
     388                if ( type_decl && isDestructorFor( decl, type_decl ) )
     389                        dtor_decl = decl;
     390                else if ( vtable_name.empty() )
     391                        ;
     392                else if ( auto param = isMainFor( decl, cast_target ) ) {
     393                        // This should never trigger.
     394                        assert( vtable_decl );
     395                        // Should be safe because of isMainFor.
     396                        StructInstType * struct_type = static_cast<StructInstType *>(
     397                                static_cast<ReferenceType *>( param->get_type() )->base );
     398                        assert( struct_type );
     399
     400                        declsToAddAfter.push_back( Virtual::makeVtableInstance( vtable_decl, {
     401                                new TypeExpr( struct_type->clone() ),
     402                        }, struct_type, nullptr ) );
     403                }
     404
    379405                return decl;
    380406        }
     
    400426                if( !dtor_decl ) SemanticError( decl, context_error );
    401427
     428                addVtableForward( decl );
    402429                FunctionDecl * func = forwardDeclare( decl );
    403430                ObjectDecl * field = addField( decl );
    404431                addRoutines( field, func );
     432        }
     433
     434        void ConcurrentSueKeyword::addVtableForward( StructDecl * decl ) {
     435                if ( vtable_decl ) {
     436                        declsToAddBefore.push_back( Virtual::makeVtableForward( vtable_decl, {
     437                                new TypeExpr( new StructInstType( noQualifiers, decl ) ),
     438                        } ) );
     439                // Its only an error if we want a vtable and don't have one.
     440                } else if ( ! vtable_name.empty() ) {
     441                        SemanticError( decl, context_error );
     442                }
    405443        }
    406444
     
    528566        // Suspend keyword implementation
    529567        //=============================================================================================
    530         DeclarationWithType * SuspendKeyword::is_main( FunctionDecl * func) {
    531                 if(func->name != "main") return nullptr;
    532                 if(func->type->parameters.size() != 1) return nullptr;
    533 
    534                 auto param = func->type->parameters.front();
    535 
    536                 auto type  = dynamic_cast<ReferenceType * >(param->get_type());
    537                 if(!type) return nullptr;
    538 
    539                 auto obj   = dynamic_cast<StructInstType *>(type->base);
    540                 if(!obj) return nullptr;
    541 
    542                 if(!obj->baseStruct->is_generator()) return nullptr;
    543 
    544                 return param;
    545         }
    546 
    547568        bool SuspendKeyword::is_real_suspend( FunctionDecl * func ) {
    548569                if(isMangled(func->linkage)) return false; // the real suspend isn't mangled
     
    565586
    566587                // Is this the main of a generator?
    567                 auto param = is_main( func );
     588                auto param = isMainFor( func, AggregateDecl::Aggregate::Generator );
    568589                if(!param) return;
    569590
     
    10331054// tab-width: 4 //
    10341055// End: //
     1056
  • src/Virtual/module.mk

    r2b7f6f0 r1c01c58  
    1515###############################################################################
    1616
    17 SRC += Virtual/ExpandCasts.cc Virtual/ExpandCasts.h
     17SRC += Virtual/ExpandCasts.cc Virtual/ExpandCasts.h \
     18        Virtual/Tables.cc Virtual/Tables.h
     19
     20SRCDEMANGLE += Virtual/Tables.cc
Note: See TracChangeset for help on using the changeset viewer.