Ignore:
File:
1 edited

Legend:

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

    rb10affd rafd550c  
    3939//-----------------------------------------------------------------------------
    4040// Coroutine ctors and dtors
    41 void ?{}(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 
    51 void ?{}(coStack_t& this, size_t size) {
    52         this{};
    53         this.size = size;
    54 
    55         create_stack(&this, this.size);
    56 }
    57 
    58 void ?{}(coroutine_desc& this) {
    59         this{ "Anonymous Coroutine" };
    60 }
    61 
    62 void ?{}(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 
    70 void ?{}(coroutine_desc& this, size_t size) {
    71         this{};
    72         (this.stack){size};
     41void ?{}( 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;
    7349}
    7450
    7551void ^?{}(coStack_t & this) {
    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         }
     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
     62void ?{}( 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;
    8469}
    8570
     
    9075forall(dtype T | is_coroutine(T))
    9176void prime(T& cor) {
    92         coroutine_desc* this = get_coroutine(cor);
    93         assert(this->state == Start);
     77      coroutine_desc* this = get_coroutine(cor);
     78      assert(this->state == Start);
    9479
    95         this->state = Primed;
    96         resume(cor);
     80      this->state = Primed;
     81      resume(cor);
    9782}
    9883
    9984// Wrapper for co
    10085void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
    101         verify( TL_GET( preemption_state ).enabled || TL_GET( this_processor )->do_terminate );
    102         disable_interrupts();
     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();
    10389
    104         // set state of current coroutine to inactive
    105         src->state = src->state == Halted ? Halted : Inactive;
     90      // set state of current coroutine to inactive
     91      src->state = src->state == Halted ? Halted : Inactive;
    10692
    107         // set new coroutine that task is executing
    108         TL_SET( this_coroutine, dst );
     93      // set new coroutine that task is executing
     94      kernelTLS.this_coroutine = dst;
    10995
    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
     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
    114100
    115         // set state of new coroutine to active
    116         src->state = Active;
     101      // set state of new coroutine to active
     102      src->state = Active;
    117103
    118         enable_interrupts( __cfaabi_dbg_ctx );
    119         verify( TL_GET( preemption_state ).enabled || TL_GET( this_processor )->do_terminate );
     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 );
    120107} //ctxSwitchDirect
    121108
    122109void create_stack( coStack_t* this, unsigned int storageSize ) with( *this ) {
    123         //TEMP HACK do this on proper kernel startup
    124         if(pageSize == 0ul) pageSize = sysconf( _SC_PAGESIZE );
     110      //TEMP HACK do this on proper kernel startup
     111      if(pageSize == 0ul) pageSize = sysconf( _SC_PAGESIZE );
    125112
    126         size_t cxtSize = libCeiling( sizeof(machine_context_t), 8 ); // minimum alignment
     113      size_t cxtSize = libCeiling( sizeof(machine_context_t), 8 ); // minimum alignment
    127114
    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
     115      if ( !storage ) {
     116            __cfaabi_dbg_print_safe("Kernel : Creating stack of size %zu for stack obj %p\n", cxtSize + size + 8, this);
    132117
    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 ) );
     118            userStack = false;
     119            size = libCeiling( storageSize, 16 );
     120            // use malloc/memalign because "new" raises an exception for out-of-memory
    136121
    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                 );
     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 ) );
    142125
    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
     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            );
    146131
    147                 __cfaabi_dbg_debug_do( limit = (char *)storage + pageSize );
    148                 __cfaabi_dbg_no_debug_do( limit = (char *)libCeiling( (unsigned long)storage, 16 ) ); // minimum alignment
     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
    149135
    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;
     136            __cfaabi_dbg_debug_do( limit = (char *)storage + pageSize );
     137            __cfaabi_dbg_no_debug_do( limit = (char *)libCeiling( (unsigned long)storage, 16 ) ); // minimum alignment
    154138
    155                 if ( size % 16 != 0u ) size -= 8;
     139      } else {
     140            __cfaabi_dbg_print_safe("Kernel : stack obj %p using user stack %p(%u bytes)\n", this, storage, storageSize);
    156141
    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 );
     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;
    160145
    161         base = (char *)limit + size;
    162         context = base;
    163         top = (char *)context + cxtSize;
     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;
    164155}
    165156
     
    167158// is not inline (We can't inline Cforall in C)
    168159extern "C" {
    169         void __suspend_internal(void) {
    170                 suspend();
    171         }
     160      void __suspend_internal(void) {
     161            suspend();
     162      }
    172163
    173         void __leave_coroutine(void) {
    174                 coroutine_desc * src = TL_GET( this_coroutine ); // optimization
     164      void __leave_coroutine(void) {
     165            coroutine_desc * src = TL_GET( this_coroutine ); // optimization
    175166
    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 );
     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 );
    184175
    185                 CoroutineCtxSwitch( src, src->starter );
    186         }
     176            CoroutineCtxSwitch( src, src->starter );
     177      }
    187178}
    188179
Note: See TracChangeset for help on using the changeset viewer.