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