Ignore:
File:
1 edited

Legend:

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

    rafd550c rb10affd  
    3939//-----------------------------------------------------------------------------
    4040// Coroutine ctors and dtors
    41 void ?{}( coStack_t & this, void * storage, size_t storageSize ) with( this ) {
    42       size               = storageSize == 0 ? 65000 : storageSize; // size of stack
    43       this.storage = storage;                                // pointer to stack
    44       limit              = NULL;                                   // stack grows towards stack limit
    45       base               = NULL;                                   // base of stack
    46       context    = NULL;                                   // address of cfa_context_t
    47       top                = NULL;                                   // address of top of storage
    48       userStack  = storage != NULL;
     41void ?{}(coStack_t& this) with( this ) {
     42        size            = 65000;        // size of stack
     43        storage = NULL; // pointer to stack
     44        limit           = NULL; // stack grows towards stack limit
     45        base            = NULL; // base of stack
     46        context = NULL; // address of cfa_context_t
     47        top             = NULL; // address of top of storage
     48        userStack       = false;
     49}
     50
     51void ?{}(coStack_t& this, size_t size) {
     52        this{};
     53        this.size = size;
     54
     55        create_stack(&this, this.size);
     56}
     57
     58void ?{}(coroutine_desc& this) {
     59        this{ "Anonymous Coroutine" };
     60}
     61
     62void ?{}(coroutine_desc& this, const char * name) with( this ) {
     63        this.name = name;
     64        errno_ = 0;
     65        state = Start;
     66        starter = NULL;
     67        last = NULL;
     68}
     69
     70void ?{}(coroutine_desc& this, size_t size) {
     71        this{};
     72        (this.stack){size};
    4973}
    5074
    5175void ^?{}(coStack_t & this) {
    52       if ( ! this.userStack && this.storage ) {
    53             __cfaabi_dbg_debug_do(
    54                   if ( mprotect( this.storage, pageSize, PROT_READ | PROT_WRITE ) == -1 ) {
    55                         abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) );
    56                   }
    57             );
    58             free( this.storage );
    59       }
    60 }
    61 
    62 void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize ) with( this ) {
    63       (this.stack){storage, storageSize};
    64       this.name = name;
    65       errno_ = 0;
    66       state = Start;
    67       starter = NULL;
    68       last = NULL;
     76        if ( ! this.userStack && this.storage ) {
     77                __cfaabi_dbg_debug_do(
     78                        if ( mprotect( this.storage, pageSize, PROT_READ | PROT_WRITE ) == -1 ) {
     79                                abort( "(coStack_t *)%p.^?{}() : internal error, mprotect failure, error(%d) %s.", &this, errno, strerror( errno ) );
     80                        }
     81                );
     82                free( this.storage );
     83        }
    6984}
    7085
     
    7590forall(dtype T | is_coroutine(T))
    7691void prime(T& cor) {
    77       coroutine_desc* this = get_coroutine(cor);
    78       assert(this->state == Start);
     92        coroutine_desc* this = get_coroutine(cor);
     93        assert(this->state == Start);
    7994
    80       this->state = Primed;
    81       resume(cor);
     95        this->state = Primed;
     96        resume(cor);
    8297}
    8398
    8499// Wrapper for co
    85100void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
    86       // Safety note : This could cause some false positives due to preemption
    87       verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate );
    88       disable_interrupts();
     101        verify( TL_GET( preemption_state ).enabled || TL_GET( this_processor )->do_terminate );
     102        disable_interrupts();
    89103
    90       // set state of current coroutine to inactive
    91       src->state = src->state == Halted ? Halted : Inactive;
     104        // set state of current coroutine to inactive
     105        src->state = src->state == Halted ? Halted : Inactive;
    92106
    93       // set new coroutine that task is executing
    94       kernelTLS.this_coroutine = dst;
     107        // set new coroutine that task is executing
     108        TL_SET( this_coroutine, dst );
    95109
    96       // context switch to specified coroutine
    97       assert( src->stack.context );
    98       CtxSwitch( src->stack.context, dst->stack.context );
    99       // when CtxSwitch returns we are back in the src coroutine
     110        // context switch to specified coroutine
     111        assert( src->stack.context );
     112        CtxSwitch( src->stack.context, dst->stack.context );
     113        // when CtxSwitch returns we are back in the src coroutine
    100114
    101       // set state of new coroutine to active
    102       src->state = Active;
     115        // set state of new coroutine to active
     116        src->state = Active;
    103117
    104       enable_interrupts( __cfaabi_dbg_ctx );
    105       // Safety note : This could cause some false positives due to preemption
    106       verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate );
     118        enable_interrupts( __cfaabi_dbg_ctx );
     119        verify( TL_GET( preemption_state ).enabled || TL_GET( this_processor )->do_terminate );
    107120} //ctxSwitchDirect
    108121
    109122void create_stack( coStack_t* this, unsigned int storageSize ) with( *this ) {
    110       //TEMP HACK do this on proper kernel startup
    111       if(pageSize == 0ul) pageSize = sysconf( _SC_PAGESIZE );
     123        //TEMP HACK do this on proper kernel startup
     124        if(pageSize == 0ul) pageSize = sysconf( _SC_PAGESIZE );
    112125
    113       size_t cxtSize = libCeiling( sizeof(machine_context_t), 8 ); // minimum alignment
     126        size_t cxtSize = libCeiling( sizeof(machine_context_t), 8 ); // minimum alignment
    114127
    115       if ( !storage ) {
    116             __cfaabi_dbg_print_safe("Kernel : Creating stack of size %zu for stack obj %p\n", cxtSize + size + 8, this);
     128        if ( (intptr_t)storage == 0 ) {
     129                userStack = false;
     130                size = libCeiling( storageSize, 16 );
     131                // use malloc/memalign because "new" raises an exception for out-of-memory
    117132
    118             userStack = false;
    119             size = libCeiling( storageSize, 16 );
    120             // use malloc/memalign because "new" raises an exception for out-of-memory
     133                // assume malloc has 8 byte alignment so add 8 to allow rounding up to 16 byte alignment
     134                __cfaabi_dbg_debug_do( storage = memalign( pageSize, cxtSize + size + pageSize ) );
     135                __cfaabi_dbg_no_debug_do( storage = malloc( cxtSize + size + 8 ) );
    121136
    122             // assume malloc has 8 byte alignment so add 8 to allow rounding up to 16 byte alignment
    123             __cfaabi_dbg_debug_do( storage = memalign( pageSize, cxtSize + size + pageSize ) );
    124             __cfaabi_dbg_no_debug_do( storage = malloc( cxtSize + size + 8 ) );
     137                __cfaabi_dbg_debug_do(
     138                        if ( mprotect( storage, pageSize, PROT_NONE ) == -1 ) {
     139                                abort( "(uMachContext &)%p.createContext() : internal error, mprotect failure, error(%d) %s.", this, (int)errno, strerror( (int)errno ) );
     140                        } // if
     141                );
    125142
    126             __cfaabi_dbg_debug_do(
    127                   if ( mprotect( storage, pageSize, PROT_NONE ) == -1 ) {
    128                         abort( "(uMachContext &)%p.createContext() : internal error, mprotect failure, error(%d) %s.", this, (int)errno, strerror( (int)errno ) );
    129                   } // if
    130             );
     143                if ( (intptr_t)storage == 0 ) {
     144                        abort( "Attempt to allocate %zd bytes of storage for coroutine or task execution-state but insufficient memory available.", size );
     145                } // if
    131146
    132             if ( (intptr_t)storage == 0 ) {
    133                   abort( "Attempt to allocate %zd bytes of storage for coroutine or task execution-state but insufficient memory available.", size );
    134             } // if
     147                __cfaabi_dbg_debug_do( limit = (char *)storage + pageSize );
     148                __cfaabi_dbg_no_debug_do( limit = (char *)libCeiling( (unsigned long)storage, 16 ) ); // minimum alignment
    135149
    136             __cfaabi_dbg_debug_do( limit = (char *)storage + pageSize );
    137             __cfaabi_dbg_no_debug_do( limit = (char *)libCeiling( (unsigned long)storage, 16 ) ); // minimum alignment
     150        } else {
     151                assertf( ((size_t)storage & (libAlign() - 1)) != 0ul, "Stack storage %p for task/coroutine must be aligned on %d byte boundary.", storage, (int)libAlign() );
     152                userStack = true;
     153                size = storageSize - cxtSize;
    138154
    139       } else {
    140             __cfaabi_dbg_print_safe("Kernel : stack obj %p using user stack %p(%u bytes)\n", this, storage, storageSize);
     155                if ( size % 16 != 0u ) size -= 8;
    141156
    142             assertf( ((size_t)storage & (libAlign() - 1)) == 0ul, "Stack storage %p for task/coroutine must be aligned on %d byte boundary.", storage, (int)libAlign() );
    143             userStack = true;
    144             size = storageSize - cxtSize;
     157                limit = (char *)libCeiling( (unsigned long)storage, 16 ); // minimum alignment
     158        } // if
     159        assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %d bytes for a stack.", size, MinStackSize );
    145160
    146             if ( size % 16 != 0u ) size -= 8;
    147 
    148             limit = (char *)libCeiling( (unsigned long)storage, 16 ); // minimum alignment
    149       } // if
    150       assertf( size >= MinStackSize, "Stack size %zd provides less than minimum of %d bytes for a stack.", size, MinStackSize );
    151 
    152       base = (char *)limit + size;
    153       context = base;
    154       top = (char *)context + cxtSize;
     161        base = (char *)limit + size;
     162        context = base;
     163        top = (char *)context + cxtSize;
    155164}
    156165
     
    158167// is not inline (We can't inline Cforall in C)
    159168extern "C" {
    160       void __suspend_internal(void) {
    161             suspend();
    162       }
     169        void __suspend_internal(void) {
     170                suspend();
     171        }
    163172
    164       void __leave_coroutine(void) {
    165             coroutine_desc * src = TL_GET( this_coroutine ); // optimization
     173        void __leave_coroutine(void) {
     174                coroutine_desc * src = TL_GET( this_coroutine ); // optimization
    166175
    167             assertf( src->starter != 0,
    168                   "Attempt to suspend/leave coroutine \"%.256s\" (%p) that has never been resumed.\n"
    169                   "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
    170                   src->name, src );
    171             assertf( src->starter->state != Halted,
    172                   "Attempt by coroutine \"%.256s\" (%p) to suspend/leave back to terminated coroutine \"%.256s\" (%p).\n"
    173                   "Possible cause is terminated coroutine's main routine has already returned.",
    174                   src->name, src, src->starter->name, src->starter );
     176                assertf( src->starter != 0,
     177                        "Attempt to suspend/leave coroutine \"%.256s\" (%p) that has never been resumed.\n"
     178                        "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
     179                        src->name, src );
     180                assertf( src->starter->state != Halted,
     181                        "Attempt by coroutine \"%.256s\" (%p) to suspend/leave back to terminated coroutine \"%.256s\" (%p).\n"
     182                        "Possible cause is terminated coroutine's main routine has already returned.",
     183                        src->name, src, src->starter->name, src->starter );
    175184
    176             CoroutineCtxSwitch( src, src->starter );
    177       }
     185                CoroutineCtxSwitch( src, src->starter );
     186        }
    178187}
    179188
Note: See TracChangeset for help on using the changeset viewer.