Ignore:
File:
1 edited

Legend:

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

    r212c2187 r5b11c25  
    6464      forall(dtype T | is_coroutine(T))
    6565      void CtxStart(T * this, void ( *invoke)(T *));
     66
     67        extern void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));
     68
     69        extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");
     70        extern void CtxStore ( struct __stack_context_t * from, __attribute__((noreturn)) void (*__callback)(void) ) asm ("CtxStore");
     71        extern void CtxRet   ( struct __stack_context_t * to ) asm ("CtxRet") __attribute__ ((__noreturn__));
    6672}
    6773
    6874// Private wrappers for context switch and stack creation
    69 extern void CoroutineCtxSwitch(coroutine_desc * src, coroutine_desc * dst);
    70 extern void create_stack( coStack_t * this, unsigned int storageSize );
     75// Wrapper for co
     76static inline void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
     77        // set state of current coroutine to inactive
     78        src->state = src->state == Halted ? Halted : Inactive;
     79
     80        // set new coroutine that task is executing
     81        TL_GET( this_thread )->curr_cor = dst;
     82
     83        // context switch to specified coroutine
     84        verify( dst->context.SP );
     85        CtxSwitch( &src->context, &dst->context );
     86        // when CtxSwitch returns we are back in the src coroutine
     87
     88        // set state of new coroutine to active
     89        src->state = Active;
     90
     91        if( unlikely(src->cancellation != NULL) ) {
     92                _CtxCoroutine_Unwind(src->cancellation, src);
     93        }
     94}
     95
     96extern void __stack_prepare   ( __stack_info_t * this, size_t size /* ignored if storage already allocated */);
    7197
    7298// Suspend implementation inlined for performance
     
    102128        coroutine_desc * dst = get_coroutine(cor);
    103129
    104         if( unlikely(!dst->stack.base) ) {
    105                 create_stack(&dst->stack, dst->stack.size);
     130        if( unlikely(dst->context.SP == NULL) ) {
     131                __stack_prepare(&dst->stack, 65000);
    106132                CtxStart(&cor, CtxInvokeCoroutine);
    107133        }
     
    146172}
    147173
    148 
    149 
    150 // static inline bool suspend_checkpoint(void) {
    151 //      // optimization : read TLS once and reuse it
    152 //      // Safety note: this is preemption safe since if
    153 //      // preemption occurs after this line, the pointer
    154 //      // will also migrate which means this value will
    155 //      // stay in syn with the TLS
    156 //      // set state of current coroutine to inactive
    157 //       this->state = Checkpoint;
    158 
    159 //       // context switch to specified coroutine
    160 //       assert( src->stack.context );
    161 
    162 //       CtxStore(src->stack.context);
    163 
    164 //      bool ret = this->state == Checkpoint;
    165 
    166 //       // set state of new coroutine to active
    167 //       src->state = Active;
    168 
    169 //       enable_interrupts( __cfaabi_dbg_ctx );
    170 //       // Safety note : This could cause some false positives due to preemption
    171 //       verify( TL_GET( preemption_state.enabled ) || TL_GET( this_processor )->do_terminate );
    172 
    173 //       if( unlikely(src->cancellation != NULL) ) {
    174 //             _CtxCoroutine_Unwind(src->cancellation);
    175 //       }
    176 
    177 //      return ret;
    178 // }
     174static inline void suspend_then(fptr_t call) {
     175        // optimization : read TLS once and reuse it
     176        // Safety note: this is preemption safe since if
     177        // preemption occurs after this line, the pointer
     178        // will also migrate which means this value will
     179        // stay in syn with the TLS
     180        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
     181
     182        assertf( src->last != 0,
     183                "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"
     184                "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
     185                src->name, src );
     186        assertf( src->last->state != Halted,
     187                "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"
     188                "Possible cause is terminated coroutine's main routine has already returned.",
     189                src->name, src, src->last->name, src->last );
     190
     191        src->state = PreInactive;
     192
     193      // context switch to specified coroutine
     194      assert( src->context.SP );
     195
     196        __attribute__((noreturn)) void __suspend_callback(void) {
     197                call();
     198
     199                // set state of current coroutine to inactive
     200                src->state = src->state == Halted ? Halted : Inactive;
     201
     202                TL_GET( this_thread )->curr_cor = src->last;
     203
     204                // context switch to specified coroutine
     205                assert( src->last->context.SP );
     206                CtxRet( &src->last->context );
     207
     208                abort();
     209        }
     210      CtxStore( &src->context, __suspend_callback );
     211        // when CtxStore returns we are back in the src coroutine
     212
     213        // set state of new coroutine to active
     214        src->state = Active;
     215
     216        if( unlikely(src->cancellation != NULL) ) {
     217                _CtxCoroutine_Unwind(src->cancellation, src);
     218        }
     219
     220        return;
     221}
    179222
    180223// static inline void suspend_return(void) {
Note: See TracChangeset for help on using the changeset viewer.