- File:
-
- 1 edited
-
libcfa/src/concurrency/coroutine.hfa (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
libcfa/src/concurrency/coroutine.hfa
r4422579 r09f357ec 10 10 // Created On : Mon Nov 28 12:27:26 2016 11 11 // Last Modified By : Peter A. Buhr 12 // Last Modified On : Tue Feb 4 12:29:26 202013 // Update Count : 1 112 // Last Modified On : Tue Dec 3 22:47:58 2019 13 // Update Count : 10 14 14 // 15 15 … … 18 18 #include <assert.h> 19 19 #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) *);34 20 35 21 //----------------------------------------------------------------------------- … … 37 23 // Anything that implements this trait can be resumed. 38 24 // 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);25 trait is_coroutine(dtype T) { 26 void main(T & this); 27 coroutine_desc * get_coroutine(T & this); 42 28 }; 43 29 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) 45 31 46 32 //----------------------------------------------------------------------------- … … 49 35 // void ^?{}( coStack_t & this ); 50 36 51 void ?{}( $coroutine & this, const char name[], void * storage, size_t storageSize );52 void ^?{}( $coroutine& this );37 void ?{}( coroutine_desc & this, const char * name, void * storage, size_t storageSize ); 38 void ^?{}( coroutine_desc & this ); 53 39 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 }; }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 }; } 59 45 60 46 //----------------------------------------------------------------------------- 61 47 // 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 62 53 forall(dtype T | is_coroutine(T)) 63 54 void prime(T & cor); 64 55 65 static inline struct $coroutine * active_coroutine() { return active_thread()->curr_cor; }56 static inline struct coroutine_desc * active_coroutine() { return TL_GET( this_thread )->curr_cor; } 66 57 67 58 //----------------------------------------------------------------------------- … … 70 61 // Start coroutine routines 71 62 extern "C" { 72 void __cfactx_invoke_coroutine(void (*main)(void *), void * this);63 void CtxInvokeCoroutine(void (*main)(void *), void * this); 73 64 74 65 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 *)); 76 67 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__)); 78 69 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"); 80 71 } 81 72 82 73 // Private wrappers for context switch and stack creation 83 74 // Wrapper for co 84 static inline void $ctx_switch( $coroutine * src, $coroutine * dst ) __attribute__((nonnull (1, 2))) {75 static inline void CoroutineCtxSwitch(coroutine_desc* src, coroutine_desc* dst) { 85 76 // set state of current coroutine to inactive 86 src->state = src->state == Halted ? Halted : Blocked;77 src->state = src->state == Halted ? Halted : Inactive; 87 78 88 79 // set new coroutine that task is executing 89 active_thread()->curr_cor = dst;80 TL_GET( this_thread )->curr_cor = dst; 90 81 91 82 // context switch to specified coroutine 92 83 verify( dst->context.SP ); 93 __cfactx_switch( &src->context, &dst->context );94 // when __cfactx_switch returns we are back in the src coroutine84 CtxSwitch( &src->context, &dst->context ); 85 // when CtxSwitch returns we are back in the src coroutine 95 86 96 87 // set state of new coroutine to active … … 98 89 99 90 if( unlikely(src->cancellation != 0p) ) { 100 _ _cfactx_coroutine_unwind(src->cancellation, src);91 _CtxCoroutine_Unwind(src->cancellation, src); 101 92 } 102 93 } 103 94 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 95 extern void __stack_prepare ( __stack_info_t * this, size_t size /* ignored if storage already allocated */); 107 96 108 97 // 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(); 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; 117 105 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 ); 126 114 127 $ctx_switch( src, src->last ); 128 } 115 CoroutineCtxSwitch( src, src->last ); 129 116 } 130 131 forall(dtype T | is_coroutine(T))132 void __cfaehm_cancelled_coroutine( T & cor, $coroutine * desc );133 117 134 118 // Resume implementation inlined for performance … … 140 124 // will also migrate which means this value will 141 125 // 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); 144 128 145 129 if( unlikely(dst->context.SP == 0p) ) { 130 TL_GET( this_thread )->curr_cor = dst; 146 131 __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; 148 134 } 149 135 … … 161 147 162 148 // 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 ); 167 150 168 151 return cor; 169 152 } 170 153 171 static inline void resume( $coroutine * dst ) __attribute__((nonnull (1))) {154 static inline void resume(coroutine_desc * dst) { 172 155 // optimization : read TLS once and reuse it 173 156 // Safety note: this is preemption safe since if … … 175 158 // will also migrate which means this value will 176 159 // stay in syn with the TLS 177 $coroutine * src = active_coroutine();160 coroutine_desc * src = TL_GET( this_thread )->curr_cor; 178 161 179 162 // not resuming self ? … … 189 172 190 173 // always done for performance testing 191 $ctx_switch( src, dst );174 CoroutineCtxSwitch( src, dst ); 192 175 } 193 176
Note:
See TracChangeset
for help on using the changeset viewer.