Changes in / [2cd0434:fef8293]
- Location:
- src
- Files:
-
- 6 edited
-
libcfa/concurrency/CtxSwitch-x86_64.S (modified) (1 diff)
-
libcfa/concurrency/invoke.c (modified) (4 diffs)
-
libcfa/concurrency/invoke.h (modified) (1 diff)
-
libcfa/concurrency/threads (modified) (1 diff)
-
libcfa/concurrency/threads.c (modified) (3 diffs)
-
tests/coroutine.c (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/libcfa/concurrency/CtxSwitch-x86_64.S
r2cd0434 rfef8293 81 81 .globl coInvokeStub 82 82 coInvokeStub: 83 movq %rbx, %rdi 84 jmp *%r12 83 movq %rbx, %rdi 84 movq %r12, %rsi 85 jmp *%r13 85 86 86 87 // Local Variables: // -
src/libcfa/concurrency/invoke.c
r2cd0434 rfef8293 7 7 #include "invoke.h" 8 8 9 #define __CFA_INVOKE_PRIVATE__ 10 #include "invoke.h" 9 struct machine_context_t { 10 void *SP; 11 void *FP; 12 void *PC; 13 }; 14 15 extern void coInvokeStub( void ); 11 16 12 17 // magically invoke the "main" of the most derived class 13 18 // Called from the kernel when starting a coroutine or task so must switch back to user mode. 19 void __invokeCoroutine__F_P9scoVtablePv__1(struct coVtable *vtable, void* vthis) 20 { 21 LIB_DEBUG_PRINTF("Invoke : Received %p (v %p)\n", vthis, vtable); 14 22 15 void invokeCoroutine(covptr_t* vthis) 16 { 17 LIB_DEBUG_PRINTF("Invoke : Received %p (v %p)\n", vthis, *vthis); 18 19 struct coroutine* cor = get_coroutine( vthis ); 23 struct coroutine* cor = vtable->this_coroutine(vthis); 20 24 21 25 cor->state = Active; 22 26 23 (*vthis)->main( get_object(vthis));27 vtable->main(vthis); 24 28 } 25 29 30 void __startCoroutine__A0_1_0___this_coroutine__PFP10scoroutine_Pd0___co_main__PF_Pd0___vtable__PFP9scoVtable_Pd0__F_Pd0PF_P9scoVtablePv___1( 31 struct coroutine *(*this_coroutine)(void * ), 32 void (*co_main)(void *), 33 struct coVtable *(*get_vtable)(void *), 34 void *vthis, 35 void (*invoke)(struct coVtable *, void *) 36 ) { 37 LIB_DEBUG_PRINTF("StartCoroutine : Passing in %p (v %p) to %p\n", vthis, vtable, invoke); 26 38 27 void startCoroutine(covptr_t* vthis, void (*invoke)(covptr_t*)) { 28 LIB_DEBUG_PRINTF("StartCoroutine : Passing in %p (v %p) to %p\n", vthis, *vthis, invoke); 29 30 struct coroutine* this = get_coroutine( vthis ); 39 struct coVtable * vtable = get_vtable( vthis ); 40 struct coroutine* this = this_coroutine( vthis ); 31 41 struct coStack_t* stack = &this->stack; 32 42 … … 37 47 void *rturn; // where to go on return from uSwitch 38 48 void *dummyReturn; // fake return compiler would have pushed on call to uInvoke 39 void *argument ; // for 16-byte ABI, 16-byte alignment starts here40 void *padding[ 3]; // padding to force 16-byte alignment, as "base" is 16-byte aligned49 void *argument[2]; // for 16-byte ABI, 16-byte alignment starts here 50 void *padding[2]; // padding to force 16-byte alignment, as "base" is 16-byte aligned 41 51 }; 42 52 … … 45 55 46 56 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->dummyReturn = NULL; 47 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->argument = vthis; // argument to invoke 57 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->argument[0] = vtable; // argument to invoke 58 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->argument[1] = vthis; // argument to invoke 48 59 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->rturn = invoke; 49 60 … … 61 72 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->dummyReturn = NULL; 62 73 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->rturn = coInvokeStub; 63 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[0] = vthis; 64 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[1] = invoke; 74 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[0] = vtable; 75 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[1] = vthis; 76 ((struct FakeStack *)(((struct machine_context_t *)stack->context)->SP))->fixedRegisters[2] = invoke; 65 77 #else 66 78 #error Only __i386__ and __x86_64__ is supported for threads in cfa -
src/libcfa/concurrency/invoke.h
r2cd0434 rfef8293 1 #include <stdbool.h>2 #include <stdint.h>3 1 4 #ifdef __CFORALL__5 extern "C" {6 #endif7 8 #if ! defined(__CFA_INVOKE_PRIVATE__)9 2 #ifndef _INVOKE_H_ 10 3 #define _INVOKE_H_ 11 4 12 #define OFFSET_OF(type, field) ((intptr_t)( &((type*)0)->field)) 13 #define VPTR_OFFSET(type, vptr, field) (OFFSET_OF(type, field) - OFFSET_OF(type, vptr)) 5 struct coVtable { 6 void (*main)(void*); 7 struct coroutine* (*this_coroutine)(void*); 8 }; 14 9 15 struct coVtable_t { 16 void (*main)(void*); 17 intptr_t offset_coroutine; 18 intptr_t offset_object; 19 }; 10 struct coStack_t { 11 unsigned int size; // size of stack 12 void *storage; // pointer to stack 13 void *limit; // stack grows towards stack limit 14 void *base; // base of stack 15 void *context; // address of cfa_context_t 16 void *top; // address of top of storage 17 bool userStack; 18 }; 20 19 21 typedef struct coVtable_t* covptr_t;22 20 23 static inline struct coroutine* get_coroutine(covptr_t* vthis) { 24 return (struct coroutine*) ( ((intptr_t)vthis) + ((intptr_t)(*vthis)->offset_coroutine) ); 25 } 21 enum coroutine_state { Start, Inactive, Active, Halt }; 26 22 27 static inline void* get_object(covptr_t* vthis) { 28 return (void*) ( ((intptr_t)vthis) + ((intptr_t)(*vthis)->offset_object) ); 29 } 23 struct coroutine { 24 struct coStack_t stack; 25 const char *name; // textual name for coroutine/task, initialized by uC++ generated code 26 int errno_; // copy of global UNIX variable errno 27 enum coroutine_state state; // current execution status for coroutine 28 bool notHalted; // indicate if execuation state is not halted 30 29 31 struct coStack_t { 32 unsigned int size; // size of stack 33 void *storage; // pointer to stack 34 void *limit; // stack grows towards stack limit 35 void *base; // base of stack 36 void *context; // address of cfa_context_t 37 void *top; // address of top of storage 38 bool userStack; 39 }; 30 struct coroutine *starter; // first coroutine to resume this one 31 struct coroutine *last; // last coroutine to resume this one 32 }; 40 33 41 enum coroutine_state { Start, Inactive, Active, Halt };42 43 struct coroutine {44 struct coStack_t stack;45 const char *name; // textual name for coroutine/task, initialized by uC++ generated code46 int errno_; // copy of global UNIX variable errno47 enum coroutine_state state; // current execution status for coroutine48 bool notHalted; // indicate if execuation state is not halted49 50 struct coroutine *starter; // first coroutine to resume this one51 struct coroutine *last; // last coroutine to resume this one52 };53 54 void invokeCoroutine(covptr_t* this);55 void startCoroutine(covptr_t* this, void (*invoke)(covptr_t*));56 34 #endif //_INVOKE_H_ 57 #else //! defined(__CFA_INVOKE_PRIVATE__)58 #ifndef _INVOKE_PRIVATE_H_59 #define _INVOKE_PRIVATE_H_60 61 struct machine_context_t {62 void *SP;63 void *FP;64 void *PC;65 };66 67 // assembler routines that performs the context switch68 extern void coInvokeStub( void );69 void CtxSwitch( void *from, void *to ) asm ("CtxSwitch");70 71 #endif //_INVOKE_PRIVATE_H_72 #endif //! defined(__CFA_INVOKE_PRIVATE__)73 #ifdef __CFORALL__74 }75 #endif -
src/libcfa/concurrency/threads
r2cd0434 rfef8293 18 18 #define __THREADS_H__ 19 19 20 #include "invoke.h" 20 #include <stdbool.h> 21 22 extern "C" { 23 struct coVtable { 24 void (*main)(void*); 25 struct coroutine* (*this_coroutine)(void*); 26 }; 27 28 struct coStack_t { 29 unsigned int size; // size of stack 30 void *storage; // pointer to stack 31 void *limit; // stack grows towards stack limit 32 void *base; // base of stack 33 void *context; // address of cfa_context_t 34 void *top; // address of top of storage 35 bool userStack; 36 }; 37 38 39 enum coroutine_state { Start, Inactive, Active, Halt }; 40 41 struct coroutine { 42 coStack_t stack; 43 const char *name; // textual name for coroutine/task, initialized by uC++ generated code 44 int errno_; // copy of global UNIX variable errno 45 coroutine_state state; // current execution status for coroutine 46 bool notHalted; // indicate if execuation state is not halted 47 48 coroutine *starter; // first coroutine to resume this one 49 coroutine *last; // last coroutine to resume this one 50 }; 51 } 21 52 22 53 void ?{}(coStack_t* this); 23 54 24 55 void ?{}(coroutine* this); 25 void ?{}(coroutine* this, covptr_t* object);26 56 27 57 trait coroutine_t(dtype T) { 58 coroutine* this_coroutine(T* this); 28 59 void co_main(T* this); 29 co vptr_t* vtable(T* this);60 coVtable* vtable(T* this); 30 61 }; 62 63 forall(dtype T | coroutine_t(T)) 64 void start(T* cor); 31 65 32 66 void suspend(void); -
src/libcfa/concurrency/threads.c
r2cd0434 rfef8293 27 27 #include "libhdr.h" 28 28 29 #define __CFA_INVOKE_PRIVATE__ 30 #include "invoke.h" 29 extern "C" { extern void coInvokeStub( void ); } 31 30 32 31 // minimum feasible stack size in bytes 33 32 #define MinStackSize 1000 34 static size_t pageSize = 0; // architecture pagesize35 33 36 34 static coroutine main_coroutine; 37 35 static coroutine* current_coroutine = &main_coroutine; 38 36 39 coroutine* this_coroutine(void) { 40 return current_coroutine; 37 extern "C" { 38 struct machine_context_t { 39 void *SP; 40 void *FP; 41 void *PC; 42 }; 41 43 } 42 44 43 void ctxSwitchDirect(coroutine* src, coroutine* dst); 44 void create_stack( coStack_t* this, unsigned int storageSize ); // used by all constructors 45 extern "C" { void CtxSwitch( void *from, void *to ) asm ("CtxSwitch"); }// assembler routine that performs the context switch 45 46 46 void ?{}(coStack_t* this) { 47 this->size = 10240; // size of stack 48 this->storage = NULL; // pointer to stack 49 this->limit = NULL; // stack grows towards stack limit 50 this->base = NULL; // base of stack 51 this->context = NULL; // address of cfa_context_t 52 this->top = NULL; // address of top of storage 53 this->userStack = false; 54 55 create_stack(this, this->size); 56 } 57 58 void ?{}(coroutine* this) 59 { 60 this->name = "Anonymous Coroutine"; 61 this->errno_ = 0; 62 this->state = Start; 63 this->notHalted = true; 64 this->starter = NULL; 65 this->last = NULL; 66 } 67 68 void ?{}(coroutine* this, covptr_t* object) 69 { 70 this{}; 71 72 startCoroutine(object, invokeCoroutine); 73 } 74 75 void suspend() { 76 coroutine* src = this_coroutine(); // optimization 77 78 assertf( src->last != 0, 79 "Attempt to suspend coroutine %.256s (%p) that has never been resumed.\n" 80 "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.", 81 src->name, src ); 82 assertf( src->last->notHalted, 83 "Attempt by coroutine %.256s (%p) to suspend back to terminated coroutine %.256s (%p).\n" 84 "Possible cause is terminated coroutine's main routine has already returned.", 85 src->name, src, src->last->name, src->last ); 86 87 ctxSwitchDirect( src, src->last ); 88 } 89 90 forall(dtype T | coroutine_t(T)) 91 void resume(T* cor) { 92 coroutine* src = this_coroutine(); // optimization 93 coroutine* dst = get_coroutine(vtable(cor)); 94 95 if ( src != dst ) { // not resuming self ? 96 assertf( dst->notHalted , 97 "Attempt by coroutine %.256s (%p) to resume terminated coroutine %.256s (%p).\n" 98 "Possible cause is terminated coroutine's main routine has already returned.", 99 src->name, src, dst->name, dst ); 100 dst->last = src; // set last resumer 101 } // if 102 ctxSwitchDirect( src, dst ); // always done for performance testing 103 } 47 static size_t pageSize = 0; // architecture pagesize 104 48 105 49 void ctxSwitchDirect(coroutine* src, coroutine* dst) { … … 121 65 // THREAD_GETMEM( This )->enableInterrupts(); 122 66 } //ctxSwitchDirect 67 68 void invokeCoroutine(coVtable* vtable, void* this); 69 70 forall(dtype T | coroutine_t(T)) 71 void startCoroutine(T* this, void (*invoke)(coVtable*, void*)); 123 72 124 73 // used by all constructors … … 167 116 } 168 117 118 coroutine* this_coroutine() { 119 return current_coroutine; 120 } 121 122 void ?{}(coStack_t* this) { 123 this->size = 10240; // size of stack 124 this->storage = NULL; // pointer to stack 125 this->limit = NULL; // stack grows towards stack limit 126 this->base = NULL; // base of stack 127 this->context = NULL; // address of cfa_context_t 128 this->top = NULL; // address of top of storage 129 this->userStack = false; 130 create_stack(this, this->size); 131 } 132 133 void ?{}(coroutine* this) 134 { 135 this->name = "Anonymous Coroutine"; 136 this->errno_ = 0; 137 this->state = Start; 138 this->notHalted = true; 139 this->starter = NULL; 140 this->last = NULL; 141 } 142 143 forall(dtype T | coroutine_t(T)) 144 void start(T* this) { 145 startCoroutine(this, invokeCoroutine); 146 } 147 148 void suspend() { 149 coroutine* src = this_coroutine(); // optimization 150 151 assertf( src->last != 0, 152 "Attempt to suspend coroutine %.256s (%p) that has never been resumed.\n" 153 "Possible cause is a suspend executed in a member called by a coroutine user rather than by the coroutine main.", 154 src->name, src ); 155 assertf( src->last->notHalted, 156 "Attempt by coroutine %.256s (%p) to suspend back to terminated coroutine %.256s (%p).\n" 157 "Possible cause is terminated coroutine's main routine has already returned.", 158 src->name, src, src->last->name, src->last ); 159 160 ctxSwitchDirect( src, src->last ); 161 } 162 163 forall(dtype T | coroutine_t(T)) 164 void resume(T* cor) { 165 coroutine* src = this_coroutine(); // optimization 166 coroutine* dst = this_coroutine(cor); 167 168 if ( src != dst ) { // not resuming self ? 169 assertf( dst->notHalted , 170 "Attempt by coroutine %.256s (%p) to resume terminated coroutine %.256s (%p).\n" 171 "Possible cause is terminated coroutine's main routine has already returned.", 172 src->name, src, dst->name, dst ); 173 dst->last = src; // set last resumer 174 } // if 175 ctxSwitchDirect( src, dst ); // always done for performance testing 176 } 177 169 178 // Local Variables: // 170 179 // mode: c // -
src/tests/coroutine.c
r2cd0434 rfef8293 3 3 4 4 struct Fibonacci { 5 coroutine c; 6 coVtable v; 5 7 int fn; // used for communication 6 covptr_t v;7 coroutine c;8 8 }; 9 9 10 coroutine* this_coroutine(Fibonacci* this); 10 11 void co_main(Fibonacci* this); 11 co vptr_t* vtable(Fibonacci* this);12 coVtable* vtable(Fibonacci* this); 12 13 13 //GENERATED in proposal for virtuals14 14 void co_main_fib(void* this) { 15 15 co_main( (Fibonacci*) this ); 16 16 } 17 17 18 //GENERATED in proposal for virtuals 19 static coVtable_t FibonacciVtable = { 20 co_main_fib, 21 VPTR_OFFSET(Fibonacci, v, c), 22 VPTR_OFFSET(Fibonacci, v, fn) 23 }; 18 coroutine* this_coroutine_fib(void* this) { 19 return this_coroutine( (Fibonacci*) this); 20 } 24 21 25 22 void ?{}(Fibonacci* this) { 26 23 this->fn = 0; 27 this->v = &FibonacciVtable; //GENERATED in proposal for virtuals 28 (&this->c) { &this->v }; 24 this->v.main = co_main_fib; 25 this->v.this_coroutine = this_coroutine_fib; 26 start(this); 29 27 } 30 28 … … 32 30 #ifdef MORE_DEBUG 33 31 sout | "Starting main of coroutine " | this | endl; 34 sout | "Started from " | this ->c.last | endl;32 sout | "Started from " | this_coroutine(this)->last | endl; 35 33 #endif 36 34 int fn1, fn2; // retained between resumes … … 57 55 } 58 56 59 covptr_t* vtable(Fibonacci* this) { 57 coroutine* this_coroutine(Fibonacci* this) { 58 return &this->c; 59 } 60 61 coVtable* vtable(Fibonacci* this) { 60 62 return &this->v; 61 63 } … … 64 66 Fibonacci f1, f2; 65 67 #ifdef MORE_DEBUG 66 Fibonacci *pf1 = &f1, *pf2 = &f2; 67 coroutine *cf1 = &f1.c, *cf2 = &f2.c; 68 covptr_t *vf1 = vtable(pf1), *vf2 = vtable(pf2); 69 coroutine *cv1 = get_coroutine(vf1), *cv2 = get_coroutine(vf2); 70 Fibonacci *ov1 = (Fibonacci *)get_object(vf1), *ov2 = (Fibonacci *)get_object(vf2); 71 72 sout | "User coroutines : " | pf1 | ' ' | pf2 | endl; 73 sout | "Coroutine data : " | cf1 | ' ' | cf2 | endl; 74 sout | "Vptr address : " | vf1 | ' ' | vf2 | endl; 75 sout | "Vptr obj data : " | ov1 | ' ' | ov2 | endl; 76 sout | "Vptr cor data : " | cv1 | ' ' | cv2 | endl; 68 sout | "User coroutines : " | &f1 | ' ' | &f1 | endl; 77 69 #endif 78 70 for ( int i = 1; i <= 10; i += 1 ) {
Note:
See TracChangeset
for help on using the changeset viewer.