Ignore:
File:
1 edited

Legend:

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

    rae7be7a rd4e68a6  
    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 : Fri Jun 21 17:49:39 2019
     13// Update Count     : 9
    1414//
    1515
     
    2525trait is_coroutine(dtype T) {
    2626      void main(T & this);
    27       $coroutine * get_coroutine(T & this);
     27      coroutine_desc * get_coroutine(T & this);
    2828};
    2929
    30 #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)
    3131
    3232//-----------------------------------------------------------------------------
     
    3535// void ^?{}( coStack_t & this );
    3636
    37 void  ?{}( $coroutine & this, const char name[], void * storage, size_t storageSize );
    38 void ^?{}( $coroutine & this );
     37void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize );
     38void ^?{}( coroutine_desc & this );
    3939
    40 static inline void ?{}( $coroutine & this)                                       { this{ "Anonymous Coroutine", 0p, 0 }; }
    41 static inline void ?{}( $coroutine & this, size_t stackSize)                     { this{ "Anonymous Coroutine", 0p, stackSize }; }
    42 static inline void ?{}( $coroutine & this, void * storage, size_t storageSize )  { this{ "Anonymous Coroutine", storage, storageSize }; }
    43 static inline void ?{}( $coroutine & this, const char name[])                    { this{ name, 0p, 0 }; }
    44 static inline void ?{}( $coroutine & this, const char name[], size_t stackSize ) { this{ name, 0p, stackSize }; }
     40static inline void ?{}( coroutine_desc & this)                                       { this{ "Anonymous Coroutine", NULL, 0 }; }
     41static inline void ?{}( coroutine_desc & this, size_t stackSize)                     { this{ "Anonymous Coroutine", NULL, 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, NULL, 0 }; }
     44static inline void ?{}( coroutine_desc & this, const char * name, size_t stackSize ) { this{ name, NULL, stackSize }; }
    4545
    4646//-----------------------------------------------------------------------------
    4747// Public coroutine API
     48static inline void suspend(void);
     49
     50forall(dtype T | is_coroutine(T))
     51static inline T & resume(T & cor);
     52
    4853forall(dtype T | is_coroutine(T))
    4954void prime(T & cor);
    5055
    51 static inline struct $coroutine * active_coroutine() { return TL_GET( this_thread )->curr_cor; }
     56static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread )->curr_cor; }
    5257
    5358//-----------------------------------------------------------------------------
     
    5661// Start coroutine routines
    5762extern "C" {
    58         void __cfactx_invoke_coroutine(void (*main)(void *), void * this);
     63      forall(dtype T | is_coroutine(T))
     64      void CtxInvokeCoroutine(T * this);
    5965
    60         forall(dtype T)
    61         void __cfactx_start(void (*main)(T &), struct $coroutine * cor, T & this, void (*invoke)(void (*main)(void *), void *));
     66      forall(dtype T | is_coroutine(T))
     67      void CtxStart(T * this, void ( *invoke)(T *));
    6268
    63         extern void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine *) __attribute__ ((__noreturn__));
     69        extern void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));
    6470
    65         extern void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("__cfactx_switch");
     71        extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");
    6672}
    6773
    6874// Private wrappers for context switch and stack creation
    6975// Wrapper for co
    70 static inline void $ctx_switch( $coroutine * src, $coroutine * dst ) __attribute__((nonnull (1, 2))) {
     76static inline void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
    7177        // set state of current coroutine to inactive
    72         src->state = src->state == Halted ? Halted : Blocked;
     78        src->state = src->state == Halted ? Halted : Inactive;
    7379
    7480        // set new coroutine that task is executing
     
    7783        // context switch to specified coroutine
    7884        verify( dst->context.SP );
    79         __cfactx_switch( &src->context, &dst->context );
    80         // when __cfactx_switch returns we are back in the src coroutine
     85        CtxSwitch( &src->context, &dst->context );
     86        // when CtxSwitch returns we are back in the src coroutine
    8187
    8288        // set state of new coroutine to active
    8389        src->state = Active;
    8490
    85         if( unlikely(src->cancellation != 0p) ) {
    86                 __cfactx_coroutine_unwind(src->cancellation, src);
     91        if( unlikely(src->cancellation != NULL) ) {
     92                _CtxCoroutine_Unwind(src->cancellation, src);
    8793        }
    8894}
     
    9197
    9298// Suspend implementation inlined for performance
    93 extern "C" {
    94         static inline void __cfactx_suspend(void) {
    95                 // optimization : read TLS once and reuse it
    96                 // Safety note: this is preemption safe since if
    97                 // preemption occurs after this line, the pointer
    98                 // will also migrate which means this value will
    99                 // stay in syn with the TLS
    100                 $coroutine * src = TL_GET( this_thread )->curr_cor;
     99static inline void suspend(void) {
     100        // optimization : read TLS once and reuse it
     101        // Safety note: this is preemption safe since if
     102        // preemption occurs after this line, the pointer
     103        // will also migrate which means this value will
     104        // stay in syn with the TLS
     105        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    101106
    102                 assertf( src->last != 0,
    103                         "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"
    104                         "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
    105                         src->name, src );
    106                 assertf( src->last->state != Halted,
    107                         "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"
    108                         "Possible cause is terminated coroutine's main routine has already returned.",
    109                         src->name, src, src->last->name, src->last );
     107        assertf( src->last != 0,
     108                "Attempt to suspend coroutine \"%.256s\" (%p) that has never been resumed.\n"
     109                "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.",
     110                src->name, src );
     111        assertf( src->last->state != Halted,
     112                "Attempt by coroutine \"%.256s\" (%p) to suspend back to terminated coroutine \"%.256s\" (%p).\n"
     113                "Possible cause is terminated coroutine's main routine has already returned.",
     114                src->name, src, src->last->name, src->last );
    110115
    111                 $ctx_switch( src, src->last );
    112         }
     116        CoroutineCtxSwitch( src, src->last );
    113117}
    114118
     
    121125        // will also migrate which means this value will
    122126        // stay in syn with the TLS
    123         $coroutine * src = TL_GET( this_thread )->curr_cor;
    124         $coroutine * dst = get_coroutine(cor);
     127        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
     128        coroutine_desc * dst = get_coroutine(cor);
    125129
    126         if( unlikely(dst->context.SP == 0p) ) {
    127                 TL_GET( this_thread )->curr_cor = dst;
     130        if( unlikely(dst->context.SP == NULL) ) {
    128131                __stack_prepare(&dst->stack, 65000);
    129                 __cfactx_start(main, dst, cor, __cfactx_invoke_coroutine);
    130                 TL_GET( this_thread )->curr_cor = src;
     132                CtxStart(&cor, CtxInvokeCoroutine);
    131133        }
    132134
     
    144146
    145147        // always done for performance testing
    146         $ctx_switch( src, dst );
     148        CoroutineCtxSwitch( src, dst );
    147149
    148150        return cor;
    149151}
    150152
    151 static inline void resume( $coroutine * dst ) __attribute__((nonnull (1))) {
     153static inline void resume(coroutine_desc * dst) {
    152154        // optimization : read TLS once and reuse it
    153155        // Safety note: this is preemption safe since if
     
    155157        // will also migrate which means this value will
    156158        // stay in syn with the TLS
    157         $coroutine * src = TL_GET( this_thread )->curr_cor;
     159        coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    158160
    159161        // not resuming self ?
     
    169171
    170172        // always done for performance testing
    171         $ctx_switch( src, dst );
     173        CoroutineCtxSwitch( src, dst );
    172174}
    173175
Note: See TracChangeset for help on using the changeset viewer.