Ignore:
Timestamp:
Jan 7, 2021, 2:55:57 PM (5 years ago)
Author:
Thierry Delisle <tdelisle@…>
Branches:
ADT, arm-eh, ast-experimental, enum, forall-pointer-decay, jacob/cs343-translation, master, new-ast-unique-expr, pthread-emulation, qualifiedEnum
Children:
58fe85a
Parents:
bdfc032 (diff), 44e37ef (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge branch 'master' into dkobets-vector

File:
1 edited

Legend:

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

    rbdfc032 reef8dfb  
    1010// Created On       : Mon Nov 28 12:27:26 2016
    1111// Last Modified By : Peter A. Buhr
    12 // Last Modified On : Tue Dec  3 22:47:58 2019
    13 // Update Count     : 10
     12// Last Modified On : Tue Feb  4 12:29:26 2020
     13// Update Count     : 11
    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.
     24FORALL_DATA_EXCEPTION(CoroutineCancelled, (dtype coroutine_t), (coroutine_t)) (
     25        coroutine_t * the_coroutine;
     26        exception_t * the_exception;
     27);
     28
     29forall(dtype T)
     30void copy(CoroutineCancelled(T) * dst, CoroutineCancelled(T) * src);
     31
     32forall(dtype T)
     33const char * msg(CoroutineCancelled(T) *);
    2034
    2135//-----------------------------------------------------------------------------
     
    2337// Anything that implements this trait can be resumed.
    2438// Anything that is resumed is a coroutine.
    25 trait is_coroutine(dtype T) {
    26       void main(T & this);
    27       coroutine_desc * get_coroutine(T & this);
     39trait is_coroutine(dtype T | IS_RESUMPTION_EXCEPTION(CoroutineCancelled, (T))) {
     40        void main(T & this);
     41        $coroutine * get_coroutine(T & this);
    2842};
    2943
    30 #define DECL_COROUTINE(X) static inline coroutine_desc* get_coroutine(X& this) { return &this.__cor; } void main(X& this)
     44#define DECL_COROUTINE(X) static inline $coroutine* get_coroutine(X& this) { return &this.__cor; } void main(X& this)
    3145
    3246//-----------------------------------------------------------------------------
     
    3549// void ^?{}( coStack_t & this );
    3650
    37 void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize );
    38 void ^?{}( coroutine_desc & this );
     51void  ?{}( $coroutine & this, const char name[], void * storage, size_t storageSize );
     52void ^?{}( $coroutine & this );
    3953
    40 static inline void ?{}( coroutine_desc & this)                                       { this{ "Anonymous Coroutine", 0p, 0 }; }
    41 static inline void ?{}( coroutine_desc & this, size_t stackSize)                     { this{ "Anonymous Coroutine", 0p, stackSize }; }
    42 static inline void ?{}( coroutine_desc & this, void * storage, size_t storageSize )  { this{ "Anonymous Coroutine", storage, storageSize }; }
    43 static inline void ?{}( coroutine_desc & this, const char * name)                    { this{ name, 0p, 0 }; }
    44 static inline void ?{}( coroutine_desc & this, const char * name, size_t stackSize ) { this{ name, 0p, stackSize }; }
     54static inline void ?{}( $coroutine & this)                                       { this{ "Anonymous Coroutine", 0p, 0 }; }
     55static inline void ?{}( $coroutine & this, size_t stackSize)                     { this{ "Anonymous Coroutine", 0p, stackSize }; }
     56static inline void ?{}( $coroutine & this, void * storage, size_t storageSize )  { this{ "Anonymous Coroutine", storage, storageSize }; }
     57static inline void ?{}( $coroutine & this, const char name[])                    { this{ name, 0p, 0 }; }
     58static inline void ?{}( $coroutine & this, const char name[], size_t stackSize ) { this{ name, 0p, stackSize }; }
    4559
    4660//-----------------------------------------------------------------------------
    4761// Public coroutine API
    48 static inline void suspend(void);
    49 
    50 forall(dtype T | is_coroutine(T))
    51 static inline T & resume(T & cor);
    52 
    5362forall(dtype T | is_coroutine(T))
    5463void prime(T & cor);
    5564
    56 static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread )->curr_cor; }
     65static inline struct $coroutine * active_coroutine() { return active_thread()->curr_cor; }
    5766
    5867//-----------------------------------------------------------------------------
     
    6170// Start coroutine routines
    6271extern "C" {
    63         void CtxInvokeCoroutine(void (*main)(void *), void * this);
     72        void __cfactx_invoke_coroutine(void (*main)(void *), void * this);
    6473
    6574        forall(dtype T)
    66         void CtxStart(void (*main)(T &), struct coroutine_desc * cor, T & this, void (*invoke)(void (*main)(void *), void *));
     75        void __cfactx_start(void (*main)(T &), struct $coroutine * cor, T & this, void (*invoke)(void (*main)(void *), void *));
    6776
    68         extern void _CtxCoroutine_Unwind(struct _Unwind_Exception * storage, struct coroutine_desc *) __attribute__ ((__noreturn__));
     77        extern void __cfactx_coroutine_unwind(struct _Unwind_Exception * storage, struct $coroutine *) __attribute__ ((__noreturn__));
    6978
    70         extern void CtxSwitch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("CtxSwitch");
     79        extern void __cfactx_switch( struct __stack_context_t * from, struct __stack_context_t * to ) asm ("__cfactx_switch");
    7180}
    7281
    7382// Private wrappers for context switch and stack creation
    7483// Wrapper for co
    75 static inline void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) {
     84static inline void $ctx_switch( $coroutine * src, $coroutine * dst ) __attribute__((nonnull (1, 2))) {
    7685        // set state of current coroutine to inactive
    77         src->state = src->state == Halted ? Halted : Inactive;
     86        src->state = src->state == Halted ? Halted : Blocked;
    7887
    7988        // set new coroutine that task is executing
    80         TL_GET( this_thread )->curr_cor = dst;
     89        active_thread()->curr_cor = dst;
    8190
    8291        // context switch to specified coroutine
    8392        verify( dst->context.SP );
    84         CtxSwitch( &src->context, &dst->context );
    85         // when CtxSwitch returns we are back in the src coroutine
     93        __cfactx_switch( &src->context, &dst->context );
     94        // when __cfactx_switch returns we are back in the src coroutine
    8695
    8796        // set state of new coroutine to active
     
    8998
    9099        if( unlikely(src->cancellation != 0p) ) {
    91                 _CtxCoroutine_Unwind(src->cancellation, src);
     100                __cfactx_coroutine_unwind(src->cancellation, src);
    92101        }
    93102}
    94103
    95 extern void __stack_prepare   ( __stack_info_t * this, size_t size /* ignored if storage already allocated */);
     104extern void __stack_prepare( __stack_info_t * this, size_t size /* ignored if storage already allocated */);
     105extern void __stack_clean  ( __stack_info_t * this );
     106
    96107
    97108// Suspend implementation inlined for performance
    98 static 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;
     109extern "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();
    105117
    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 );
     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 );
    114126
    115         CoroutineCtxSwitch( src, src->last );
     127                $ctx_switch( src, src->last );
     128        }
    116129}
     130
     131forall(dtype T | is_coroutine(T))
     132void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc );
    117133
    118134// Resume implementation inlined for performance
     
    124140        // will also migrate which means this value will
    125141        // stay in syn with the TLS
    126         coroutine_desc * src = TL_GET( this_thread )->curr_cor;
    127         coroutine_desc * dst = get_coroutine(cor);
     142        $coroutine * src = active_coroutine();
     143        $coroutine * dst = get_coroutine(cor);
    128144
    129145        if( unlikely(dst->context.SP == 0p) ) {
    130                 TL_GET( this_thread )->curr_cor = dst;
    131146                __stack_prepare(&dst->stack, 65000);
    132                 CtxStart(main, dst, cor, CtxInvokeCoroutine);
    133                 TL_GET( this_thread )->curr_cor = src;
     147                __cfactx_start(main, dst, cor, __cfactx_invoke_coroutine);
    134148        }
    135149
     
    147161
    148162        // always done for performance testing
    149         CoroutineCtxSwitch( src, dst );
     163        $ctx_switch( src, dst );
     164        if ( unlikely(dst->cancellation) ) {
     165                __cfaehm_cancelled_coroutine( cor, dst );
     166        }
    150167
    151168        return cor;
    152169}
    153170
    154 static inline void resume(coroutine_desc * dst) {
     171static inline void resume( $coroutine * dst ) __attribute__((nonnull (1))) {
    155172        // optimization : read TLS once and reuse it
    156173        // Safety note: this is preemption safe since if
     
    158175        // will also migrate which means this value will
    159176        // stay in syn with the TLS
    160         coroutine_desc * src = TL_GET( this_thread )->curr_cor;
     177        $coroutine * src = active_coroutine();
    161178
    162179        // not resuming self ?
     
    172189
    173190        // always done for performance testing
    174         CoroutineCtxSwitch( src, dst );
     191        $ctx_switch( src, dst );
    175192}
    176193
Note: See TracChangeset for help on using the changeset viewer.