Ignore:
File:
1 edited

Legend:

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

    r4422579 r09f357ec  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Feb  4 12:29:26 2020
    13 // Update Count     : 11
     12// Last Modified On : Tue Dec  3 22:47:58 2019
     13// Update Count     : 10
    1414//
    1515
     
    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 FORALL_DATA_EXCEPTION(CoroutineCancelled, (dtype coroutine_t), (coroutine_t)) (
    25         coroutine_t * the_coroutine;
    26         exception_t * the_exception;
    27 );
    28 
    29 forall(dtype T)
    30 void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src);
    31 
    32 forall(dtype T)
    33 const char * msg(CoroutineCancelled(T) *);
    3420
    3521//-----------------------------------------------------------------------------
     
    3723// Anything that implements this trait can be resumed.
    3824// Anything that is resumed is a coroutine.
    39 trait is_coroutine(dtype T | IS_RESUMPTION_EXCEPTION(CoroutineCancelled, (T))) {
    40         void main(T & this);
    41         $coroutine * get_coroutine(T & this);
     25trait is_coroutine(dtype T) {
     26      void main(T & this);
     27      coroutine_desc * get_coroutine(T & this);
    4228};
    4329
    44 #define DECL_COROUTINE(X) static inline $coroutine* get_coroutine(X& this) { return &this.__cor; } void main(X& this)
     30#define DECL_COROUTINE(X) static inline coroutine_desc* get_coroutine(X& this) { return &this.__cor; } void main(X& this)
    4531
    4632//-----------------------------------------------------------------------------
     
    4935// void ^?{}( coStack_t & this );
    5036
    51 void  ?{}( $coroutine & this, const char name[], void * storage, size_t storageSize );
    52 void ^?{}( $coroutine & this );
     37void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize );
     38void ^?{}( coroutine_desc & this );
    5339
    54 static inline void ?{}( $coroutine & this)                                       { this{ "Anonymous Coroutine", 0p, 0 }; }
    55 static inline void ?{}( $coroutine & this, size_t stackSize)                     { this{ "Anonymous Coroutine", 0p, stackSize }; }
    56 static inline void ?{}( $coroutine & this, void * storage, size_t storageSize )  { this{ "Anonymous Coroutine", storage, storageSize }; }
    57 static inline void ?{}( $coroutine & this, const char name[])                    { this{ name, 0p, 0 }; }
    58 static inline void ?{}( $coroutine & this, const char name[], size_t stackSize ) { this{ name, 0p, stackSize }; }
     40static inline void ?{}( coroutine_desc & this)                                       { this{ "Anonymous Coroutine", 0p, 0 }; }
     41static inline void ?{}( coroutine_desc & this, size_t stackSize)                     { this{ "Anonymous Coroutine", 0p, stackSize }; }
     42static inline void ?{}( coroutine_desc & this, void * storage, size_t storageSize )  { this{ "Anonymous Coroutine", storage, storageSize }; }
     43static inline void ?{}( coroutine_desc & this, const char * name)                    { this{ name, 0p, 0 }; }
     44static inline void ?{}( coroutine_desc & this, const char * name, size_t stackSize ) { this{ name, 0p, stackSize }; }
    5945
    6046//-----------------------------------------------------------------------------
    6147// Public coroutine API
     48static inline void suspend(void);
     49
     50forall(dtype T | is_coroutine(T))
     51static inline T & resume(T & cor);
     52
    6253forall(dtype T | is_coroutine(T))
    6354void prime(T & cor);
    6455
    65 static inline struct $coroutine * active_coroutine() { return active_thread()->curr_cor; }
     56static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread )->curr_cor; }
    6657
    6758//-----------------------------------------------------------------------------
     
    7061// Start coroutine routines
    7162extern "C" {
    72         void __cfactx_invoke_coroutine(void (*main)(void *), void * this);
     63        void CtxInvokeCoroutine(void (*main)(void *), void * this);
    7364
    7465        forall(dtype T)
    75         void __cfactx_start(void (*main)(T &), struct $coroutine * cor, T & this, void (*invoke)(void (*main)(void *), void *));
     66        void CtxStart(void (*main)(T &), struct coroutine_desc * cor, T & this, void (*invoke)(void (*main)(void *), void *));
    7667
    77         extern void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine *) __attribute__ ((__noreturn__));
     68        extern void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));
    7869
    79         extern void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("__cfactx_switch");
     70        extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");
    8071}
    8172
    8273// Private wrappers for context switch and stack creation
    8374// Wrapper for co
    84 static inline void $ctx_switch( $coroutine * src, $coroutine * dst ) __attribute__((nonnull (1, 2))) {
     75static inline void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
    8576        // set state of current coroutine to inactive
    86         src->state = src->state == Halted ? Halted : Blocked;
     77        src->state = src->state == Halted ? Halted : Inactive;
    8778
    8879        // set new coroutine that task is executing
    89         active_thread()->curr_cor = dst;
     80        TL_GET( this_thread )->curr_cor = dst;
    9081
    9182        // context switch to specified coroutine
    9283        verify( dst->context.SP );
    93         __cfactx_switch( &src->context, &dst->context );
    94         // when __cfactx_switch returns we are back in the src coroutine
     84        CtxSwitch( &src->context, &dst->context );
     85        // when CtxSwitch returns we are back in the src coroutine
    9586
    9687        // set state of new coroutine to active
     
    9889
    9990        if( unlikely(src->cancellation != 0p) ) {
    100                 __cfactx_coroutine_unwind(src->cancellation, src);
     91                _CtxCoroutine_Unwind(src->cancellation, src);
    10192        }
    10293}
    10394
    104 extern void __stack_prepare( __stack_info_t * this, size_t size /* ignored if storage already allocated */);
    105 extern void __stack_clean  ( __stack_info_t * this );
    106 
     95extern void __stack_prepare   ( __stack_info_t * this, size_t size /* ignored if storage already allocated */);
    10796
    10897// Suspend implementation inlined for performance
    109 extern "C" {
    110         static inline void __cfactx_suspend(void) {
    111                 // optimization : read TLS once and reuse it
    112                 // Safety note: this is preemption safe since if
    113                 // preemption occurs after this line, the pointer
    114                 // will also migrate which means this value will
    115                 // stay in syn with the TLS
    116                 $coroutine * src = active_coroutine();
     98static inline void suspend(void) {
     99        // optimization : read TLS once and reuse it
     100        // Safety note: this is preemption safe since if
     101        // preemption occurs after this line, the pointer
     102        // will also migrate which means this value will
     103        // stay in syn with the TLS
     104        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    117105
    118                 assertf( src->last != 0,
    119                         "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"
    120                         "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
    121                         src->name, src );
    122                 assertf( src->last->state != Halted,
    123                         "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"
    124                         "Possible cause is terminated coroutine's main routine has already returned.",
    125                         src->name, src, src->last->name, src->last );
     106        assertf( src->last != 0,
     107                "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"
     108                "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
     109                src->name, src );
     110        assertf( src->last->state != Halted,
     111                "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"
     112                "Possible cause is terminated coroutine's main routine has already returned.",
     113                src->name, src, src->last->name, src->last );
    126114
    127                 $ctx_switch( src, src->last );
    128         }
     115        CoroutineCtxSwitch( src, src->last );
    129116}
    130 
    131 forall(dtype T | is_coroutine(T))
    132 void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc );
    133117
    134118// Resume implementation inlined for performance
     
    140124        // will also migrate which means this value will
    141125        // stay in syn with the TLS
    142         $coroutine * src = active_coroutine();
    143         $coroutine * dst = get_coroutine(cor);
     126        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
     127        coroutine_desc * dst = get_coroutine(cor);
    144128
    145129        if( unlikely(dst->context.SP == 0p) ) {
     130                TL_GET( this_thread )->curr_cor = dst;
    146131                __stack_prepare(&dst->stack, 65000);
    147                 __cfactx_start(main, dst, cor, __cfactx_invoke_coroutine);
     132                CtxStart(main, dst, cor, CtxInvokeCoroutine);
     133                TL_GET( this_thread )->curr_cor = src;
    148134        }
    149135
     
    161147
    162148        // always done for performance testing
    163         $ctx_switch( src, dst );
    164         if ( unlikely(dst->cancellation) ) {
    165                 __cfaehm_cancelled_coroutine( cor, dst );
    166         }
     149        CoroutineCtxSwitch( src, dst );
    167150
    168151        return cor;
    169152}
    170153
    171 static inline void resume( $coroutine * dst ) __attribute__((nonnull (1))) {
     154static inline void resume(coroutine_desc * dst) {
    172155        // optimization : read TLS once and reuse it
    173156        // Safety note: this is preemption safe since if
     
    175158        // will also migrate which means this value will
    176159        // stay in syn with the TLS
    177         $coroutine * src = active_coroutine();
     160        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    178161
    179162        // not resuming self ?
     
    189172
    190173        // always done for performance testing
    191         $ctx_switch( src, dst );
     174        CoroutineCtxSwitch( src, dst );
    192175}
    193176
Note: See TracChangeset for help on using the changeset viewer.